All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wildfly.security.permission.PermissionUtil Maven / Gradle / Ivy

The newest version!
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2016 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.wildfly.security.permission;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.AllPermission;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.IntFunction;
import java.util.function.LongFunction;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;

import org.wildfly.common.Assert;

/**
 * General permission utility methods and constants.
 *
 * @author David M. Lloyd
 */
public final class PermissionUtil {

    private PermissionUtil() {
    }

    /**
     * A shared {@link AllPermission} instance.
     */
    public static final Permission ALL_PERMISSION = new AllPermission();

    /**
     * A read-only permission collection which implies {@link AllPermission}.
     */
    public static final PermissionCollection ALL_PERMISSIONS;

    /**
     * A permission collection which is empty.
     */
    public static final PermissionCollection EMPTY_PERMISSION_COLLECTION;

    /**
     * An array with no permissions in it.
     */
    public static final Permission[] NO_PERMISSIONS = new Permission[0];

    static {
        Permissions permissions = new Permissions();
        permissions.add(ALL_PERMISSION);
        permissions.setReadOnly();
        ALL_PERMISSIONS = permissions;
        permissions = new Permissions();
        permissions.setReadOnly();
        EMPTY_PERMISSION_COLLECTION = permissions;
    }

    /**
     * Parse an actions string, using the given function to map action strings to bits.
     *
     * @param actionsString the actions string (must not be {@code null})
     * @param function the mapping function (must not be {@code null})
     * @return the union of all the action bits
     * @throws IllegalArgumentException if {@code function} throws this exception (indicating an invalid action string)
     */
    public static int parseActions(String actionsString, ToIntFunction function) throws IllegalArgumentException {
        Assert.checkNotNullParam("actionsString", actionsString);
        Assert.checkNotNullParam("function", function);
        int actions = 0;
        int pos = 0;
        int idx = actionsString.indexOf(',');
        for (;;) {
            String str;
            if (idx == -1) {
                str = actionsString.substring(pos, actionsString.length()).trim();
                if (! str.isEmpty()) actions |= function.applyAsInt(str);
                return actions;
            } else {
                str = actionsString.substring(pos, idx).trim();
                pos = idx + 1;
                if (! str.isEmpty()) actions |= function.applyAsInt(str);
                idx = actionsString.indexOf(',', pos);
            }
        }
    }

    /**
     * Parse an actions string, using the given function to map action strings to bits.
     *
     * @param actionsString the actions string (must not be {@code null})
     * @param function the mapping function (must not be {@code null})
     * @return the union of all the action bits
     * @throws IllegalArgumentException if {@code function} throws this exception (indicating an invalid action string)
     */
    public static long parseActions(String actionsString, ToLongFunction function) throws IllegalArgumentException {
        Assert.checkNotNullParam("actionsString", actionsString);
        Assert.checkNotNullParam("function", function);
        long actions = 0;
        int pos = 0;
        int idx = actionsString.indexOf(',');
        for (;;) {
            String str;
            if (idx == -1) {
                str = actionsString.substring(pos, actionsString.length()).trim();
                if (! str.isEmpty()) actions |= function.applyAsLong(str);
                return actions;
            } else {
                str = actionsString.substring(pos, idx).trim();
                pos = idx + 1;
                if (! str.isEmpty()) actions |= function.applyAsLong(str);
                idx = actionsString.indexOf(',', pos);
            }
        }
    }

    /**
     * Deparse an action bit set, using the given function to map action bits to strings.  If the bits are all clear,
     * the empty string {@code ""} is returned.
     *
     * @param actionBits the action bit set
     * @param mappingFunction the mapping function (must not be {@code null})
     * @return the actions string (not {@code null})
     */
    public static String toActionsString(int actionBits, IntFunction mappingFunction) {
        Assert.checkNotNullParam("mappingFunction", mappingFunction);
        final StringBuilder sb = new StringBuilder();
        if (actionBits == 0) return "";
        int lb = Integer.highestOneBit(actionBits);
        sb.append(mappingFunction.apply(lb));
        actionBits &= ~lb;
        while (actionBits != 0) {
            lb = Integer.highestOneBit(actionBits);
            sb.append(',').append(mappingFunction.apply(lb));
            actionBits &= ~lb;
        }
        return sb.toString();
    }

    /**
     * Deparse an action bit set, using the given function to map action bits to strings.  If the bits are all clear,
     * the empty string {@code ""} is returned.
     *
     * @param actionBits the action bit set
     * @param mappingFunction the mapping function (must not be {@code null})
     * @return the actions string (not {@code null})
     */
    public static String toActionsString(long actionBits, LongFunction mappingFunction) {
        Assert.checkNotNullParam("mappingFunction", mappingFunction);
        final StringBuilder sb = new StringBuilder();
        if (actionBits == 0) return "";
        long lb = Long.highestOneBit(actionBits);
        sb.append(mappingFunction.apply(lb));
        actionBits &= ~lb;
        while (actionBits != 0) {
            lb = Long.highestOneBit(actionBits);
            sb.append(',').append(mappingFunction.apply(lb));
            actionBits &= ~lb;
        }
        return sb.toString();
    }

