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-2009 Sun Microsystems, Inc.
015 * Portions Copyright 2011-2016 ForgeRock AS.
016 */
017package org.opends.server.extensions;
018
019import java.util.List;
020
021import org.forgerock.i18n.LocalizableMessage;
022import org.forgerock.i18n.slf4j.LocalizedLogger;
023import org.forgerock.opendj.config.server.ConfigException;
024import org.forgerock.opendj.ldap.ByteString;
025import org.forgerock.opendj.ldap.ConditionResult;
026import org.forgerock.opendj.ldap.ResultCode;
027import org.opends.server.admin.server.ConfigurationChangeListener;
028import org.opends.server.admin.std.server.MemberVirtualAttributeCfg;
029import org.opends.server.api.Group;
030import org.opends.server.api.VirtualAttributeProvider;
031import org.opends.server.core.DirectoryServer;
032import org.opends.server.types.Attribute;
033import org.opends.server.types.AttributeBuilder;
034import org.opends.server.types.Attributes;
035import org.opends.server.core.SearchOperation;
036import org.forgerock.opendj.config.server.ConfigChangeResult;
037import org.forgerock.opendj.ldap.DN;
038import org.opends.server.types.Entry;
039import org.opends.server.types.InitializationException;
040import org.opends.server.types.MemberList;
041import org.opends.server.types.MembershipException;
042import org.opends.server.types.VirtualAttributeRule;
043
044/**
045 * This class implements a virtual attribute provider that works in conjunction
046 * with virtual static groups to generate the values for the member or
047 * uniqueMember attribute.
048 */
049public class MemberVirtualAttributeProvider
050       extends VirtualAttributeProvider<MemberVirtualAttributeCfg>
051       implements ConfigurationChangeListener<MemberVirtualAttributeCfg>
052{
053  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
054
055  /** The current configuration for this member virtual attribute. */
056  private MemberVirtualAttributeCfg currentConfig;
057
058
059
060  /**
061   * Creates a new instance of this member virtual attribute provider.
062   */
063  public MemberVirtualAttributeProvider()
064  {
065    super();
066
067    // All initialization should be performed in the
068    // initializeVirtualAttributeProvider method.
069  }
070
071
072
073  /** {@inheritDoc} */
074  @Override
075  public void initializeVirtualAttributeProvider(
076                            MemberVirtualAttributeCfg configuration)
077         throws ConfigException, InitializationException
078  {
079    configuration.addMemberChangeListener(this);
080    currentConfig = configuration;
081  }
082
083
084
085  /** {@inheritDoc} */
086  @Override
087  public boolean isMultiValued()
088  {
089    return true;
090  }
091
092
093
094  /** {@inheritDoc} */
095  @Override
096  public Attribute getValues(Entry entry, VirtualAttributeRule rule)
097  {
098    if (! currentConfig.isAllowRetrievingMembership())
099    {
100      return Attributes.empty(rule.getAttributeType());
101    }
102
103    Group<?> g =
104      DirectoryServer.getGroupManager().getGroupInstance(entry.getName());
105    if (g == null)
106    {
107      return Attributes.empty(rule.getAttributeType());
108    }
109
110    AttributeBuilder builder = new AttributeBuilder(rule.getAttributeType());
111    try
112    {
113      MemberList memberList = g.getMembers();
114      while (memberList.hasMoreMembers())
115      {
116        try
117        {
118          DN memberDN = memberList.nextMemberDN();
119          if (memberDN != null)
120          {
121            builder.add(ByteString.valueOfUtf8(memberDN.toString()));
122          }
123        }
124        catch (MembershipException me)
125        {
126          if (! me.continueIterating())
127          {
128            break;
129          }
130        }
131      }
132    }
133    catch (Exception e)
134    {
135      logger.traceException(e);
136    }
137
138    return builder.toAttribute();
139  }
140
141
142
143  /** {@inheritDoc} */
144  @Override
145  public boolean hasValue(Entry entry, VirtualAttributeRule rule)
146  {
147    Group<?> g =
148      DirectoryServer.getGroupManager().getGroupInstance(entry.getName());
149    if (g == null)
150    {
151      return false;
152    }
153
154    try
155    {
156      MemberList memberList = g.getMembers();
157      while (memberList.hasMoreMembers())
158      {
159        try
160        {
161          DN memberDN = memberList.nextMemberDN();
162          if (memberDN != null)
163          {
164            memberList.close();
165            return true;
166          }
167        }
168        catch (MembershipException me)
169        {
170          if (! me.continueIterating())
171          {
172            break;
173          }
174        }
175      }
176    }
177    catch (Exception e)
178    {
179      logger.traceException(e);
180    }
181
182    return false;
183  }
184
185
186
187  /** {@inheritDoc} */
188  @Override
189  public boolean hasValue(Entry entry, VirtualAttributeRule rule, ByteString value)
190  {
191    Group<?> g =
192      DirectoryServer.getGroupManager().getGroupInstance(entry.getName());
193    if (g == null)
194    {
195      return false;
196    }
197
198    try
199    {
200      return g.isMember(DN.valueOf(value));
201    }
202    catch (Exception e)
203    {
204      logger.traceException(e);
205    }
206
207    return false;
208  }
209
210
211
212  /** {@inheritDoc} */
213  @Override
214  public ConditionResult matchesSubstring(Entry entry,
215                                          VirtualAttributeRule rule,
216                                          ByteString subInitial,
217                                          List<ByteString> subAny,
218                                          ByteString subFinal)
219  {
220    // DNs cannot be used in substring matching.
221    return ConditionResult.UNDEFINED;
222  }
223
224
225
226  /** {@inheritDoc} */
227  @Override
228  public ConditionResult greaterThanOrEqualTo(Entry entry,
229                              VirtualAttributeRule rule,
230                              ByteString value)
231  {
232    // DNs cannot be used in ordering matching.
233    return ConditionResult.UNDEFINED;
234  }
235
236
237
238  /** {@inheritDoc} */
239  @Override
240  public ConditionResult lessThanOrEqualTo(Entry entry,
241                              VirtualAttributeRule rule,
242                              ByteString value)
243  {
244    // DNs cannot be used in ordering matching.
245    return ConditionResult.UNDEFINED;
246  }
247
248
249
250  /** {@inheritDoc} */
251  @Override
252  public ConditionResult approximatelyEqualTo(Entry entry,
253                              VirtualAttributeRule rule,
254                              ByteString value)
255  {
256    // DNs cannot be used in approximate matching.
257    return ConditionResult.UNDEFINED;
258  }
259
260
261
262  /** {@inheritDoc} */
263  @Override
264  public boolean isSearchable(VirtualAttributeRule rule,
265                              SearchOperation searchOperation,
266                              boolean isPreIndexed)
267  {
268    return false;
269  }
270
271
272
273  /** {@inheritDoc} */
274  @Override
275  public void processSearch(VirtualAttributeRule rule,
276                            SearchOperation searchOperation)
277  {
278    searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
279    return;
280  }
281
282
283
284  /** {@inheritDoc} */
285  @Override
286  public boolean isConfigurationChangeAcceptable(
287                      MemberVirtualAttributeCfg configuration,
288                      List<LocalizableMessage> unacceptableReasons)
289  {
290    // The new configuration should always be acceptable.
291    return true;
292  }
293
294
295
296  /** {@inheritDoc} */
297  @Override
298  public ConfigChangeResult applyConfigurationChange(
299                                 MemberVirtualAttributeCfg configuration)
300  {
301    currentConfig = configuration;
302    return new ConfigChangeResult();
303  }
304}
305