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