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.*; 020import static org.opends.server.authorization.dseecompat.Aci.*; 021 022import java.util.LinkedList; 023import java.util.List; 024import java.util.regex.Matcher; 025import java.util.regex.Pattern; 026 027import org.forgerock.i18n.LocalizableMessage; 028import org.forgerock.i18n.LocalizedIllegalArgumentException; 029import org.forgerock.opendj.ldap.ByteString; 030import org.forgerock.opendj.ldap.DN; 031import org.opends.server.api.Group; 032import org.opends.server.core.DirectoryServer; 033import org.opends.server.core.GroupManager; 034import org.forgerock.opendj.ldap.schema.AttributeType; 035import org.opends.server.types.*; 036 037/** 038 * This class implements the groupdn bind rule keyword. 039 */ 040public class GroupDN implements KeywordBindRule { 041 042 /** List of group DNs. */ 043 private List<DN> groupDNs; 044 045 /** Enumeration representing the groupdn operator type. */ 046 private EnumBindRuleType type; 047 048 /** 049 * Regular expression matching one or more LDAP URLs separated by 050 * "||". 051 */ 052 public static final String LDAP_URLS = LDAP_URL + 053 ZERO_OR_MORE_WHITESPACE + "(" + LOGICAL_OR + 054 ZERO_OR_MORE_WHITESPACE + LDAP_URL + ")*"; 055 056 /** 057 * Create a class representing a groupdn bind rule keyword. 058 * @param type An enumeration representing the bind rule type. 059 * @param groupDNs A list of the dns representing groups. 060 */ 061 private GroupDN(EnumBindRuleType type, List<DN> groupDNs ) { 062 this.groupDNs=groupDNs; 063 this.type=type; 064 } 065 066 /** 067 * Decode an string expression representing a groupdn bind rule. 068 * @param expr A string representation of the bind rule. 069 * @param type An enumeration of the type of the bind rule. 070 * @return A keyword bind rule class that can be used to evaluate 071 * this bind rule. 072 * @throws AciException If the expression string is invalid. 073 */ 074 public static KeywordBindRule decode(String expr, EnumBindRuleType type) 075 throws AciException { 076 if (!Pattern.matches(LDAP_URLS, expr)) { 077 LocalizableMessage message = 078 WARN_ACI_SYNTAX_INVALID_GROUPDN_EXPRESSION.get(expr); 079 throw new AciException(message); 080 } 081 List<DN> groupDNs = new LinkedList<>(); 082 int ldapURLPos = 1; 083 Pattern ldapURLPattern = Pattern.compile(LDAP_URL); 084 Matcher ldapURLMatcher = ldapURLPattern.matcher(expr); 085 while (ldapURLMatcher.find()) { 086 try { 087 String value = ldapURLMatcher.group(ldapURLPos).trim(); 088 DN dn=LDAPURL.decode(value, true).getBaseDN(); 089 groupDNs.add(dn); 090 } catch (DirectoryException ex) { 091 LocalizableMessage message = WARN_ACI_SYNTAX_INVALID_GROUPDN_URL.get( 092 ex.getMessageObject()); 093 throw new AciException(message); 094 } 095 } 096 return new GroupDN(type, groupDNs); 097 } 098 099 /** 100 * Performs the evaluation of a groupdn bind rule based on the 101 * evaluation context passed to it. The evaluation stops when there 102 * are no more group DNs to evaluate, or if a group DN evaluates to true 103 * if it contains the client DN. 104 * @param evalCtx An evaluation context to use in the evaluation. 105 * @return Enumeration evaluation result. 106 */ 107 @Override 108 public EnumEvalResult evaluate(AciEvalContext evalCtx) { 109 EnumEvalResult matched = EnumEvalResult.FALSE; 110 for (DN groupDN : groupDNs) { 111 Group<?> group = getGroupManager().getGroupInstance(groupDN); 112 if(group != null && evalCtx.isMemberOf(group)) { 113 matched = EnumEvalResult.TRUE; 114 break; 115 } 116 } 117 return matched.getRet(type, false); 118 } 119 120 /** 121 * Performs an evaluation of a group that was specified in an attribute 122 * type value of the specified entry and attribute type. Each 123 * value of the attribute type is assumed to be a group DN and evaluation 124 * stops when there are no more values or if the group DN evaluates to 125 * true if it contains the client DN. 126 * @param e The entry to use in the evaluation. 127 * @param evalCtx The evaluation context to use in the evaluation. 128 * @param attributeType The attribute type of the entry to use to get the 129 * values for the groupd DNs. 130 * @param suffixDN The suffix that the groupDN must be under. If it's null, 131 * then the groupDN can be anywhere in the DIT. 132 * @return Enumeration evaluation result. 133 */ 134 public static EnumEvalResult evaluate (Entry e, AciEvalContext evalCtx, 135 AttributeType attributeType, 136 DN suffixDN) { 137 EnumEvalResult matched= EnumEvalResult.FALSE; 138 List<Attribute> attrs = e.getAttribute(attributeType); 139 for(ByteString v : attrs.get(0)) { 140 try { 141 DN groupDN = DN.valueOf(v.toString()); 142 if(suffixDN != null && !groupDN.isSubordinateOrEqualTo(suffixDN)) 143 { 144 continue; 145 } 146 Group<?> group = getGroupManager().getGroupInstance(groupDN); 147 if(group != null && evalCtx.isMemberOf(group)) { 148 matched=EnumEvalResult.TRUE; 149 break; 150 } 151 } catch (LocalizedIllegalArgumentException ignored) { 152 break; 153 } 154 } 155 return matched; 156 } 157 158 private static GroupManager getGroupManager() { 159 return DirectoryServer.getGroupManager(); 160 } 161 162 /** {@inheritDoc} */ 163 @Override 164 public String toString() { 165 final StringBuilder sb = new StringBuilder(); 166 toString(sb); 167 return sb.toString(); 168 } 169 170 /** {@inheritDoc} */ 171 @Override 172 public final void toString(StringBuilder buffer) { 173 buffer.append(super.toString()); 174 } 175 176}