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

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

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show 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 static org.wildfly.security.permission.SecurityMessages.permission;

import org.wildfly.common.Assert;

import java.util.Arrays;
import java.util.EnumSet;
import java.util.Iterator;

/**
 * A helper class for defining permissions which use a finite list of actions.  Define custom permissions using
 * an {@code enum} of actions, where the string representation (via {@code toString()}) of each enum is one possible
 * action name.  Typically the {@code enum} should be non-public, and the constant names should be lowercase.  If
 * an action name contains a character which is not a valid Java identifier, then the {@code toString()} method of
 * such constants should be overridden to report the correct string.  The actions may be stored on the permission as
 * an {@code EnumSet}, an {@code int}, or a {@code long}.  The field should be marked {@code transient}, and
 * the actions represented by a (possibly synthetic) field of type {@code String} which uses the canonical representation
 * of the actions.
 *
 * @author David M. Lloyd
 *
 * @deprecated Use one of the abstract permission classes like {@link AbstractActionSetPermission} instead.
 */
@Deprecated
public final class PermissionActions {

    private PermissionActions() {
    }

    static final class TrieNode {
        private static final char[] C_EMPTY = new char[0];
        private static final TrieNode[] T_EMPTY = new TrieNode[0];

        private E result;
        private char[] matches = C_EMPTY;
        @SuppressWarnings("unchecked")
        private TrieNode[] children = T_EMPTY;

        void put(String s, int idx, E value) {
            if (idx == s.length()) {
                result = value;
                return;
            }
            char c = s.charAt(idx);
            final int i = Arrays.binarySearch(matches, c);
            if (i < 0) {
                // copy and add
                final int oldLength = matches.length;
                final char[] newMatches = Arrays.copyOf(matches, oldLength + 1);
                final TrieNode[] newChildren = Arrays.copyOf(children, oldLength + 1);
                // i is the negated insertion index
                final int insertIndex = -i - 1;
                System.arraycopy(newMatches, insertIndex, newMatches, insertIndex + 1, oldLength - insertIndex);
                System.arraycopy(newChildren, insertIndex, newChildren, insertIndex + 1, oldLength - insertIndex);
                newMatches[insertIndex] = c;
                final TrieNode newNode = new TrieNode<>();
                newChildren[insertIndex] = newNode;
                matches = newMatches;
                children = newChildren;
                newNode.put(s, idx + 1, value);
            } else {
                children[i].put(s, idx + 1, value);
            }
        }

        E get(String s, int idx, int end) {
            if (idx == end) {
                return result;
            }
            final char c = s.charAt(idx);
            final int i = Arrays.binarySearch(matches, c);
            if (i < 0) {
                return null;
            }
            return children[i].get(s, idx + 1, end);
        }
    }

    static final class Info {
        final TrieNode root;
        final E[] constants;

        Info(final TrieNode root, final E[] constants) {
            this.root = root;
            this.constants = constants;
        }
    }

    private static final ClassValue> storedInfo = new ClassValue>() {
        protected Info computeValue(final Class type) {
            return computeReal(type);
        }

        private  Info computeReal(final Class type) {
            final TrieNode root = new TrieNode<>();
            final E[] enumConstants = type.getEnumConstants();
            for (E e : enumConstants) {
                root.put(e.toString(), 0, e);
            }
            return new Info<>(root, type.getEnumConstants());
        }
    };

    interface MatchAction> {
        void matched(E item);

        void matchedAll(Class type);
    }

    static class SetMatchAction> implements MatchAction {
        private EnumSet set;

        SetMatchAction(final EnumSet set) {
            this.set = set;
        }

        public void matched(final E item) {
            set.add(item);
        }

        public void matchedAll(final Class type) {
            set = EnumSet.allOf(type);
        }

        public EnumSet getSet() {
            return set;
        }
    }

    static class IntMatchAction> implements MatchAction {
        private int result;

        IntMatchAction() {
        }

        public void matched(final E item) {
            result |= 1 << item.ordinal();
        }

