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 2013-2016 ForgeRock AS.
016 */
017package org.opends.server.authorization.dseecompat;
018
019import static org.opends.messages.AccessControlMessages.*;
020
021import java.net.InetAddress;
022import java.util.Iterator;
023import java.util.LinkedList;
024import java.util.List;
025import java.util.regex.Pattern;
026
027/**
028 * This class represents a single ACI's IP bind rule expression. It is possible
029 * for that expression to contain several IP addresses to evaluate, so the
030 * class contains a list of classes that can evaluate a remote clients IP
031 * address for each IP address parsed from the bind rule.
032 */
033public class IP implements KeywordBindRule {
034    /**
035     * Regular expression used to do a quick check on the characters in a
036     * bind rule address. These are all of the valid characters that may
037     * appear in an bind rule address part.
038     */
039    private static final Pattern ipRegEx =
040        Pattern.compile("((?i)[\\.{1}[a-f]\\d:\\+{1}\\*/{1}\\t\\[{1}\\]{1}]+(?-i))");
041
042    /** List of the pattern classes, one for each address decoded from the bind rule. */
043    private final List<PatternIP> patternIPList;
044    /** The type of the bind rule (!= or =). */
045    private final EnumBindRuleType type;
046
047    /**
048     * Create a class representing the IP bind rule expressions for this ACI.
049     * @param patternIPList A list of PatternIP objects representing the IP
050     *                      bind rule expressions decoded from ACI.
051     * @param type An enumeration representing the expression type.
052     */
053    private IP(List<PatternIP> patternIPList, EnumBindRuleType type) {
054        this.patternIPList=patternIPList;
055        this.type=type;
056    }
057
058    /**
059     * Decodes the provided IP bind rule expression string and returns an
060     * IP class the can be used to evaluate remote clients IP addresses.
061     *
062     * @param expr The expression string from the ACI IP bind rule.
063     * @param type An enumeration representing the expression type.
064     * @return  A class that can be used to evaluate remote clients IP
065     *          addresses.
066     * @throws AciException  If there is a parsing error.
067     */
068    public static KeywordBindRule decode(String expr, EnumBindRuleType type)
069            throws AciException  {
070        //Split on the ','.
071        String[] ipStrs=expr.split("\\,", -1);
072        List<PatternIP> patternIPList= new LinkedList<>();
073        for (String ipStr : ipStrs) {
074            if (!ipRegEx.matcher(ipStr).matches()) {
075                throw new AciException(WARN_ACI_SYNTAX_INVALID_IP_EXPRESSION.get(expr));
076            }
077            patternIPList.add(PatternIP.decode(ipStr));
078        }
079        return new IP(patternIPList, type);
080    }
081
082    /**
083     * Perform an evaluation using the provided evaluation context's remote
084     * IP address information.
085     *
086     * @param evalCtx An evaluation context containing the remote clients
087     * IP address information.
088     *
089     * @return An enumeration representing if the address matched.
090     */
091    @Override
092    public EnumEvalResult evaluate(AciEvalContext evalCtx) {
093        return evaluate(evalCtx.getRemoteAddress());
094    }
095
096    /**
097     * Perform an evaluation using the InetAddress.
098     *
099     * @param addr  The InetAddress to evaluate against PatternIP classes.
100     * @return  An enumeration representing if the address matched one
101     *          of the patterns.
102     */
103    EnumEvalResult evaluate(InetAddress addr) {
104        EnumEvalResult matched=EnumEvalResult.FALSE;
105        Iterator<PatternIP> it=patternIPList.iterator();
106        for(; it.hasNext() && matched != EnumEvalResult.TRUE &&
107                matched != EnumEvalResult.ERR;) {
108            PatternIP patternIP=it.next();
109            matched=patternIP.evaluate(addr);
110        }
111        return matched.getRet(type, false);
112    }
113
114    @Override
115    public String toString() {
116        final StringBuilder sb = new StringBuilder();
117        toString(sb);
118        return sb.toString();
119    }
120
121    @Override
122    public final void toString(StringBuilder buffer) {
123        buffer.append(super.toString());
124    }
125}