001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2008 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2016 ForgeRock AS.
016 */
017package org.opends.server.authorization.dseecompat;
018
019import java.util.regex.Pattern;
020
021import org.forgerock.opendj.ldap.DN;
022import org.opends.server.types.DirectoryException;
023import org.opends.server.types.LDAPURL;
024
025import static org.opends.messages.AccessControlMessages.*;
026import static org.opends.server.authorization.dseecompat.Aci.*;
027
028/**
029 * A class representing an ACI target keyword.
030 */
031public class Target
032{
033    /**
034     * Enumeration representing the target operator.
035     */
036    private EnumTargetOperator operator = EnumTargetOperator.EQUALITY;
037
038    /**
039     * True if the URL contained a DN wild-card pattern.
040     */
041    private boolean isPattern;
042
043    /**
044     * The target DN from the URL or null if it was a wild-card pattern.
045     */
046    private DN urlDN;
047
048    /**
049     * The pattern matcher for a wild-card pattern or null if the URL
050     * contained an ordinary DN.
051     */
052    private PatternDN patternDN;
053
054    /*
055     * TODO Save aciDN parameter and use it in matchesPattern re-write.
056     *
057     * Should the aciDN argument provided to the constructor be stored so that
058     * it can be used in the matchesPattern() method?  The DN should only be
059     * considered a potential match if it is at or below the entry containing
060     * the ACI.
061     *
062     */
063    /**
064     * This constructor parses the target string.
065     * @param operator  An enumeration of the operation of this target.
066     * @param target A string representation of the target.
067     * @param aciDN The dn of the ACI entry used for a descendant check.
068     * @throws AciException If the target string is invalid.
069     */
070    private Target(EnumTargetOperator operator, String target, DN aciDN)
071            throws AciException {
072        this.operator = operator;
073        try {
074          //The NULL_LDAP_URL corresponds to the root DSE.
075          if (!NULL_LDAP_URL.equals(target) && !Pattern.matches(LDAP_URL, target)) {
076              throw new AciException(WARN_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION.get(target));
077          }
078          LDAPURL targetURL =  LDAPURL.decode(target, false);
079          if (targetURL.getRawBaseDN().contains("*")) {
080              this.isPattern=true;
081              patternDN = PatternDN.decodeSuffix(targetURL.getRawBaseDN());
082          } else {
083              urlDN=targetURL.getBaseDN();
084              if(!urlDN.isSubordinateOrEqualTo(aciDN)) {
085                  throw new AciException(WARN_ACI_SYNTAX_TARGET_DN_NOT_DESCENDENTOF.get(urlDN, aciDN));
086              }
087          }
088        }
089        catch (DirectoryException e){
090            throw new AciException(WARN_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION.get(target));
091        }
092    }
093
094    /**
095     *  Decode an expression string representing a target keyword expression.
096     * @param operator  An enumeration of the operation of this target.
097     * @param expr A string representation of the target.
098     * @param aciDN  The DN of the ACI entry used for a descendant check.
099     * @return  A Target class representing this target.
100     * @throws AciException  If the expression string is invalid.
101     */
102    public static Target decode(EnumTargetOperator operator,
103                                String expr, DN aciDN)
104            throws AciException {
105        return new Target(operator, expr, aciDN);
106    }
107
108    /**
109     * Returns the operator of this expression.
110     * @return An enumeration of the operation value.
111     */
112    public EnumTargetOperator getOperator() {
113        return operator;
114    }
115
116    /**
117     * Returns the URL DN of the expression.
118     * @return A DN of the URL or null if the URL contained a DN pattern.
119     */
120    public DN getDN() {
121        return urlDN;
122    }
123
124    /**
125     * Returns boolean if a pattern was seen during parsing.
126     * @return  True if the URL contained a DN pattern.
127     */
128    public boolean isPattern() {
129        return isPattern;
130    }
131
132    /**
133     * This method tries to match a pattern against a DN.
134     * @param dn  The DN to try an match.
135     * @return True if the pattern matches.
136     */
137    public boolean matchesPattern(DN dn) {
138        return patternDN.matchesDN(dn);
139    }
140}