    /**
     * Create an iterable view over a permission collection.
     *
     * @param pc the permission collection (must not be {@code null})
     * @return the iterable view (not {@code null})
     */
    public static Iterable iterable(PermissionCollection pc) {
        return () -> {
            final Enumeration elements = pc.elements();
            return new Iterator() {
                public boolean hasNext() {
                    return elements.hasMoreElements();
                }

                public Permission next() {
                    return elements.nextElement();
                }
            };
        };
    }

    /**
     * Perform an action for each permission in the given collection.
     *
     * @param collection the collection (must not be {@code null})
     * @param consumer the consumer to which each permission should be passed (must not be {@code null})
     */
    public static void forEachIn(PermissionCollection collection, Consumer consumer) {
        Assert.checkNotNullParam("collection", collection);
        Assert.checkNotNullParam("consumer", consumer);
        final Enumeration elements = collection.elements();
        while (elements.hasMoreElements()) {
            consumer.accept(elements.nextElement());
        }
    }

    /**
     * Perform an action for each permission in the given collection.
     *
     * @param collection the collection (must not be {@code null})
     * @param parameter the parameter to pass to the consumer
     * @param consumer the consumer to which each permission should be passed (must not be {@code null})
     * @param 

the type of the parameter * @return the {@code parameter} that was passed in */ public static

P forEachIn(PermissionCollection collection, BiConsumer consumer, P parameter) { Assert.checkNotNullParam("collection", collection); Assert.checkNotNullParam("consumer", consumer); final Enumeration elements = collection.elements(); while (elements.hasMoreElements()) { consumer.accept(parameter, elements.nextElement()); } return parameter; } /** * Run a test for each permission in the given collection. If the predicate returns {@code false} for any element, * {@code false} is returned; otherwise, {@code true} is returned. * * @param collection the collection (must not be {@code null}) * @param predicate the predicate to apply to each element (must not be {@code null}) * @return {@code true} if the predicate matched all the permissions in the collection, {@code false} otherwise */ public static boolean forEachIn(PermissionCollection collection, Predicate predicate) { Assert.checkNotNullParam("collection", collection); Assert.checkNotNullParam("predicate", predicate); final Enumeration elements = collection.elements(); while (elements.hasMoreElements()) { if (! predicate.test(elements.nextElement())) { return false; } } return true; } /** * Run a test for each permission in the given collection. If the predicate returns {@code false} for any element, * {@code false} is returned; otherwise, {@code true} is returned. * * @param collection the collection (must not be {@code null}) * @param parameter the parameter to pass to the consumer * @param predicate the predicate to apply to each element (must not be {@code null}) * @param

the type of the parameter * @return {@code true} if the predicate matched all the permissions in the collection, {@code false} otherwise */ public static

boolean forEachIn(PermissionCollection collection, BiPredicate predicate, P parameter) { Assert.checkNotNullParam("collection", collection); Assert.checkNotNullParam("predicate", predicate); final Enumeration elements = collection.elements(); while (elements.hasMoreElements()) { if (! predicate.test(parameter, elements.nextElement())) { return false; } } return true; } /** * Create a permission collection that is the union of two permission collections. The permission * collections must be read-only. * * @param pc1 the first permission collection (must not be {@code null}) * @param pc2 the second permission collection (must not be {@code null}) * @return a new permission collection that is the union of the two collections (not {@code null}) */ public static PermissionCollection union(PermissionCollection pc1, PermissionCollection pc2) { Assert.checkNotNullParam("pc1", pc1); Assert.checkNotNullParam("pc2", pc2); if (! pc1.isReadOnly() || ! pc2.isReadOnly()) { throw ElytronMessages.log.permissionCollectionMustBeReadOnly(); } if (pc1.implies(ALL_PERMISSION) || pc2.implies(ALL_PERMISSION)) { return ALL_PERMISSIONS; } else { return new UnionPermissionCollection(pc1, pc2); } } /** * Create a permission collection that is the intersection of two permission collections. The permission * collections must be read-only. * * @param pc1 the first permission collection (must not be {@code null}) * @param pc2 the second permission collection (must not be {@code null}) * @return a new permission collection that is the intersection of the two collections (not {@code null}) */ public static PermissionCollection intersection(PermissionCollection pc1, PermissionCollection pc2) { Assert.checkNotNullParam("pc1", pc1); Assert.checkNotNullParam("pc2", pc2); if (! pc1.isReadOnly() || ! pc2.isReadOnly()) { throw ElytronMessages.log.permissionCollectionMustBeReadOnly(); } if (pc1.implies(ALL_PERMISSION)) { return pc2; } else if (pc2.implies(ALL_PERMISSION)) { return pc1; } else { return new IntersectionPermissionCollection(pc1, pc2); } } /** * Determine if one collection implies all the permissions in the other collection. * * @param collection the collection to check against (must not be {@code null}) * @param testCollection the collection whose permissions are to be tested (must not be {@code null}) * @return {@code true} if {@code collection} implies all of the permissions in {@code testCollection}, {@code false} otherwise */ public static boolean impliesAll(PermissionCollection collection, PermissionCollection testCollection) { return forEachIn(collection, PermissionCollection::implies, testCollection); } /** * Determine if two permission collections are equal, that is, each collection implies all of the permissions in the * other collection. * * @param pc1 the first collection (must not be {@code null}) * @param pc2 the second collection (must not be {@code null}) * @return {@code true} if the collections imply one another, {@code false} otherwise */ public static boolean equals(PermissionCollection pc1, PermissionCollection pc2) { return impliesAll(pc1, pc2) && impliesAll(pc2, pc1); } /** * Add all of the permissions from the source collection to the target collection. * * @param target the target collection (must not be {@code null}) * @param source the source collection (must not be {@code null}) * @return the target collection (not {@code null}) */ public static PermissionCollection addAll(PermissionCollection target, PermissionCollection source) { return forEachIn(source, PermissionCollection::add, target); } /** * Add all of the permissions from the source collection to the target collection. * * @param target the target collection (must not be {@code null}) * @param source the source collection (must not be {@code null}) * @return the target collection (not {@code null}) */ public static PermissionCollection addAll(PermissionCollection target, Collection source) { source.forEach(target::add); return target; } /** * Add a permission to a collection, returning the target collection. If the permission is {@code null}, it is * not added. * * @param target the target collection (must not be {@code null}) * @param source the permission to add * @return the target collection (not {@code null}) */ public static PermissionCollection add(PermissionCollection target, Permission source) { Assert.checkNotNullParam("target", target); if (source != null) target.add(source); return target; } /** * Instantiate a permission with the given class name, permission name, and actions. * * @param classLoader the class loader to search in ({@code null} indicates the system class loader) * @param className the name of the permission class to instantiate (must not be {@code null}) * @param name the permission name (may be {@code null} if allowed by the permission class) * @param actions the permission actions (may be {@code null} if allowed by the permission class) * @return the permission object (not {@code null}) * @throws InvalidPermissionClassException if the permission class does not exist or is not valid * @throws ClassCastException if the class name does not refer to a subclass of {@link Permission} */ public static Permission createPermission(final ClassLoader classLoader, final String className, final String name, final String actions) { Assert.checkNotNullParam("className", className); final Class permissionClass; try { permissionClass = Class.forName(className, true, classLoader).asSubclass(Permission.class); } catch (ClassNotFoundException e) { throw ElytronMessages.log.permissionClassMissing(className, e); } return createPermission(permissionClass, name, actions); } /** * Instantiate a permission with the given class, permission name, and actions. * * @param permissionClass the permission class to instantiate (must not be {@code null}) * @param name the permission name (may be {@code null} if allowed by the permission class) * @param actions the permission actions (may be {@code null} if allowed by the permission class) * @return the permission object (not {@code null}) * @throws InvalidPermissionClassException if the permission class does not exist or is not valid */ public static Permission createPermission(final Class permissionClass, final String name, final String actions) { Assert.checkNotNullParam("permissionClass", permissionClass); Constructor noArgs = null; Constructor oneArg = null; Constructor twoArg = null; for (Constructor raw : permissionClass.getConstructors()) { @SuppressWarnings("unchecked") Constructor ctor = (Constructor) raw; final Class[] parameterTypes = ctor.getParameterTypes(); if (parameterTypes.length == 2 && parameterTypes[0] == String.class && parameterTypes[1] == String.class) { twoArg = ctor; } else if (parameterTypes.length == 1 && parameterTypes[0] == String.class) { oneArg = ctor; } else if (parameterTypes.length == 0) { noArgs = ctor; } } try { if (twoArg != null) { return twoArg.newInstance(name, actions); } else if (oneArg != null) { return oneArg.newInstance(name); } else if (noArgs != null) { return noArgs.newInstance(); } else { throw ElytronMessages.log.noPermissionConstructor(permissionClass.getName()); } } catch (IllegalAccessException e) { throw new IllegalAccessError(e.getMessage()); } catch (InstantiationException e) { throw ElytronMessages.log.permissionInstantiation(permissionClass.getName(), e); } catch (InvocationTargetException e) { try { throw e.getCause(); } catch (Error | RuntimeException cause) { throw cause; } catch (Throwable cause) { throw new UndeclaredThrowableException(cause); } } } /** * Get a read-only collection of the given permissions. * * @param permissions the permissions to assign * @return the read-only collection */ public static PermissionCollection readOnlyCollectionOf(Permission... permissions) { final int length = permissions.length; if (length == 0) { return EMPTY_PERMISSION_COLLECTION; } else { Permissions collection = new Permissions(); addAll(collection, Arrays.asList(permissions)); collection.setReadOnly(); return collection; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy