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-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.server.extensions; 018 019import java.util.Collections; 020import java.util.List; 021import java.util.Set; 022 023import org.forgerock.i18n.LocalizableMessage; 024import org.forgerock.i18n.LocalizedIllegalArgumentException; 025import org.forgerock.i18n.slf4j.LocalizedLogger; 026import org.forgerock.opendj.config.server.ConfigException; 027import org.forgerock.opendj.ldap.ByteString; 028import org.forgerock.opendj.ldap.ResultCode; 029import org.forgerock.opendj.ldap.SearchScope; 030import org.forgerock.opendj.ldap.schema.AttributeType; 031import org.opends.server.admin.std.server.VirtualStaticGroupImplementationCfg; 032import org.opends.server.api.Group; 033import org.opends.server.core.DirectoryServer; 034import org.opends.server.core.ServerContext; 035import org.opends.server.types.Attribute; 036import org.forgerock.opendj.ldap.DN; 037import org.opends.server.types.DirectoryException; 038import org.opends.server.types.Entry; 039import org.opends.server.types.InitializationException; 040import org.opends.server.types.MemberList; 041import org.opends.server.types.Modification; 042import org.opends.server.types.ObjectClass; 043import org.opends.server.types.SearchFilter; 044 045import static org.forgerock.util.Reject.*; 046import static org.opends.messages.ExtensionMessages.*; 047import static org.opends.server.config.ConfigConstants.*; 048import static org.opends.server.util.ServerConstants.*; 049 050/** 051 * This class provides a virtual static group implementation, in which 052 * membership is based on membership of another group. 053 */ 054public class VirtualStaticGroup 055 extends Group<VirtualStaticGroupImplementationCfg> 056{ 057 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 058 059 /** The DN of the entry that holds the definition for this group. */ 060 private DN groupEntryDN; 061 062 /** The DN of the target group that will provide membership information. */ 063 private DN targetGroupDN; 064 065 066 067 /** 068 * Creates a new, uninitialized virtual static group instance. This is 069 * intended for internal use only. 070 */ 071 public VirtualStaticGroup() 072 { 073 super(); 074 075 // No initialization is required here. 076 } 077 078 079 080 /** 081 * Creates a new virtual static group instance with the provided information. 082 * 083 * @param groupEntryDN The DN of the entry that holds the definition for 084 * this group. It must not be {@code null}. 085 * @param targetGroupDN The DN of the target group that will provide 086 * membership information. It must not be 087 * {@code null}. 088 */ 089 public VirtualStaticGroup(DN groupEntryDN, DN targetGroupDN) 090 { 091 super(); 092 093 ifNull(groupEntryDN, targetGroupDN); 094 095 this.groupEntryDN = groupEntryDN; 096 this.targetGroupDN = targetGroupDN; 097 } 098 099 100 101 /** {@inheritDoc} */ 102 @Override 103 public void initializeGroupImplementation( 104 VirtualStaticGroupImplementationCfg configuration) 105 throws ConfigException, InitializationException 106 { 107 // No additional initialization is required. 108 } 109 110 111 112 113 /** {@inheritDoc} */ 114 @Override 115 public VirtualStaticGroup newInstance(ServerContext serverContext, Entry groupEntry) 116 throws DirectoryException 117 { 118 ifNull(groupEntry); 119 120 121 // Get the target group DN attribute from the entry, if there is one. 122 DN targetDN = null; 123 AttributeType targetType = DirectoryServer.getAttributeType(ATTR_TARGET_GROUP_DN); 124 for (Attribute a : groupEntry.getAttribute(targetType)) 125 { 126 for (ByteString v : a) 127 { 128 if (targetDN != null) 129 { 130 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_MULTIPLE_TARGETS.get(groupEntry.getName()); 131 throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message); 132 } 133 134 try 135 { 136 targetDN = DN.valueOf(v); 137 } 138 catch (LocalizedIllegalArgumentException e) 139 { 140 logger.traceException(e); 141 142 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_CANNOT_DECODE_TARGET. 143 get(v, groupEntry.getName(), e.getMessageObject()); 144 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, e); 145 } 146 } 147 } 148 149 if (targetDN == null) 150 { 151 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_NO_TARGET.get(groupEntry.getName()); 152 throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message); 153 } 154 155 return new VirtualStaticGroup(groupEntry.getName(), targetDN); 156 } 157 158 159 160 /** {@inheritDoc} */ 161 @Override 162 public SearchFilter getGroupDefinitionFilter() 163 throws DirectoryException 164 { 165 // FIXME -- This needs to exclude enhanced groups once we have support for 166 // them. 167 return SearchFilter.createFilterFromString("(" + ATTR_OBJECTCLASS + "=" + 168 OC_VIRTUAL_STATIC_GROUP + ")"); 169 } 170 171 172 173 /** {@inheritDoc} */ 174 @Override 175 public boolean isGroupDefinition(Entry entry) 176 { 177 ifNull(entry); 178 179 // FIXME -- This needs to exclude enhanced groups once we have support for 180 //them. 181 ObjectClass virtualStaticGroupClass = 182 DirectoryServer.getObjectClass(OC_VIRTUAL_STATIC_GROUP, true); 183 return entry.hasObjectClass(virtualStaticGroupClass); 184 } 185 186 187 188 /** {@inheritDoc} */ 189 @Override 190 public DN getGroupDN() 191 { 192 return groupEntryDN; 193 } 194 195 196 197 /** {@inheritDoc} */ 198 @Override 199 public void setGroupDN(DN groupDN) 200 { 201 groupEntryDN = groupDN; 202 } 203 204 205 206 /** 207 * Retrieves the DN of the target group for this virtual static group. 208 * 209 * @return The DN of the target group for this virtual static group. 210 */ 211 public DN getTargetGroupDN() 212 { 213 return targetGroupDN; 214 } 215 216 217 218 /** {@inheritDoc} */ 219 @Override 220 public boolean supportsNestedGroups() 221 { 222 // Virtual static groups don't support nesting. 223 return false; 224 } 225 226 227 228 /** {@inheritDoc} */ 229 @Override 230 public List<DN> getNestedGroupDNs() 231 { 232 // Virtual static groups don't support nesting. 233 return Collections.<DN>emptyList(); 234 } 235 236 237 238 /** {@inheritDoc} */ 239 @Override 240 public void addNestedGroup(DN nestedGroupDN) 241 throws UnsupportedOperationException, DirectoryException 242 { 243 // Virtual static groups don't support nesting. 244 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_NESTING_NOT_SUPPORTED.get(); 245 throw new UnsupportedOperationException(message.toString()); 246 } 247 248 249 250 /** {@inheritDoc} */ 251 @Override 252 public void removeNestedGroup(DN nestedGroupDN) 253 throws UnsupportedOperationException, DirectoryException 254 { 255 // Virtual static groups don't support nesting. 256 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_NESTING_NOT_SUPPORTED.get(); 257 throw new UnsupportedOperationException(message.toString()); 258 } 259 260 261 262 /** {@inheritDoc} */ 263 @Override 264 public boolean isMember(DN userDN, Set<DN> examinedGroups) 265 throws DirectoryException 266 { 267 if (! examinedGroups.add(getGroupDN())) 268 { 269 return false; 270 } 271 272 Group targetGroup = 273 DirectoryServer.getGroupManager().getGroupInstance(targetGroupDN); 274 if (targetGroup == null) 275 { 276 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP.get(targetGroupDN, groupEntryDN); 277 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); 278 } 279 else if (targetGroup instanceof VirtualStaticGroup) 280 { 281 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL.get(groupEntryDN, targetGroupDN); 282 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 283 } 284 else 285 { 286 return targetGroup.isMember(userDN); 287 } 288 } 289 290 291 292 /** {@inheritDoc} */ 293 @Override 294 public boolean isMember(Entry userEntry, Set<DN> examinedGroups) 295 throws DirectoryException 296 { 297 if (! examinedGroups.add(getGroupDN())) 298 { 299 return false; 300 } 301 302 Group targetGroup = 303 DirectoryServer.getGroupManager().getGroupInstance(targetGroupDN); 304 if (targetGroup == null) 305 { 306 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP.get(targetGroupDN, groupEntryDN); 307 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); 308 } 309 else if (targetGroup instanceof VirtualStaticGroup) 310 { 311 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL.get(groupEntryDN, targetGroupDN); 312 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 313 } 314 else 315 { 316 return targetGroup.isMember(userEntry); 317 } 318 } 319 320 321 322 /** {@inheritDoc} */ 323 @Override 324 public MemberList getMembers() 325 throws DirectoryException 326 { 327 Group targetGroup = 328 DirectoryServer.getGroupManager().getGroupInstance(targetGroupDN); 329 if (targetGroup == null) 330 { 331 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP.get(targetGroupDN, groupEntryDN); 332 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); 333 } 334 else if (targetGroup instanceof VirtualStaticGroup) 335 { 336 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL.get(groupEntryDN, targetGroupDN); 337 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 338 } 339 else 340 { 341 return targetGroup.getMembers(); 342 } 343 } 344 345 346 347 /** {@inheritDoc} */ 348 @Override 349 public MemberList getMembers(DN baseDN, SearchScope scope, 350 SearchFilter filter) 351 throws DirectoryException 352 { 353 Group targetGroup = 354 DirectoryServer.getGroupManager().getGroupInstance(targetGroupDN); 355 if (targetGroup == null) 356 { 357 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP.get(targetGroupDN, groupEntryDN); 358 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); 359 } 360 else if (targetGroup instanceof VirtualStaticGroup) 361 { 362 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL.get(groupEntryDN, targetGroupDN); 363 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 364 } 365 else 366 { 367 return targetGroup.getMembers(baseDN, scope, filter); 368 } 369 } 370 371 372 373 /** {@inheritDoc} */ 374 @Override 375 public boolean mayAlterMemberList() 376 { 377 return false; 378 } 379 380 /** {@inheritDoc} */ 381 @Override 382 public void updateMembers(List<Modification> modifications) 383 throws UnsupportedOperationException, DirectoryException 384 { 385 // Virtual static groups don't support altering the member list. 386 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_ALTERING_MEMBERS_NOT_SUPPORTED.get(groupEntryDN); 387 throw new UnsupportedOperationException(message.toString()); 388 } 389 390 /** {@inheritDoc} */ 391 @Override 392 public void addMember(Entry userEntry) 393 throws UnsupportedOperationException, DirectoryException 394 { 395 // Virtual static groups don't support altering the member list. 396 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_ALTERING_MEMBERS_NOT_SUPPORTED.get(groupEntryDN); 397 throw new UnsupportedOperationException(message.toString()); 398 } 399 400 401 402 /** {@inheritDoc} */ 403 @Override 404 public void removeMember(DN userDN) 405 throws UnsupportedOperationException, DirectoryException 406 { 407 // Virtual static groups don't support altering the member list. 408 LocalizableMessage message = ERR_VIRTUAL_STATIC_GROUP_ALTERING_MEMBERS_NOT_SUPPORTED.get(groupEntryDN); 409 throw new UnsupportedOperationException(message.toString()); 410 } 411 412 413 414 /** {@inheritDoc} */ 415 @Override 416 public void toString(StringBuilder buffer) 417 { 418 buffer.append("VirtualStaticGroup(dn="); 419 buffer.append(groupEntryDN); 420 buffer.append(",targetGroupDN="); 421 buffer.append(targetGroupDN); 422 buffer.append(")"); 423 } 424} 425