        public void matchedAll(final Class type) {
            result |= (1 << storedInfo.get(type).constants.length) - 1;
        }

        public int getResult() {
            return result;
        }
    }

    static class LongMatchAction> implements MatchAction {
        private long result;

        LongMatchAction() {
        }

        public void matched(final E item) {
            result |= 1L << item.ordinal();
        }

        public void matchedAll(final Class type) {
            result |= (1L << storedInfo.get(type).constants.length) - 1;
        }

        public long getResult() {
            return result;
        }
    }

    /**
     * Parse an action string using the given action type to an {@code EnumSet}.
     *
     * @param actionType the action {@code enum} type class
     * @param actionString the string to parse
     * @param  the action {@code enum} type
     *
     * @return the set of actions from the string
     *
     * @throws IllegalArgumentException if the string contained an invalid action
     */
    public static > EnumSet parseActionStringToSet(Class actionType, String actionString) throws IllegalArgumentException {
        Assert.checkNotNullParam("actionType", actionType);
        Assert.checkNotNullParam("actionString", actionString);
        final SetMatchAction matchAction = new SetMatchAction<>(EnumSet.noneOf(actionType));
        doParse(actionType, actionString, matchAction);
        return matchAction.getSet();
    }

    /**
     * Parse an action string using the given action type to an {@code int}.  The given {@code enum} type must have
     * 32 or fewer constant values.
     *
     * @param actionType the action {@code enum} type class
     * @param actionString the string to parse
     * @param  the action {@code enum} type
     *
     * @return the set of actions from the string
     *
     * @throws IllegalArgumentException if the string contained an invalid action
     */
    public static > int parseActionStringToInt(Class actionType, String actionString) throws IllegalArgumentException {
        Assert.checkNotNullParam("actionType", actionType);
        Assert.checkNotNullParam("actionString", actionString);
        final IntMatchAction matchAction = new IntMatchAction<>();
        doParse(actionType, actionString, matchAction);
        return matchAction.getResult();
    }

    /**
     * Parse an action string using the given action type to a {@code long}.  The given {@code enum} type must have
     * 64 or fewer constant values.
     *
     * @param actionType the action {@code enum} type class
     * @param actionString the string to parse
     * @param  the action {@code enum} type
     *
     * @return the set of actions from the string
     *
     * @throws IllegalArgumentException if the string contained an invalid action
     */
    public static > long parseActionStringToLong(Class actionType, String actionString) throws IllegalArgumentException {
        Assert.checkNotNullParam("actionType", actionType);
        Assert.checkNotNullParam("actionString", actionString);
        final LongMatchAction matchAction = new LongMatchAction<>();
        doParse(actionType, actionString, matchAction);
        return matchAction.getResult();
    }

    private static > void doParse(final Class actionType, final String actionString, final MatchAction matchAction) {
        @SuppressWarnings("unchecked")
        final Info info = (Info) storedInfo.get(actionType);
        final TrieNode rootNode = info.root;
        // begin parse
        char c;
        final int length = actionString.length();
        int i = 0;
        L0: for (;;) {
            if (i == length) {
                // OK
                break L0;
            }
            c = actionString.charAt(i);
            if (Character.isWhitespace(c)) {
                i ++;
                continue L0;
            }
            if (c == ',') {
                // hmm, empty segment; ignore it
                i ++;
                continue L0;
            }
            if (c == '*') {
                // potential star
                matchAction.matchedAll(actionType);
                for (;;) {
                    i ++;
                    if (i == length) {
                        // done
                        break L0;
                    }
                    c = actionString.charAt(i);
                    if (c == ',') {
                        // pointless, but go on
                        i ++;
                        continue L0;
                    }
                    if (! Character.isWhitespace(c)) {
                        throw permission.unexpectedActionCharacter(c, i, actionString);
                    }
                }
                // not reachable
            }
            // else it's a potentially valid character
            int start = i;
            for (;;) {
                i++;
                c = i < length ? actionString.charAt(i) : 0;
                if (i == length || Character.isWhitespace(c) || c == ',') {
                    // action string ends here
                    final E action = rootNode.get(actionString, start, i);
                    if (action == null) {
                        throw permission.invalidAction(actionString.substring(start, i), start, actionString);
                    }
                    matchAction.matched(action);
                    if (i == length) {
                        // done
                        break L0;
                    }
                    while (Character.isWhitespace(c)) {
                        i++;
                        if (i == length) {
                            // done
                            break L0;
                        }
                        c = actionString.charAt(i);
                    }
                    if (c != ',') {
                        throw permission.unexpectedActionCharacter(c, i, actionString);
                    }
                    i ++;
                    continue L0;
                }
            }
            // not reachable
        }
    }

