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