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