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 2014-2015 ForgeRock AS
026 */
027package org.opends.server.authorization.dseecompat;
028
029import java.util.regex.Pattern;
030
031import org.opends.server.types.DN;
032import org.opends.server.types.DirectoryException;
033import org.opends.server.types.LDAPURL;
034
035import static org.opends.messages.AccessControlMessages.*;
036import static org.opends.server.authorization.dseecompat.Aci.*;
037
038/**
039 * A class representing an ACI target keyword.
040 */
041public class Target
042{
043    /**
044     * Enumeration representing the target operator.
045     */
046    private EnumTargetOperator operator = EnumTargetOperator.EQUALITY;
047
048    /**
049     * True if the URL contained a DN wild-card pattern.
050     */
051    private boolean isPattern;
052
053    /**
054     * The target DN from the URL or null if it was a wild-card pattern.
055     */
056    private DN urlDN;
057
058    /**
059     * The pattern matcher for a wild-card pattern or null if the URL
060     * contained an ordinary DN.
061     */
062    private PatternDN patternDN;
063
064    /*
065     * TODO Save aciDN parameter and use it in matchesPattern re-write.
066     *
067     * Should the aciDN argument provided to the constructor be stored so that
068     * it can be used in the matchesPattern() method?  The DN should only be
069     * considered a potential match if it is at or below the entry containing
070     * the ACI.
071     *
072     */
073    /**
074     * This constructor parses the target string.
075     * @param operator  An enumeration of the operation of this target.
076     * @param target A string representation of the target.
077     * @param aciDN The dn of the ACI entry used for a descendant check.
078     * @throws AciException If the target string is invalid.
079     */
080    private Target(EnumTargetOperator operator, String target, DN aciDN)
081            throws AciException {
082        this.operator = operator;
083        try {
084          //The NULL_LDAP_URL corresponds to the root DSE.
085          if (!NULL_LDAP_URL.equals(target) && !Pattern.matches(LDAP_URL, target)) {
086              throw new AciException(WARN_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION.get(target));
087          }
088          LDAPURL targetURL =  LDAPURL.decode(target, false);
089          if (targetURL.getRawBaseDN().contains("*")) {
090              this.isPattern=true;
091              patternDN = PatternDN.decodeSuffix(targetURL.getRawBaseDN());
092          } else {
093              urlDN=targetURL.getBaseDN();
094              if(!urlDN.isDescendantOf(aciDN)) {
095                  throw new AciException(WARN_ACI_SYNTAX_TARGET_DN_NOT_DESCENDENTOF.get(urlDN, aciDN));
096              }
097          }
098        }
099        catch (DirectoryException e){
100            throw new AciException(WARN_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION.get(target));
101        }
102    }
103
104    /**
105     *  Decode an expression string representing a target keyword expression.
106     * @param operator  An enumeration of the operation of this target.
107     * @param expr A string representation of the target.
108     * @param aciDN  The DN of the ACI entry used for a descendant check.
109     * @return  A Target class representing this target.
110     * @throws AciException  If the expression string is invalid.
111     */
112    public static Target decode(EnumTargetOperator operator,
113                                String expr, DN aciDN)
114            throws AciException {
115        return new Target(operator, expr, aciDN);
116    }
117
118    /**
119     * Returns the operator of this expression.
120     * @return An enumeration of the operation value.
121     */
122    public EnumTargetOperator getOperator() {
123        return operator;
124    }
125
126    /**
127     * Returns the URL DN of the expression.
128     * @return A DN of the URL or null if the URL contained a DN pattern.
129     */
130    public DN getDN() {
131        return urlDN;
132    }
133
134    /**
135     * Returns boolean if a pattern was seen during parsing.
136     * @return  True if the URL contained a DN pattern.
137     */
138    public boolean isPattern() {
139        return isPattern;
140    }
141
142    /**
143     * This method tries to match a pattern against a DN.
144     * @param dn  The DN to try an match.
145     * @return True if the pattern matches.
146     */
147    public boolean matchesPattern(DN dn) {
148        return patternDN.matchesDN(dn);
149    }
150}