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