001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2008 Sun Microsystems, Inc.
025 *      Portions Copyright 2013-2015 ForgeRock AS
026 */
027package org.opends.server.authorization.dseecompat;
028
029import static org.opends.messages.AccessControlMessages.*;
030import static org.opends.server.authorization.dseecompat.Aci.*;
031
032import java.util.Iterator;
033import java.util.Set;
034import java.util.regex.Pattern;
035
036import org.forgerock.i18n.LocalizableMessage;
037
038/**
039 * A class representing the permissions of an bind rule. The permissions
040 * of an ACI look like deny(search, write).
041 */
042public class Permission {
043
044    /**
045     *  The access type (allow,deny) corresponding to the ACI permission value.
046     */
047    private EnumAccessType accessType;
048
049    /**
050     * The rights (search, add, delete, ...) corresponding to the ACI rights
051     * value.
052     */
053    private int rights;
054
055    /**
056     * Regular expression token representing the separator.
057     */
058    private static final String separatorToken = ",";
059
060    /**
061     * Regular expression used to match the ACI rights string.
062     */
063    private static final String rightsRegex = ZERO_OR_MORE_WHITESPACE +
064            WORD_GROUP + ZERO_OR_MORE_WHITESPACE +
065            "(," + ZERO_OR_MORE_WHITESPACE + WORD_GROUP +
066            ZERO_OR_MORE_WHITESPACE +  ")*";
067
068    /**
069     * Constructor creating a class representing a permission part of an bind
070     * rule.
071     * @param accessType A string representing access type.
072     * @param rights  A string representing the rights.
073     * @throws AciException If the access type string or rights string
074     * is invalid.
075     */
076    private Permission(String accessType, String rights)
077    throws AciException {
078        this.accessType = EnumAccessType.decode(accessType);
079        if (this.accessType == null){
080            LocalizableMessage message =
081                WARN_ACI_SYNTAX_INVALID_ACCESS_TYPE_VERSION.get(accessType);
082            throw new AciException(message);
083        }
084        if (!Pattern.matches(rightsRegex, rights)){
085            LocalizableMessage message = WARN_ACI_SYNTAX_INVALID_RIGHTS_SYNTAX.get(rights);
086            throw new AciException(message);
087        }
088        else {
089            Pattern separatorPattern = Pattern.compile(separatorToken);
090            String[] rightsStr =
091                separatorPattern.split(rights.replaceAll("\\s", ""));
092            for (String r : rightsStr) {
093                EnumRight right = EnumRight.decode(r);
094                if (right != null) {
095                  this.rights|= EnumRight.getMask(right);
096                } else {
097                    LocalizableMessage message =
098                        WARN_ACI_SYNTAX_INVALID_RIGHTS_KEYWORD.get(rights);
099                    throw new AciException(message);
100                }
101            }
102        }
103    }
104
105    /**
106     * Decode an string representation of bind rule permission into a Permission
107     * class.
108     * @param accessType  A string representing the access type.
109     * @param rights   A string representing the rights.
110     * @return  A Permission class representing the permissions of the bind
111     * rule.
112     * @throws AciException  If the accesstype or rights strings are invalid.
113     */
114    public static Permission decode (String accessType, String rights)
115            throws AciException {
116        return new Permission(accessType, rights);
117    }
118
119    /**
120     * Checks if a given access type enumeration is equal to this classes
121     * access type.
122     * @param accessType An enumeration representing an access type.
123     * @return True if the access types are equal.
124     */
125    public boolean hasAccessType(EnumAccessType accessType) {
126        return this.accessType == accessType;
127    }
128
129    /**
130     * Checks if the permission's rights has the specified rights.
131     * @param  rights The rights to check for.
132     * @return True if the permission's rights has the specified rights.
133     */
134    public boolean hasRights(int rights) {
135        return (this.rights & rights) != 0;
136    }
137
138    /** {@inheritDoc} */
139    @Override
140    public String toString() {
141        final StringBuilder sb = new StringBuilder();
142        toString(sb);
143        return sb.toString();
144    }
145
146    /**
147     * Appends a string representation of this object to the provided buffer.
148     *
149     * @param buffer
150     *          The buffer into which a string representation of this object
151     *          should be appended.
152     */
153    public final void toString(StringBuilder buffer) {
154        if (this.accessType != null) {
155            buffer.append(accessType.toString().toLowerCase());
156            Set<EnumRight> enumRights = EnumRight.getEnumRight(rights);
157            if (enumRights != null) {
158                buffer.append("(");
159                for (Iterator<EnumRight> iter = enumRights.iterator(); iter
160                        .hasNext();) {
161                    buffer.append(iter.next().getRight());
162                    if (iter.hasNext()) {
163                        buffer.append(",");
164                    }
165                }
166                buffer.append(")");
167            } else {
168                buffer.append("(all)");
169            }
170        }
171    }
172}