    /**
     * Get the canonical action string representation for the given action set.
     *
     * @param set the action set
     * @param  the action type
     * @return the canonical representation
     */
    public static > String getCanonicalActionString(EnumSet set) {
        if (set == null || set.isEmpty()) return "";
        final StringBuilder b = new StringBuilder();
        getCanonicalActionString(set, b);
        return b.toString();
    }

    /**
     * Get the canonical action string representation for the given action set, appending it to the given string builder.
     *
     * @param set the action set
     * @param b the string builder
     * @param  the action type
     */
    public static > void getCanonicalActionString(EnumSet set, StringBuilder b) {
        if (set == null || set.isEmpty()) return;
        final Iterator iterator = set.iterator();
        if (iterator.hasNext()) {
            E e = iterator.next();
            b.append(e.toString());
            while (iterator.hasNext()) {
                e = iterator.next();
                b.append(',');
                b.append(e.toString());
            }
        }
    }

    /**
     * Get the canonical action string representation for the given action set.
     *
     * @param type the action {@code enum} type class
     * @param set the action set
     * @param  the action type
     * @return the canonical representation
     */
    public static > String getCanonicalActionString(Class type, int set) {
        if (set == 0) return "";
        final StringBuilder b = new StringBuilder();
        getCanonicalActionString(type, set, b);
        return b.toString();
    }

    /**
     * Get the canonical action string representation for the given action set, appending it to the given string builder.
     *
     * @param type the action {@code enum} type class
     * @param set the action set
     * @param b the string builder
     * @param  the action type
     */
    public static > void getCanonicalActionString(Class type, int set, StringBuilder b) {
        if (set == 0) return;
        @SuppressWarnings("unchecked")
        final E[] constants = (E[]) storedInfo.get(type).constants;
        int bit = Integer.lowestOneBit(set);
        E e = constants[Integer.numberOfTrailingZeros(bit)];
        b.append(e.toString());
        set &= ~bit;
        while (set != 0) {
            bit = Integer.lowestOneBit(set);
            e = constants[Integer.numberOfTrailingZeros(bit)];
            b.append(',').append(e.toString());
            set &= ~bit;
        }
    }

    /**
     * Get the canonical action string representation for the given action set.
     *
     * @param type the action {@code enum} type class
     * @param set the action set
     * @param  the action type
     * @return the canonical representation
     */
    public static > String getCanonicalActionString(Class type, long set) {
        if (set == 0) return "";
        final StringBuilder b = new StringBuilder();
        getCanonicalActionString(type, set, b);
        return b.toString();
    }

    /**
     * Get the canonical action string representation for the given action set, appending it to the given string builder.
     *
     * @param type the action {@code enum} type class
     * @param set the action set
     * @param b the string builder
     * @param  the action type
     */
    public static > void getCanonicalActionString(Class type, long set, StringBuilder b) {
        if (set == 0) return;
        @SuppressWarnings("unchecked")
        final E[] constants = (E[]) storedInfo.get(type).constants;
        long bit = Long.lowestOneBit(set);
        E e = constants[Long.numberOfTrailingZeros(bit)];
        b.append(e.toString());
        set &= ~bit;
        while (set != 0) {
            bit = Long.lowestOneBit(set);
            e = constants[Long.numberOfTrailingZeros(bit)];
            b.append(',').append(e.toString());
            set &= ~bit;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy