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 2014-2016 ForgeRock AS. 016 */ 017package org.opends.server.extensions; 018 019import org.forgerock.i18n.LocalizableMessage; 020import org.forgerock.i18n.slf4j.LocalizedLogger; 021import org.forgerock.opendj.ldap.ResultCode; 022import org.forgerock.opendj.ldap.SearchScope; 023import org.opends.server.api.DirectoryThread; 024import org.opends.server.core.DirectoryServer; 025import org.opends.server.protocols.internal.InternalClientConnection; 026import org.opends.server.protocols.internal.InternalSearchListener; 027import org.opends.server.protocols.internal.InternalSearchOperation; 028import org.opends.server.protocols.internal.SearchRequest; 029import static org.opends.server.protocols.internal.Requests.*; 030import org.forgerock.opendj.ldap.DN; 031import org.opends.server.types.DirectoryException; 032import org.opends.server.types.LDAPURL; 033import org.opends.server.types.MembershipException; 034import org.opends.server.types.SearchFilter; 035import org.opends.server.types.SearchResultEntry; 036import org.opends.server.types.SearchResultReference; 037 038import static org.opends.messages.ExtensionMessages.*; 039import static org.opends.server.protocols.internal.InternalClientConnection.*; 040 041/** 042 * This class implements a Directory Server thread that will be used to perform 043 * a background search to retrieve all of the members of a dynamic group. 044 * <BR><BR> 045 */ 046public class DynamicGroupSearchThread 047// FIXME -- Would it be better to implement this class using an Executor 048// rather than always creating a custom thread? 049 extends DirectoryThread 050 implements InternalSearchListener 051{ 052 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 053 054 /** The set of base DNs for the search requests. */ 055 private final DN[] baseDNs; 056 057 /** The member list with which this search thread is associated. */ 058 private final DynamicGroupMemberList memberList; 059 060 /** A counter used to keep track of which search is currently in progress. */ 061 private int searchCounter; 062 063 /** The set of member URLs for determining whether entries match the criteria. */ 064 private final LDAPURL[][] memberURLs; 065 066 /** The set of search filters for the search requests. */ 067 private final SearchFilter[] searchFilters; 068 069 /** 070 * Creates a new dynamic group search thread that is associated with the 071 * provided member list and that will perform the search using the provided 072 * information. 073 * 074 * @param memberList The dynamic group member list with which this thread is 075 * associated. 076 * @param baseDNs The set of base DNs to use for the search requests. 077 * @param filters The set of search filters to use for the search 078 * requests. 079 * @param memberURLs The set of member URLs to use when determining if 080 * entries match the necessary group criteria. 081 */ 082 public DynamicGroupSearchThread(DynamicGroupMemberList memberList, 083 DN[] baseDNs, SearchFilter[] filters, 084 LDAPURL[][] memberURLs) 085 { 086 super("Dynamic Group Search Thread " + memberList.getDynamicGroupDN()); 087 088 this.memberList = memberList; 089 this.baseDNs = baseDNs; 090 this.searchFilters = filters; 091 this.memberURLs = memberURLs; 092 093 searchCounter = 0; 094 } 095 096 /** Performs the set of searches and provides the results to the associated member list. */ 097 @Override 098 public void run() 099 { 100 InternalClientConnection conn = getRootConnection(); 101 for (searchCounter = 0; searchCounter < baseDNs.length; searchCounter++) 102 { 103 DN baseDN = baseDNs[searchCounter]; 104 SearchFilter filter = searchFilters[searchCounter]; 105 // Include all the user attributes along with the ismemberof. 106 final SearchRequest request = newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, filter) 107 .addAttribute("*", "ismemberof"); 108 InternalSearchOperation searchOperation = conn.processSearch(request, this); 109 110 ResultCode resultCode = searchOperation.getResultCode(); 111 if (resultCode != ResultCode.SUCCESS) 112 { 113 if (resultCode == ResultCode.NO_SUCH_OBJECT) 114 { 115 logger.warn(WARN_DYNAMICGROUP_NONEXISTENT_BASE_DN, baseDN, 116 memberList.getDynamicGroupDN()); 117 continue; 118 } 119 else 120 { 121 LocalizableMessage message = 122 ERR_DYNAMICGROUP_INTERNAL_SEARCH_FAILED.get( 123 baseDN, 124 filter, 125 memberList.getDynamicGroupDN(), 126 resultCode, 127 searchOperation.getErrorMessage()); 128 if (! memberList.addResult( 129 new MembershipException(message, true))) 130 { 131 memberList.setSearchesCompleted(); 132 return; 133 } 134 } 135 } 136 } 137 138 memberList.setSearchesCompleted(); 139 } 140 141 @Override 142 public void handleInternalSearchEntry(InternalSearchOperation searchOperation, 143 SearchResultEntry searchEntry) 144 throws DirectoryException 145 { 146 for (LDAPURL url : memberURLs[searchCounter]) 147 { 148 if (url.matchesEntry(searchEntry)) 149 { 150 if (! memberList.addResult(searchEntry)) 151 { 152 LocalizableMessage message = ERR_DYNAMICGROUP_CANNOT_RETURN_ENTRY. 153 get(searchEntry.getName(), memberList.getDynamicGroupDN()); 154 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); 155 } 156 157 return; 158 } 159 } 160 } 161 162 @Override 163 public void handleInternalSearchReference( 164 InternalSearchOperation searchOperation, 165 SearchResultReference searchReference) 166 { 167 // No implementation required. 168 } 169}