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