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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.extensions; 028 029 030 031 import java.util.Collections; 032 import java.util.List; 033 import java.util.Set; 034 035 import org.opends.messages.Message; 036 import org.opends.server.admin.std.server.VirtualStaticGroupImplementationCfg; 037 import org.opends.server.api.Group; 038 import org.opends.server.core.DirectoryServer; 039 import org.opends.server.config.ConfigException; 040 import org.opends.server.loggers.debug.DebugTracer; 041 import org.opends.server.types.Attribute; 042 import org.opends.server.types.AttributeType; 043 import org.opends.server.types.AttributeValue; 044 import org.opends.server.types.DebugLogLevel; 045 import org.opends.server.types.DirectoryException; 046 import org.opends.server.types.DN; 047 import org.opends.server.types.Entry; 048 import org.opends.server.types.InitializationException; 049 import org.opends.server.types.MemberList; 050 import org.opends.server.types.ObjectClass; 051 import org.opends.server.types.ResultCode; 052 import org.opends.server.types.SearchFilter; 053 import org.opends.server.types.SearchScope; 054 055 import static org.opends.messages.ExtensionMessages.*; 056 import static org.opends.server.config.ConfigConstants.*; 057 import static org.opends.server.loggers.debug.DebugLogger.*; 058 import static org.opends.server.util.ServerConstants.*; 059 import static org.opends.server.util.Validator.*; 060 061 062 063 /** 064 * This class provides a virtual static group implementation, in which 065 * membership is based on membership of another group. 066 */ 067 public class VirtualStaticGroup 068 extends Group<VirtualStaticGroupImplementationCfg> 069 { 070 /** 071 * The tracer object for the debug logger. 072 */ 073 private static final DebugTracer TRACER = getTracer(); 074 075 // The DN of the entry that holds the definition for this group. 076 private DN groupEntryDN; 077 078 // The DN of the target group that will provide membership information. 079 private DN targetGroupDN; 080 081 082 083 /** 084 * Creates a new, uninitialized virtual static group instance. This is 085 * intended for internal use only. 086 */ 087 public VirtualStaticGroup() 088 { 089 super(); 090 091 // No initialization is required here. 092 } 093 094 095 096 /** 097 * Creates a new virtual static group instance with the provided information. 098 * 099 * @param groupEntryDN The DN of the entry that holds the definition for 100 * this group. It must not be {@code null}. 101 * @param targetGroupDN The DN of the target group that will provide 102 * membership information. It must not be 103 * {@code null}. 104 */ 105 public VirtualStaticGroup(DN groupEntryDN, DN targetGroupDN) 106 { 107 super(); 108 109 ensureNotNull(groupEntryDN, targetGroupDN); 110 111 this.groupEntryDN = groupEntryDN; 112 this.targetGroupDN = targetGroupDN; 113 } 114 115 116 117 /** 118 * {@inheritDoc} 119 */ 120 @Override() 121 public void initializeGroupImplementation( 122 VirtualStaticGroupImplementationCfg configuration) 123 throws ConfigException, InitializationException 124 { 125 // No additional initialization is required. 126 } 127 128 129 130 131 /** 132 * {@inheritDoc} 133 */ 134 @Override() 135 public VirtualStaticGroup newInstance(Entry groupEntry) 136 throws DirectoryException 137 { 138 ensureNotNull(groupEntry); 139 140 141 // Get the target group DN attribute from the entry, if there is one. 142 DN targetDN = null; 143 AttributeType targetType = 144 DirectoryServer.getAttributeType(ATTR_TARGET_GROUP_DN, true); 145 List<Attribute> attrList = groupEntry.getAttribute(targetType); 146 if (attrList != null) 147 { 148 for (Attribute a : attrList) 149 { 150 for (AttributeValue v : a.getValues()) 151 { 152 if (targetDN != null) 153 { 154 Message message = ERR_VIRTUAL_STATIC_GROUP_MULTIPLE_TARGETS.get( 155 String.valueOf(groupEntry.getDN())); 156 throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, 157 message); 158 } 159 160 try 161 { 162 targetDN = DN.decode(v.getValue()); 163 } 164 catch (DirectoryException de) 165 { 166 if (debugEnabled()) 167 { 168 TRACER.debugCaught(DebugLogLevel.ERROR, de); 169 } 170 171 Message message = ERR_VIRTUAL_STATIC_GROUP_CANNOT_DECODE_TARGET. 172 get(v.getStringValue(), String.valueOf(groupEntry.getDN()), 173 de.getMessageObject()); 174 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 175 message, de); 176 } 177 } 178 } 179 } 180 181 if (targetDN == null) 182 { 183 Message message = ERR_VIRTUAL_STATIC_GROUP_NO_TARGET.get( 184 String.valueOf(groupEntry.getDN())); 185 throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message); 186 } 187 188 return new VirtualStaticGroup(groupEntry.getDN(), targetDN); 189 } 190 191 192 193 /** 194 * {@inheritDoc} 195 */ 196 @Override() 197 public SearchFilter getGroupDefinitionFilter() 198 throws DirectoryException 199 { 200 // FIXME -- This needs to exclude enhanced groups once we have support for 201 // them. 202 return SearchFilter.createFilterFromString("(" + ATTR_OBJECTCLASS + "=" + 203 OC_VIRTUAL_STATIC_GROUP + ")"); 204 } 205 206 207 208 /** 209 * {@inheritDoc} 210 */ 211 @Override() 212 public boolean isGroupDefinition(Entry entry) 213 { 214 ensureNotNull(entry); 215 216 // FIXME -- This needs to exclude enhanced groups once we have support for 217 //them. 218 ObjectClass virtualStaticGroupClass = 219 DirectoryServer.getObjectClass(OC_VIRTUAL_STATIC_GROUP, true); 220 return entry.hasObjectClass(virtualStaticGroupClass); 221 } 222 223 224 225 /** 226 * {@inheritDoc} 227 */ 228 @Override() 229 public DN getGroupDN() 230 { 231 return groupEntryDN; 232 } 233 234 235 236 /** 237 * Retrieves the DN of the target group for this virtual static group. 238 * 239 * @return The DN of the target group for this virtual static group. 240 */ 241 public DN getTargetGroupDN() 242 { 243 return targetGroupDN; 244 } 245 246 247 248 /** 249 * {@inheritDoc} 250 */ 251 @Override() 252 public boolean supportsNestedGroups() 253 { 254 // Virtual static groups don't support nesting. 255 return false; 256 } 257 258 259 260 /** 261 * {@inheritDoc} 262 */ 263 @Override() 264 public List<DN> getNestedGroupDNs() 265 { 266 // Virtual static groups don't support nesting. 267 return Collections.<DN>emptyList(); 268 } 269 270 271 272 /** 273 * {@inheritDoc} 274 */ 275 @Override() 276 public void addNestedGroup(DN nestedGroupDN) 277 throws UnsupportedOperationException, DirectoryException 278 { 279 // Virtual static groups don't support nesting. 280 Message message = ERR_VIRTUAL_STATIC_GROUP_NESTING_NOT_SUPPORTED.get(); 281 throw new UnsupportedOperationException(message.toString()); 282 } 283 284 285 286 /** 287 * {@inheritDoc} 288 */ 289 @Override() 290 public void removeNestedGroup(DN nestedGroupDN) 291 throws UnsupportedOperationException, DirectoryException 292 { 293 // Virtual static groups don't support nesting. 294 Message message = ERR_VIRTUAL_STATIC_GROUP_NESTING_NOT_SUPPORTED.get(); 295 throw new UnsupportedOperationException(message.toString()); 296 } 297 298 299 300 /** 301 * {@inheritDoc} 302 */ 303 @Override() 304 public boolean isMember(DN userDN, Set<DN> examinedGroups) 305 throws DirectoryException 306 { 307 if (! examinedGroups.add(getGroupDN())) 308 { 309 return false; 310 } 311 312 Group targetGroup = 313 DirectoryServer.getGroupManager().getGroupInstance(targetGroupDN); 314 if (targetGroup == null) 315 { 316 Message message = ERR_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP.get( 317 String.valueOf(targetGroupDN), String.valueOf(groupEntryDN)); 318 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 319 message); 320 } 321 else if (targetGroup instanceof VirtualStaticGroup) 322 { 323 Message message = ERR_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL.get( 324 String.valueOf(groupEntryDN), String.valueOf(targetGroupDN)); 325 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 326 } 327 else 328 { 329 return targetGroup.isMember(userDN); 330 } 331 } 332 333 334 335 /** 336 * {@inheritDoc} 337 */ 338 @Override() 339 public boolean isMember(Entry userEntry, Set<DN> examinedGroups) 340 throws DirectoryException 341 { 342 if (! examinedGroups.add(getGroupDN())) 343 { 344 return false; 345 } 346 347 Group targetGroup = 348 DirectoryServer.getGroupManager().getGroupInstance(targetGroupDN); 349 if (targetGroup == null) 350 { 351 Message message = ERR_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP.get( 352 String.valueOf(targetGroupDN), String.valueOf(groupEntryDN)); 353 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 354 message); 355 } 356 else if (targetGroup instanceof VirtualStaticGroup) 357 { 358 Message message = ERR_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL.get( 359 String.valueOf(groupEntryDN), String.valueOf(targetGroupDN)); 360 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 361 } 362 else 363 { 364 return targetGroup.isMember(userEntry); 365 } 366 } 367 368 369 370 /** 371 * {@inheritDoc} 372 */ 373 @Override() 374 public MemberList getMembers() 375 throws DirectoryException 376 { 377 Group targetGroup = 378 DirectoryServer.getGroupManager().getGroupInstance(targetGroupDN); 379 if (targetGroup == null) 380 { 381 Message message = ERR_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP.get( 382 String.valueOf(targetGroupDN), String.valueOf(groupEntryDN)); 383 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 384 message); 385 } 386 else if (targetGroup instanceof VirtualStaticGroup) 387 { 388 Message message = ERR_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL.get( 389 String.valueOf(groupEntryDN), String.valueOf(targetGroupDN)); 390 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 391 } 392 else 393 { 394 return targetGroup.getMembers(); 395 } 396 } 397 398 399 400 /** 401 * {@inheritDoc} 402 */ 403 @Override() 404 public MemberList getMembers(DN baseDN, SearchScope scope, 405 SearchFilter filter) 406 throws DirectoryException 407 { 408 Group targetGroup = 409 DirectoryServer.getGroupManager().getGroupInstance(targetGroupDN); 410 if (targetGroup == null) 411 { 412 Message message = ERR_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP.get( 413 String.valueOf(targetGroupDN), String.valueOf(groupEntryDN)); 414 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 415 message); 416 } 417 else if (targetGroup instanceof VirtualStaticGroup) 418 { 419 Message message = ERR_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL.get( 420 String.valueOf(groupEntryDN), String.valueOf(targetGroupDN)); 421 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 422 } 423 else 424 { 425 return targetGroup.getMembers(baseDN, scope, filter); 426 } 427 } 428 429 430 431 /** 432 * {@inheritDoc} 433 */ 434 @Override() 435 public boolean mayAlterMemberList() 436 { 437 return false; 438 } 439 440 441 442 /** 443 * {@inheritDoc} 444 */ 445 @Override() 446 public void addMember(Entry userEntry) 447 throws UnsupportedOperationException, DirectoryException 448 { 449 // Virtual static groups don't support altering the member list. 450 Message message = ERR_VIRTUAL_STATIC_GROUP_ALTERING_MEMBERS_NOT_SUPPORTED. 451 get(String.valueOf(groupEntryDN)); 452 throw new UnsupportedOperationException(message.toString()); 453 } 454 455 456 457 /** 458 * {@inheritDoc} 459 */ 460 @Override() 461 public void removeMember(DN userDN) 462 throws UnsupportedOperationException, DirectoryException 463 { 464 // Virtual static groups don't support altering the member list. 465 Message message = ERR_VIRTUAL_STATIC_GROUP_ALTERING_MEMBERS_NOT_SUPPORTED. 466 get(String.valueOf(groupEntryDN)); 467 throw new UnsupportedOperationException(message.toString()); 468 } 469 470 471 472 /** 473 * {@inheritDoc} 474 */ 475 @Override() 476 public void toString(StringBuilder buffer) 477 { 478 buffer.append("VirtualStaticGroup(dn="); 479 buffer.append(groupEntryDN); 480 buffer.append(",targetGroupDN="); 481 buffer.append(targetGroupDN); 482 buffer.append(")"); 483 } 484 } 485