opends/src/server/org/opends/server/api/ClientConnection.java
@@ -80,6 +80,10 @@ // until the bind completes. private boolean bindInProgress; // Indicates whether any necessary finalization work has been done // for this client connection. private boolean finalized; // The size limit for use with this client connection. private int sizeLimit; @@ -122,6 +126,79 @@ sizeLimit = DirectoryServer.getSizeLimit(); timeLimit = DirectoryServer.getTimeLimit(); lookthroughLimit = DirectoryServer.getLookthroughLimit(); finalized = false; } /** * Performs any internal cleanup that may be necessary when this * client connection is disconnected, or if not on disconnec, then * ultimately whenever it is reaped by the garbage collector. In * this case, it will be used to ensure that the connection is * deregistered with the {@code AuthenticatedUsers} manager, and * will then invoke the {@code finalizeClientConnection} method. */ protected final void finalizeConnectionInternal() { if (finalized) { return; } finalized = true; // Deregister with the set of authenticated users. Entry authNEntry = authenticationInfo.getAuthenticationEntry(); Entry authZEntry = authenticationInfo.getAuthorizationEntry(); if (authNEntry != null) { if ((authZEntry == null) || authZEntry.getDN().equals(authNEntry.getDN())) { DirectoryServer.getAuthenticatedUsers().remove( authNEntry.getDN(), this); } else { DirectoryServer.getAuthenticatedUsers().remove( authNEntry.getDN(), this); DirectoryServer.getAuthenticatedUsers().remove( authZEntry.getDN(), this); } } else if (authZEntry != null) { DirectoryServer.getAuthenticatedUsers().remove( authZEntry.getDN(), this); } try { finalizeClientConnection(); } catch (Exception e) { assert debugException(CLASS_NAME, "finalizeConnectionInternal", e); } } /** * Performs any cleanup work that may be necessary when this client * connection is terminated. By default, no action is taken. * <BR><BR> * If possible, this method will be invoked when the client * connection is disconnected. If it isn't invoked at that time, * then it will be called when the client connection object is * finalized by the garbage collector. */ protected void finalizeClientConnection() { // No implementation is required by default. } @@ -430,9 +507,9 @@ * associated with the provided message * ID. */ public void disconnect(DisconnectReason disconnectReason, boolean sendNotification, int messageID, Object... arguments) public final void disconnect(DisconnectReason disconnectReason, boolean sendNotification, int messageID, Object... arguments) { assert debugEnter(CLASS_NAME, "disconnect", String.valueOf(disconnectReason), @@ -456,6 +533,9 @@ * operation processing (e.g., within a plugin or other extension), * the <CODE>disconnectClient</CODE> method within that operation * should be called rather than invoking this method directly. * <BR><BR> * All subclasses must invoke the {@code finalizeConnectionInternal} * method during the course of processing this method. * * @param disconnectReason The disconnect reason that provides the * generic cause for the disconnect. @@ -733,6 +813,36 @@ assert debugEnter(CLASS_NAME, "setAuthenticationInfo", String.valueOf(authenticationInfo)); if (this.authenticationInfo != null) { Entry authNEntry = this.authenticationInfo.getAuthenticationEntry(); Entry authZEntry = this.authenticationInfo.getAuthorizationEntry(); if (authNEntry != null) { if ((authZEntry == null) || authZEntry.getDN().equals(authNEntry.getDN())) { DirectoryServer.getAuthenticatedUsers().remove( authNEntry.getDN(), this); } else { DirectoryServer.getAuthenticatedUsers().remove( authNEntry.getDN(), this); DirectoryServer.getAuthenticatedUsers().remove( authZEntry.getDN(), this); } } else if (authZEntry != null) { DirectoryServer.getAuthenticatedUsers().remove( authZEntry.getDN(), this); } } if (authenticationInfo == null) { this.authenticationInfo = new AuthenticationInfo(); @@ -740,6 +850,76 @@ else { this.authenticationInfo = authenticationInfo; Entry authNEntry = authenticationInfo.getAuthenticationEntry(); Entry authZEntry = authenticationInfo.getAuthorizationEntry(); if (authNEntry != null) { if ((authZEntry == null) || authZEntry.getDN().equals(authNEntry.getDN())) { DirectoryServer.getAuthenticatedUsers().put( authNEntry.getDN(), this); } else { DirectoryServer.getAuthenticatedUsers().put( authNEntry.getDN(), this); DirectoryServer.getAuthenticatedUsers().put( authZEntry.getDN(), this); } } else if (authZEntry != null) { DirectoryServer.getAuthenticatedUsers().put( authZEntry.getDN(), this); } } } /** * Updates the cached entry associated with either the * authentication and/or authorization identity with the provided * version. * * @param oldEntry The user entry currently serving as the * authentication and/or authorization identity. * @param newEntry The updated entry that should replace the * existing entry. It may optionally have a * different DN than the old entry. */ public void updateAuthenticationInfo(Entry oldEntry, Entry newEntry) { assert debugEnter(CLASS_NAME, "updateAuthenticationInfo", String.valueOf(oldEntry), String.valueOf(newEntry)); Entry authNEntry = authenticationInfo.getAuthenticationEntry(); Entry authZEntry = authenticationInfo.getAuthorizationEntry(); if ((authNEntry != null) && authNEntry.getDN().equals(oldEntry.getDN())) { if ((authZEntry == null) || (! authZEntry.getDN().equals(authNEntry.getDN()))) { authenticationInfo = authenticationInfo.duplicate(newEntry, authZEntry); } else { authenticationInfo = authenticationInfo.duplicate(newEntry, newEntry); } } else if ((authZEntry != null) && (authZEntry.getDN().equals(oldEntry.getDN()))) { authenticationInfo = authenticationInfo.duplicate(authNEntry, newEntry); } } @@ -1053,5 +1233,20 @@ * appended. */ public abstract void toString(StringBuilder buffer); /** * Performs any work that may be needed before the JVM invokes * garbage collection for this object. In this case, it makes sure * to deregister with the Directory Server as a change notification * listener. If a subclass wishes to perform custom finalization * processing, then it should override this method and make sure to * invoke {@code super.finalize} as its first call. */ protected void finalize() { finalizeConnectionInternal(); } } opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java
@@ -327,27 +327,37 @@ /** * Retrieves the authorization DN for this proxied authorization V1 control * only if it references a valid Directory Server user entry. It will also * perform any necessary password policy checks to ensure that the specified * user account is suitable for use in performing this processing. * Retrieves the authorization entry for this proxied authorization V1 * control. It will also perform any necessary password policy checks to * ensure that the associated user account is suitable for use in performing * this processing. * * @return The validated authorization DN for this proxied authorization V1 * control. * @return The entry for user specified as the authorization identity in this * proxied authorization V1 control, or {@code null} if the * authorization DN is the null DN. * * @throws DirectoryException If an error occurs while attempting to make * the determination, or if the target user does * not exist. * @throws DirectoryException If the target user does not exist or is not * available for use, or if a problem occurs * while making the determination. */ public DN getValidatedAuthorizationDN() public Entry getAuthorizationEntry() throws DirectoryException { assert debugEnter(CLASS_NAME, "getValidatedAuthorizationDN"); assert debugEnter(CLASS_NAME, "getAuthorizationEntry"); DN authzDN = getAuthorizationDN(); if (authzDN.isNullDN()) { return authzDN; return null; } // See if the authorization DN is one of the alternate bind DNs for one of // the root users and if so then map it accordingly. DN actualDN = DirectoryServer.getActualRootBindDN(authzDN); if (actualDN != null) { authzDN = actualDN; } @@ -400,7 +410,7 @@ // If we've made it here, then the user is acceptable. return authzDN; return userEntry; } finally { opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java
@@ -233,19 +233,20 @@ /** * Retrieves the authorization DN for this proxied authorization V2 control * only if it references a valid Directory Server user entry. It will also * perform any necessary password policy checks to ensure that the specified * user account is suitable for use in performing this processing. * Retrieves the authorization entry for this proxied authorization V2 * control. It will also perform any necessary password policy checks to * ensure that the associated user account is suitable for use in performing * this processing. * * @return The validated authorization DN for this proxied authorization V2 * control. * @return The entry for user specified as the authorization identity in this * proxied authorization V1 control, or {@code null} if the * authorization DN is the null DN. * * @throws DirectoryException If an error occurs while attempting to make * the determination, or if the target user does * not exist. * @throws DirectoryException If the target user does not exist or is not * available for use, or if a problem occurs * while making the determination. */ public DN getValidatedAuthorizationDN() public Entry getAuthorizationEntry() throws DirectoryException { assert debugEnter(CLASS_NAME, "getValidatedAuthorizationDN"); @@ -254,7 +255,7 @@ // Check for a zero-length value, which would be for an anonymous user. if (authorizationID.value().length == 0) { return DN.nullDN(); return null; } @@ -269,10 +270,18 @@ DN authzDN = DN.decode(authzID.substring(3)); if (authzDN.isNullDN()) { return authzDN; return null; } else { // See if the authorization DN is one of the alternate bind DNs for one // of the root users and if so then map it accordingly. DN actualDN = DirectoryServer.getActualRootBindDN(authzDN); if (actualDN != null) { authzDN = actualDN; } Lock entryLock = null; for (int i=0; i < 3; i++) { @@ -321,7 +330,7 @@ // If we've made it here, then the user is acceptable. return authzDN; return userEntry; } finally { @@ -334,7 +343,7 @@ // If the authorization ID is just "u:", then it's an anonymous request. if (lowerAuthzID.length() == 2) { return DN.nullDN(); return null; } @@ -360,8 +369,6 @@ } else { DN authzDN = userEntry.getDN(); // FIXME -- We should provide some mechanism for enabling debug // processing. PasswordPolicyState pwpState = @@ -373,12 +380,12 @@ pwpState.isPasswordExpired()) { int msgID = MSGID_PROXYAUTH2_UNUSABLE_ACCOUNT; String message = getMessage(msgID, String.valueOf(authzDN)); String message = getMessage(msgID, String.valueOf(userEntry.getDN())); throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message, msgID); } return authzDN; return userEntry; } } else opends/src/server/org/opends/server/core/AddOperation.java
@@ -1783,10 +1783,10 @@ } DN authzDN; Entry authorizationEntry; try { authzDN = proxyControl.getValidatedAuthorizationDN(); authorizationEntry = proxyControl.getAuthorizationEntry(); } catch (DirectoryException de) { @@ -1801,7 +1801,7 @@ // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationDN(authzDN); setAuthorizationEntry(authorizationEntry); } else if (oid.equals(OID_PROXIED_AUTH_V2)) { @@ -1828,10 +1828,10 @@ } DN authzDN; Entry authorizationEntry; try { authzDN = proxyControl.getValidatedAuthorizationDN(); authorizationEntry = proxyControl.getAuthorizationEntry(); } catch (DirectoryException de) { @@ -1846,7 +1846,7 @@ // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationDN(authzDN); setAuthorizationEntry(authorizationEntry); } // NYI -- Add support for additional controls. opends/src/server/org/opends/server/core/AuthenticatedUsers.java
New file @@ -0,0 +1,265 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2007 Sun Microsystems, Inc. */ package org.opends.server.core; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import org.opends.server.api.ChangeNotificationListener; import org.opends.server.api.ClientConnection; import org.opends.server.types.DisconnectReason; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.operation.PostResponseAddOperation; import org.opends.server.types.operation.PostResponseDeleteOperation; import org.opends.server.types.operation.PostResponseModifyOperation; import org.opends.server.types.operation.PostResponseModifyDNOperation; import static org.opends.server.loggers.Debug.*; import static org.opends.server.messages.CoreMessages.*; import static org.opends.server.messages.MessageHandler.*; /** * This class provides a data structure which maps an authenticated user DN to * the set of client connections authenticated as that user. Note that a single * client connection may be registered with two different user DNs if the client * has different authentication and authorization identities. * <BR><BR> * This class also provides a mechanism for detecting changes to authenticated * user entries and notifying the corresponding client connections so that they * can update their cached versions. */ public class AuthenticatedUsers implements ChangeNotificationListener { /** * The fully-qualified name of this class for debugging purposes. */ private static final String CLASS_NAME = "org.opends.server.core.AuthenticatedUsers"; // The mapping between authenticated user DNs and the associated client // connection objects. private ConcurrentHashMap<DN,CopyOnWriteArraySet<ClientConnection>> userMap; /** * Creates a new instance of this authenticated users object. */ public AuthenticatedUsers() { assert debugConstructor(CLASS_NAME); userMap = new ConcurrentHashMap<DN,CopyOnWriteArraySet<ClientConnection>>(); DirectoryServer.registerChangeNotificationListener(this); } /** * Registers the provided user DN and client connection with this object. * * @param userDN The DN of the user associated with the provided * client connection. * @param clientConnection The client connection over which the user is * authenticated. */ public synchronized void put(DN userDN, ClientConnection clientConnection) { assert debugEnter(CLASS_NAME, "put", String.valueOf(userDN), String.valueOf(clientConnection)); CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.get(userDN); if (connectionSet == null) { connectionSet = new CopyOnWriteArraySet<ClientConnection>(); connectionSet.add(clientConnection); userMap.put(userDN, connectionSet); } else { connectionSet.add(clientConnection); } } /** * Deregisters the provided user DN and client connection with this object. * * @param userDN The DN of the user associated with the provided * client connection. * @param clientConnection The client connection over which the user is * authenticated. */ public synchronized void remove(DN userDN, ClientConnection clientConnection) { assert debugEnter(CLASS_NAME, "put", String.valueOf(userDN), String.valueOf(clientConnection)); CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.get(userDN); if (connectionSet != null) { connectionSet.remove(clientConnection); if (connectionSet.isEmpty()) { userMap.remove(userDN); } } } /** * Performs any processing that may be required after an add * operation. * * @param addOperation The add operation that was performed in the * server. * @param entry The entry that was added to the server. */ public void handleAddOperation( PostResponseAddOperation addOperation, Entry entry) { // No implementation is required for add operations, since a connection // can't be authenticated as a user that doesn't exist yet. } /** * Performs any processing that may be required after a delete * operation. * * @param deleteOperation The delete operation that was performed * in the server. * @param entry The entry that was removed from the * server. */ public void handleDeleteOperation( PostResponseDeleteOperation deleteOperation, Entry entry) { // Identify any client connections that may be authenticated or // authorized as the user whose entry has been deleted and terminate them. CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.remove(entry.getDN()); if (connectionSet != null) { for (ClientConnection conn : connectionSet) { int msgID = MSGID_CLIENTCONNECTION_DISCONNECT_DUE_TO_DELETE; String message = getMessage(msgID, String.valueOf(entry.getDN())); conn.disconnect(DisconnectReason.OTHER, true, message, msgID); } } } /** * Performs any processing that may be required after a modify * operation. * * @param modifyOperation The modify operation that was performed * in the server. * @param oldEntry The entry before it was updated. * @param newEntry The entry after it was updated. */ public void handleModifyOperation( PostResponseModifyOperation modifyOperation, Entry oldEntry, Entry newEntry) { // Identify any client connections that may be authenticated or authorized // as the user whose entry has been modified and update them with the latest // version of the entry. CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.get(oldEntry.getDN()); if (connectionSet != null) { for (ClientConnection conn : connectionSet) { conn.updateAuthenticationInfo(oldEntry, newEntry); } } } /** * Performs any processing that may be required after a modify DN * operation. * * @param modifyDNOperation The modify DN operation that was * performed in the server. * @param oldEntry The entry before it was updated. * @param newEntry The entry after it was updated. */ public void handleModifyDNOperation( PostResponseModifyDNOperation modifyDNOperation, Entry oldEntry, Entry newEntry) { // Identify any client connections that may be authenticated or authorized // as the user whose entry has been modified and update them with the latest // version of the entry. CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.remove(oldEntry.getDN()); if (connectionSet != null) { synchronized (this) { CopyOnWriteArraySet<ClientConnection> existingNewSet = userMap.get(newEntry.getDN()); if (existingNewSet == null) { userMap.put(newEntry.getDN(), connectionSet); } else { existingNewSet.addAll(connectionSet); } } for (ClientConnection conn : connectionSet) { conn.updateAuthenticationInfo(oldEntry, newEntry); } } } } opends/src/server/org/opends/server/core/BindOperation.java
@@ -147,6 +147,10 @@ // The DN of the user entry that is attempting to authenticate. private DN userEntryDN; // The entry of the user that successfully authenticated during processing of // this bind operation. private Entry authenticatedUserEntry; // The DN of the user as whom a SASL authentication was attempted (regardless // of whether the authentication was successful) for the purpose of updating // password policy state information. @@ -244,6 +248,7 @@ responseControls = new ArrayList<Control>(0); authFailureID = 0; authFailureReason = null; authenticatedUserEntry = null; saslAuthUserEntry = null; isFirstWarning = false; isGraceLogin = false; @@ -304,12 +309,13 @@ this.rawBindDN = rawBindDN; } bindDN = null; userEntryDN = null; responseControls = new ArrayList<Control>(0); authFailureID = 0; authFailureReason = null; saslAuthUserEntry = null; bindDN = null; userEntryDN = null; responseControls = new ArrayList<Control>(0); authFailureID = 0; authFailureReason = null; authenticatedUserEntry = null; saslAuthUserEntry = null; } @@ -369,6 +375,7 @@ responseControls = new ArrayList<Control>(0); authFailureID = 0; authFailureReason = null; authenticatedUserEntry = null; saslAuthUserEntry = null; isFirstWarning = false; isGraceLogin = false; @@ -429,11 +436,12 @@ rawBindDN = new ASN1OctetString(bindDN.toString()); } responseControls = new ArrayList<Control>(0); authFailureID = 0; authFailureReason = null; saslAuthUserEntry = null; userEntryDN = null; responseControls = new ArrayList<Control>(0); authFailureID = 0; authFailureReason = null; authenticatedUserEntry = null; saslAuthUserEntry = null; userEntryDN = null; } @@ -1481,8 +1489,8 @@ setResultCode(ResultCode.SUCCESS); boolean isRoot = DirectoryServer.isRootDN(userEntry.getDN()); authInfo = new AuthenticationInfo(userEntry.getDN(), simplePassword, isRoot); authInfo = new AuthenticationInfo(userEntry, simplePassword, isRoot); // See if the user's entry contains a custom size limit. @@ -2220,6 +2228,7 @@ // Update the authentication information for the user. if ((getResultCode() == ResultCode.SUCCESS) && (authInfo != null)) { authenticatedUserEntry = authInfo.getAuthenticationEntry(); clientConnection.setAuthenticationInfo(authInfo); clientConnection.setSizeLimit(sizeLimit); clientConnection.setTimeLimit(timeLimit); opends/src/server/org/opends/server/core/CompareOperation.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.core; @@ -837,10 +837,10 @@ } DN authzDN; Entry authorizationEntry; try { authzDN = proxyControl.getValidatedAuthorizationDN(); authorizationEntry = proxyControl.getAuthorizationEntry(); } catch (DirectoryException de) { @@ -855,7 +855,7 @@ // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationDN(authzDN); setAuthorizationEntry(authorizationEntry); } else if (oid.equals(OID_PROXIED_AUTH_V2)) { @@ -882,10 +882,10 @@ } DN authzDN; Entry authorizationEntry; try { authzDN = proxyControl.getValidatedAuthorizationDN(); authorizationEntry = proxyControl.getAuthorizationEntry(); } catch (DirectoryException de) { @@ -900,7 +900,7 @@ // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationDN(authzDN); setAuthorizationEntry(authorizationEntry); } // NYI -- Add support for additional controls. opends/src/server/org/opends/server/core/DeleteOperation.java
@@ -816,10 +816,10 @@ } DN authzDN; Entry authorizationEntry; try { authzDN = proxyControl.getValidatedAuthorizationDN(); authorizationEntry = proxyControl.getAuthorizationEntry(); } catch (DirectoryException de) { @@ -834,7 +834,7 @@ // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationDN(authzDN); setAuthorizationEntry(authorizationEntry); } else if (oid.equals(OID_PROXIED_AUTH_V2)) { @@ -861,10 +861,10 @@ } DN authzDN; Entry authorizationEntry; try { authzDN = proxyControl.getValidatedAuthorizationDN(); authorizationEntry = proxyControl.getAuthorizationEntry(); } catch (DirectoryException de) { @@ -879,7 +879,7 @@ // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationDN(authzDN); setAuthorizationEntry(authorizationEntry); } // NYI -- Add support for additional controls. opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -224,6 +224,9 @@ // The attribute type used to reference the "objectclass" attribute. private AttributeType objectClassAttributeType; // The authenticated users manager for the server. private AuthenticatedUsers authenticatedUsers; // The configuration manager that will handle the server backends. private BackendConfigManager backendConfigManager; @@ -649,6 +652,7 @@ new ConcurrentHashMap<String,ExtendedOperationHandler>(); directoryServer.saslMechanismHandlers = new ConcurrentHashMap<String,SASLMechanismHandler>(); directoryServer.authenticatedUsers = new AuthenticatedUsers(); } @@ -1761,6 +1765,20 @@ /** * Retrieves the authenticated users manager for the Directory Server. * * @return The authenticated users manager for the Directory Server. */ public static AuthenticatedUsers getAuthenticatedUsers() { assert debugEnter(CLASS_NAME, "getAuthenticatedUsers"); return directoryServer.authenticatedUsers; } /** * Initializes the crypto manager for the Directory Server. * * @throws ConfigException If a configuration problem is identified while opends/src/server/org/opends/server/core/ModifyDNOperation.java
@@ -1307,10 +1307,10 @@ } DN authzDN; Entry authorizationEntry; try { authzDN = proxyControl.getValidatedAuthorizationDN(); authorizationEntry = proxyControl.getAuthorizationEntry(); } catch (DirectoryException de) { @@ -1325,7 +1325,7 @@ // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationDN(authzDN); setAuthorizationEntry(authorizationEntry); } else if (oid.equals(OID_PROXIED_AUTH_V2)) { @@ -1352,10 +1352,10 @@ } DN authzDN; Entry authorizationEntry; try { authzDN = proxyControl.getValidatedAuthorizationDN(); authorizationEntry = proxyControl.getAuthorizationEntry(); } catch (DirectoryException de) { @@ -1370,7 +1370,7 @@ // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationDN(authzDN); setAuthorizationEntry(authorizationEntry); } // NYI -- Add support for additional controls. opends/src/server/org/opends/server/core/ModifyOperation.java
@@ -1109,10 +1109,10 @@ } DN authzDN; Entry authorizationEntry; try { authzDN = proxyControl.getValidatedAuthorizationDN(); authorizationEntry = proxyControl.getAuthorizationEntry(); } catch (DirectoryException de) { @@ -1127,7 +1127,7 @@ // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationDN(authzDN); setAuthorizationEntry(authorizationEntry); } else if (oid.equals(OID_PROXIED_AUTH_V2)) { @@ -1154,10 +1154,10 @@ } DN authzDN; Entry authorizationEntry; try { authzDN = proxyControl.getValidatedAuthorizationDN(); authorizationEntry = proxyControl.getAuthorizationEntry(); } catch (DirectoryException de) { @@ -1172,7 +1172,7 @@ // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationDN(authzDN); setAuthorizationEntry(authorizationEntry); } // NYI -- Add support for additional controls. opends/src/server/org/opends/server/core/Operation.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.core; @@ -34,13 +34,13 @@ import java.util.Map; import org.opends.server.api.ClientConnection; import org.opends.server.types.AuthenticationInfo; import org.opends.server.types.CancelRequest; import org.opends.server.types.CancelResult; import org.opends.server.types.Control; import org.opends.server.types.DisconnectReason; import org.opends.server.types.DN; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; import org.opends.server.types.OperationType; import org.opends.server.types.ResultCode; import org.opends.server.types.operation.PostOperationOperation; @@ -111,12 +111,12 @@ // The cancel result for this operation. private CancelResult cancelResult; // The authorization DN for this operation. private DN authorizationDN; // The matched DN for this operation. private DN matchedDN; // The entry for the authorization identify for this operation. private Entry authorizationEntry; // A set of attachments associated with this operation that might be used by // various components during its processing. private Map<String,Object> attachments; @@ -180,8 +180,8 @@ cancelResult = null; isInternalOperation = false; isSynchronizationOperation = false; authorizationDN = clientConnection.getAuthenticationInfo().getAuthorizationDN(); authorizationEntry = clientConnection.getAuthenticationInfo().getAuthorizationEntry(); } @@ -732,6 +732,48 @@ /** * Retrieves the entry for the user that should be considered the * authorization identity for this operation. In many cases, it will be the * same as the authorization entry for the underlying client connection, or * {@code null} if no authentication has been performed on that connection. * However, it may be some other value if special processing has been * requested (e.g., the operation included a proxied authorization control). * This method should not be called by pre-parse plugins because the correct * value may not yet have been determined. * * @return The entry for the user that should be considered the authorization * identity for this operation, or {@code null} if the authorization * identity should be the unauthenticated user. */ public final Entry getAuthorizationEntry() { assert debugEnter(CLASS_NAME, "getAuthorizationEntry"); return authorizationEntry; } /** * Provides the entry for the user that should be considered the authorization * identity for this operation. This must not be called from within a plugin. * * @param authorizationEntry The entry for the user that should be * considered the authorization identity for this * operation, or {@code null} if it should be the * unauthenticated user. */ public final void setAuthorizationEntry(Entry authorizationEntry) { assert debugEnter(CLASS_NAME, "setAuthorizationEntry", String.valueOf(authorizationEntry)); this.authorizationEntry = authorizationEntry; } /** * Retrieves the authorization DN for this operation. In many cases, it will * be the same as the DN of the authenticated user for the underlying * connection, or the null DN if no authentication has been performed on that @@ -740,51 +782,26 @@ * control). This method should not be called by pre-parse plugins because * the correct value may not have yet been determined. * * @return The authorization DN for this operation. * @return The authorization DN for this operation, or the null DN if it * should be the unauthenticated user.. */ public final DN getAuthorizationDN() { assert debugEnter(CLASS_NAME, "getAuthorizationDN"); if (authorizationDN == null) if (authorizationEntry == null) { AuthenticationInfo authInfo = clientConnection.getAuthenticationInfo(); if (authInfo == null) { return DN.nullDN(); } else { return authInfo.getAuthorizationDN(); } return DN.nullDN(); } else { return authorizationDN; return authorizationEntry.getDN(); } } /** * Specifies the authorization DN for this operation. This method may not be * called from within a plugin. * * @param authorizationDN The authorization DN for this operation, or * <CODE>null</CODE> if it should use the DN of the * authenticated user. */ public final void setAuthorizationDN(DN authorizationDN) { assert debugEnter(CLASS_NAME, "setAuthorizationDN", String.valueOf(authorizationDN)); this.authorizationDN = authorizationDN; } /** * Retrieves the set of attachments defined for this operation, as a mapping * between the attachment name and the associated object. * opends/src/server/org/opends/server/core/SearchOperation.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.core; @@ -1783,25 +1783,25 @@ } DN authzDN; try { authzDN = proxyControl.getValidatedAuthorizationDN(); } catch (DirectoryException de) { assert debugException(CLASS_NAME, "run", de); Entry authorizationEntry; try { authorizationEntry = proxyControl.getAuthorizationEntry(); } catch (DirectoryException de) { assert debugException(CLASS_NAME, "run", de); setResultCode(de.getResultCode()); appendErrorMessage(de.getErrorMessage()); setResultCode(de.getResultCode()); appendErrorMessage(de.getErrorMessage()); break searchProcessing; } break searchProcessing; } // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationDN(authzDN); // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationEntry(authorizationEntry); } else if (oid.equals(OID_PROXIED_AUTH_V2)) { @@ -1828,25 +1828,25 @@ } DN authzDN; try { authzDN = proxyControl.getValidatedAuthorizationDN(); } catch (DirectoryException de) { assert debugException(CLASS_NAME, "run", de); Entry authorizationEntry; try { authorizationEntry = proxyControl.getAuthorizationEntry(); } catch (DirectoryException de) { assert debugException(CLASS_NAME, "run", de); setResultCode(de.getResultCode()); appendErrorMessage(de.getErrorMessage()); setResultCode(de.getResultCode()); appendErrorMessage(de.getErrorMessage()); break searchProcessing; } break searchProcessing; } // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationDN(authzDN); // FIXME -- Should we specifically check permissions here, or let // the earlier access control checks handle it? setAuthorizationEntry(authorizationEntry); } else if (oid.equals(OID_PERSISTENT_SEARCH)) { opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java
@@ -547,7 +547,7 @@ bindOperation.setResultCode(ResultCode.SUCCESS); AuthenticationInfo authInfo = new AuthenticationInfo(userEntry.getDN(), SASL_MECHANISM_CRAM_MD5, new AuthenticationInfo(userEntry, SASL_MECHANISM_CRAM_MD5, DirectoryServer.isRootDN(userEntry.getDN())); bindOperation.setAuthenticationInfo(authInfo); return; opends/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandler.java
@@ -1011,7 +1011,7 @@ AuthenticationInfo authInfo = new AuthenticationInfo(userEntry.getDN(), SASL_MECHANISM_DIGEST_MD5, new AuthenticationInfo(userEntry, SASL_MECHANISM_DIGEST_MD5, DirectoryServer.isRootDN(userEntry.getDN())); bindOperation.setAuthenticationInfo(authInfo); return; opends/src/server/org/opends/server/extensions/ExternalSASLMechanismHandler.java
@@ -455,7 +455,7 @@ AuthenticationInfo authInfo = new AuthenticationInfo(userEntry.getDN(), SASL_MECHANISM_EXTERNAL, new AuthenticationInfo(userEntry, SASL_MECHANISM_EXTERNAL, DirectoryServer.isRootDN(userEntry.getDN())); bindOperation.setAuthenticationInfo(authInfo); bindOperation.setResultCode(ResultCode.SUCCESS); opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java
@@ -419,10 +419,10 @@ { // The authentication was successful, so set the proper state information // in the client connection and return success. DN userDN = stateInfo.getUserEntry().getDN(); Entry userEntry = stateInfo.getUserEntry(); AuthenticationInfo authInfo = new AuthenticationInfo(userDN, SASL_MECHANISM_GSSAPI, DirectoryServer.isRootDN(userDN)); new AuthenticationInfo(userEntry, SASL_MECHANISM_GSSAPI, DirectoryServer.isRootDN(userEntry.getDN())); bindOperation.setAuthenticationInfo(authInfo); bindOperation.setResultCode(ResultCode.SUCCESS); opends/src/server/org/opends/server/extensions/GSSAPIStateInfo.java
@@ -430,7 +430,7 @@ // The authentication was successful, so set the proper state information // in the client connection and return success. AuthenticationInfo authInfo = new AuthenticationInfo(userEntry.getDN(), SASL_MECHANISM_GSSAPI, new AuthenticationInfo(userEntry, SASL_MECHANISM_GSSAPI, DirectoryServer.isRootDN(userEntry.getDN())); bindOperation.setAuthenticationInfo(authInfo); bindOperation.setResultCode(ResultCode.SUCCESS); opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.extensions; @@ -310,8 +310,8 @@ } // Get the DN of the user that issued the request. DN requestorDN = operation.getAuthorizationDN(); // Get the entry for the user that issued the request. Entry requestorEntry = operation.getAuthorizationEntry(); // See if a user identity was provided. If so, then try to resolve it to @@ -329,8 +329,7 @@ // authenticated. ClientConnection clientConnection = operation.getClientConnection(); AuthenticationInfo authInfo = clientConnection.getAuthenticationInfo(); if ((! authInfo.isAuthenticated()) || (requestorDN == null) || (requestorDN.isNullDN())) if ((! authInfo.isAuthenticated()) || (requestorEntry == null)) { operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); @@ -342,7 +341,7 @@ // Retrieve a write lock on that user's entry. userDN = requestorDN; userDN = requestorEntry.getDN(); for (int i=0; i < 3; i++) { @@ -366,11 +365,7 @@ } userEntry = getEntryByDN(operation, userDN); if (userEntry == null) { return; } userEntry = requestorEntry; } else { @@ -500,8 +495,9 @@ // Determine whether the user is changing his own password or if it's an // administrative reset. boolean selfChange = ((userIdentity == null) || (requestorDN == null) || userDN.equals(requestorDN)); boolean selfChange = ((userIdentity == null) || (requestorEntry == null) || userDN.equals(requestorEntry.getDN())); // See if the account is locked. If so, then reject the request. @@ -1085,9 +1081,14 @@ } else { if (selfChange && (requestorEntry == null)) { requestorEntry = userEntry; } // Get an internal connection and use it to perform the modification. boolean isRoot = DirectoryServer.isRootDN(requestorDN); AuthenticationInfo authInfo = new AuthenticationInfo(requestorDN, boolean isRoot = DirectoryServer.isRootDN(requestorEntry.getDN()); AuthenticationInfo authInfo = new AuthenticationInfo(requestorEntry, isRoot); InternalClientConnection internalConnection = new InternalClientConnection(authInfo); opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java
@@ -435,7 +435,7 @@ bindOperation.setResultCode(ResultCode.SUCCESS); AuthenticationInfo authInfo = new AuthenticationInfo(userEntry.getDN(), SASL_MECHANISM_PLAIN, new AuthenticationInfo(userEntry, SASL_MECHANISM_PLAIN, DirectoryServer.isRootDN(userEntry.getDN())); bindOperation.setAuthenticationInfo(authInfo); return; opends/src/server/org/opends/server/messages/CoreMessages.java
@@ -6150,6 +6150,17 @@ /** * The message ID for the message that will be used if a client connection is * terminated because the associated authentication or authorization entry was * removed from the server. It takes a single argument, which is the DN of * the entry that has been removed. */ public static final int MSGID_CLIENTCONNECTION_DISCONNECT_DUE_TO_DELETE = CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_WARNING | 588; /** * Associates a set of generic messages with the message IDs defined * in this class. */ @@ -8321,6 +8332,11 @@ "Rejecting the requested operation " + "because the connection has not been authenticated."); registerMessage(MSGID_CLIENTCONNECTION_DISCONNECT_DUE_TO_DELETE, "Terminating the client connection because its " + "associated authentication or authorization entry %s has " + "been deleted."); } } opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
@@ -32,6 +32,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; @@ -46,6 +47,7 @@ import org.opends.server.core.BindOperation; import org.opends.server.core.CompareOperation; import org.opends.server.core.DeleteOperation; import org.opends.server.core.DirectoryServer; import org.opends.server.core.ExtendedOperation; import org.opends.server.core.ModifyOperation; import org.opends.server.core.ModifyDNOperation; @@ -70,6 +72,7 @@ import org.opends.server.types.ErrorLogSeverity; import org.opends.server.types.DirectoryException; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.IntermediateResponse; import org.opends.server.types.Modification; import org.opends.server.types.ObjectClass; @@ -79,10 +82,12 @@ import org.opends.server.types.SearchResultReference; import org.opends.server.types.SearchScope; import static org.opends.server.config.ConfigConstants.*; import static org.opends.server.loggers.Debug.*; import static org.opends.server.loggers.Error.*; import static org.opends.server.messages.MessageHandler.*; import static org.opends.server.messages.ProtocolMessages.*; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.StaticUtils.*; @@ -152,13 +157,60 @@ // This connection will be authenticated as a root user so that no // access control will be enforced. String dnString = "cn=Internal Client"; String commonName = "Internal Client"; String shortDNString = "cn=" + commonName; String fullDNString = shortDNString + ",cn=Root DNs,cn=config"; try { DN internalUserDN = DN.decode(dnString); LinkedHashMap<ObjectClass,String> objectClasses = new LinkedHashMap<ObjectClass,String>(); ObjectClass topOC = DirectoryServer.getTopObjectClass(); ObjectClass personOC = DirectoryServer.getObjectClass(OC_PERSON, true); ObjectClass rootOC = DirectoryServer.getObjectClass(OC_ROOT_DN, true); objectClasses.put(topOC, topOC.getPrimaryName()); objectClasses.put(personOC, personOC.getPrimaryName()); objectClasses.put(rootOC, rootOC.getPrimaryName()); LinkedHashMap<AttributeType,List<Attribute>> userAttrs = new LinkedHashMap<AttributeType,List<Attribute>>(); AttributeType cnAT = DirectoryServer.getAttributeType(ATTR_COMMON_NAME, true); AttributeType snAT = DirectoryServer.getAttributeType(ATTR_SN, true); AttributeType altDNAT = DirectoryServer.getAttributeType( ATTR_ROOTDN_ALTERNATE_BIND_DN, true); LinkedList<Attribute> attrList = new LinkedList<Attribute>(); attrList.add(new Attribute(ATTR_COMMON_NAME, commonName)); userAttrs.put(cnAT, attrList); attrList = new LinkedList<Attribute>(); attrList.add(new Attribute(ATTR_SN, commonName)); userAttrs.put(snAT, attrList); attrList = new LinkedList<Attribute>(); attrList.add(new Attribute(ATTR_ROOTDN_ALTERNATE_BIND_DN, shortDNString)); userAttrs.put(altDNAT, attrList); LinkedHashMap<AttributeType,List<Attribute>> operationalAttrs = new LinkedHashMap<AttributeType,List<Attribute>>(); // FIXME -- Add privileges here. DN internalUserDN = DN.decode(fullDNString); Entry internalUserEntry = new Entry(internalUserDN, objectClasses, userAttrs, operationalAttrs); this.authenticationInfo = new AuthenticationInfo(internalUserDN, true); new AuthenticationInfo(internalUserEntry, true); } catch (DirectoryException de) { @@ -166,7 +218,7 @@ logError(ErrorLogCategory.CONNECTION_HANDLING, ErrorLogSeverity.SEVERE_ERROR, MSGID_INTERNAL_CANNOT_DECODE_DN, dnString, MSGID_INTERNAL_CANNOT_DECODE_DN, fullDNString, stackTraceToSingleLineString(de)); } @@ -1535,7 +1587,10 @@ String.valueOf(messageID)); // No implementation is required since there is nothing to // disconnect. // disconnect. Further, since there is no real disconnect, we can // wait to have the garbage collector call // finalizeConnectionInternal whenever this internal connection is // garbage collected. } @@ -1735,7 +1790,12 @@ buffer.append("InternalClientConnection(connID="); buffer.append(connectionID); buffer.append(", authDN=\""); buffer.append(getAuthenticationInfo().getAuthenticationDN()); if (getAuthenticationInfo() != null) { buffer.append(getAuthenticationInfo().getAuthenticationDN()); } buffer.append("\")"); } } opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.protocols.jmx; @@ -895,6 +895,7 @@ return; } disconnectStarted = true ; finalizeConnectionInternal(); @@ -1144,6 +1145,7 @@ */ protected void finalize() { super.finalize(); disconnect(DisconnectReason.OTHER, false, null, -1); } } opends/src/server/org/opends/server/protocols/jmx/RmiAuthenticator.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.protocols.jmx; @@ -265,7 +265,7 @@ bindPW = new ASN1OctetString(password); } AuthenticationInfo authInfo = new AuthenticationInfo(bindDN, bindPW, false); AuthenticationInfo authInfo = new AuthenticationInfo(); JmxClientConnection jmxClientConnection = new JmxClientConnection( jmxConnectionHandler, authInfo); @@ -284,6 +284,8 @@ "bind", "User is authenticated"); authInfo = bindOp.getAuthenticationInfo(); jmxClientConnection.setAuthenticationInfo(authInfo); return jmxClientConnection; } else opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.protocols.ldap; @@ -1032,6 +1032,7 @@ } cancelAllOperations(new CancelRequest(true, message)); finalizeConnectionInternal(); // See if we should send a notification to the client. If so, then opends/src/server/org/opends/server/types/AuthenticationInfo.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.types; @@ -34,6 +34,7 @@ import java.util.Set; import static org.opends.server.loggers.Debug.*; import static org.opends.server.util.Validator.*; @@ -68,11 +69,12 @@ // other operation will be allowed. private boolean mustChangePassword; // The DN of the user that is currently authenticated. private DN authenticationDN; // The entry of the user that is currently authenticated. private Entry authenticationEntry; // The authorization DN for this authentication info structure. private DN authorizationDN; // The entry of the user that will be used as the default // authorization identity. private Entry authorizationEntry; // The type of authentication performed on this connection. private Set<AuthenticationType> authenticationTypes; @@ -95,8 +97,8 @@ mustChangePassword = false; simplePassword = null; authenticationTypes = new HashSet<AuthenticationType>(0); authenticationDN = null; authorizationDN = null; authenticationEntry = null; authorizationEntry = null; saslMechanisms = new HashSet<String>(0); } @@ -106,24 +108,25 @@ * Creates a new set of authentication information to be used for * clients that are authenticated internally. * * @param authenticationDN The DN of the user that has * authenticated. * @param isRoot Indicates whether the authenticated * user is a root user. * @param authenticationEntry The entry of the user that has * authenticated, or {@code null} to * indicate an unauthenticated user. * @param isRoot Indicates whether the authenticated * user is a root user. */ public AuthenticationInfo(DN authenticationDN, boolean isRoot) public AuthenticationInfo(Entry authenticationEntry, boolean isRoot) { assert debugConstructor(CLASS_NAME, String.valueOf(authenticationDN), String.valueOf(authenticationEntry), String.valueOf(isRoot)); this.authenticationDN = authenticationDN; this.isRoot = isRoot; this.authenticationEntry = authenticationEntry; this.isRoot = isRoot; isAuthenticated = true; isAuthenticated = (authenticationEntry != null); mustChangePassword = false; simplePassword = null; authorizationDN = authenticationDN; authorizationEntry = authenticationEntry; saslMechanisms = new HashSet<String>(0); authenticationTypes = new HashSet<AuthenticationType>(1); @@ -136,28 +139,32 @@ * Creates a new set of authentication information to be used for * clients that have successfully performed simple authentication. * * @param authenticationDN The DN of the user that has * authenticated. * @param simplePassword The password that was used to perform * the simple authentication. * @param isRoot Indicates whether the authenticated * user is a root user. * @param authenticationEntry The entry of the user that has * authenticated. It must not be * {@code null}. * @param simplePassword The password that was used to * perform the simple authentication. * It must not be {@code null}. * @param isRoot Indicates whether the authenticated * user is a root user. */ public AuthenticationInfo(DN authenticationDN, public AuthenticationInfo(Entry authenticationEntry, ByteString simplePassword, boolean isRoot) { assert debugConstructor(CLASS_NAME, String.valueOf(authenticationDN), String.valueOf(authenticationEntry), String.valueOf(simplePassword), String.valueOf(isRoot)); this.authenticationDN = authenticationDN; this.simplePassword = simplePassword; this.isRoot = isRoot; ensureNotNull(authenticationEntry, simplePassword); this.authenticationEntry = authenticationEntry; this.simplePassword = simplePassword; this.isRoot = isRoot; isAuthenticated = true; mustChangePassword = false; authorizationDN = authenticationDN; authorizationEntry = authenticationEntry; saslMechanisms = new HashSet<String>(0); authenticationTypes = new HashSet<AuthenticationType>(1); @@ -170,28 +177,32 @@ * Creates a new set of authentication information to be used for * clients that have authenticated using a SASL mechanism. * * @param authenticationDN The DN of the user that has * authenticated. * @param saslMechanism The SASL mechanism used to * authenticate. Note that this must be * provided in all-uppercase characters. * @param isRoot Indicates whether the authenticated * user is a root user. * @param authenticationEntry The entry of the user that has * authenticated. It must not be * {@code null}. * @param saslMechanism The SASL mechanism used to * authenticate. This must be provided * in all-uppercase characters and must * not be {@code null}. * @param isRoot Indicates whether the authenticated * user is a root user. */ public AuthenticationInfo(DN authenticationDN, String saslMechanism, boolean isRoot) public AuthenticationInfo(Entry authenticationEntry, String saslMechanism, boolean isRoot) { assert debugConstructor(CLASS_NAME, String.valueOf(authenticationDN), String.valueOf(authenticationEntry), String.valueOf(saslMechanism), String.valueOf(isRoot)); this.authenticationDN = authenticationDN; this.isRoot = isRoot; ensureNotNull(authenticationEntry, saslMechanism); this.authenticationEntry = authenticationEntry; this.isRoot = isRoot; isAuthenticated = true; mustChangePassword = false; authorizationDN = authenticationDN; authorizationEntry = authenticationEntry; simplePassword = null; authenticationTypes = new HashSet<AuthenticationType>(1); @@ -207,35 +218,43 @@ * Creates a new set of authentication information to be used for * clients that have authenticated using a SASL mechanism. * * @param authenticationDN The DN of the user that has * authenticated. * @param authorizationDN The authorization DN for the * authenticated user. * @param saslMechanism The SASL mechanism used to * authenticate. Note that this must be * provided in all-uppercase characters. * @param isRoot Indicates whether the authenticated * user is a root user. * @param authenticationEntry The entry of the user that has * authenticated. It must not be * {@code null}. * @param authorizationEntry The entry of the user that will be * used as the default authorization * identity, or {@code null} to * indicate that it should be the same * as the authentication entry. * @param saslMechanism The SASL mechanism used to * authenticate. This must be provided * in all-uppercase characters and must * not be {@code null}. * @param isRoot Indicates whether the authenticated * user is a root user. */ public AuthenticationInfo(DN authenticationDN, DN authorizationDN, public AuthenticationInfo(Entry authenticationEntry, Entry authorizationEntry, String saslMechanism, boolean isRoot) { assert debugConstructor(CLASS_NAME, String.valueOf(authenticationDN), String.valueOf(authorizationDN), String.valueOf(authenticationEntry), String.valueOf(authorizationEntry), String.valueOf(saslMechanism), String.valueOf(isRoot)); this.authenticationDN = authenticationDN; this.isRoot = isRoot; ensureNotNull(authenticationEntry, saslMechanism); if (authorizationDN == null) this.authenticationEntry = authenticationEntry; this.isRoot = isRoot; if (authorizationEntry == null) { this.authorizationDN = authenticationDN; this.authorizationEntry = authenticationEntry; } else { this.authorizationDN = authorizationDN; this.authorizationEntry = authorizationEntry; } isAuthenticated = true; @@ -255,9 +274,8 @@ * Indicates whether this client has successfully authenticated to * the server. * * @return <CODE>true</CODE> if this client has successfully * authenticated to the server, or <CODE>false</CODE> if * not. * @return {@code true} if this client has successfully * authenticated to the server, or {@code false} if not. */ public boolean isAuthenticated() { @@ -280,8 +298,8 @@ isRoot = false; mustChangePassword = false; simplePassword = null; authenticationDN = null; authorizationDN = null; authenticationEntry = null; authorizationEntry = null; authenticationTypes.clear(); saslMechanisms.clear(); @@ -292,8 +310,8 @@ /** * Indicates whether this client should be considered a root user. * * @return <CODE>true</CODE> if this client should be considered a * root user, or <CODE>false</CODE> if not. * @return {@code true} if this client should be considered a root * user, or {@code false} if not. */ public boolean isRoot() { @@ -305,12 +323,12 @@ /** * Indicates whether the associated user must change their password * before any other operation will be allowed. * Indicates whether the authenticated user must change his/her * password before any other operation will be allowed. * * @return <CODE>true</CODE> if the user must change their password * @return {@code true} if the user must change his/her password * before any other operation will be allowed, or * <CODE>false</CODE> if not. * {@code false} if not. */ public boolean mustChangePassword() { @@ -322,12 +340,13 @@ /** * Specifies whether the associated user must change their password * before any other operation will be allowed. * Specifies whether the authenticated user must change his/her * password before any other operation will be allowed. * * @param mustChangePassword Specifies whether the associated user * must change their password before any * other operation will be allowed. * @param mustChangePassword Specifies whether the authenticated * user must change his/her password * before any other operation will be * allowed. */ public void setMustChangePassword(boolean mustChangePassword) { @@ -346,9 +365,8 @@ * @param authenticationType The authentication type for which to * make the determination. * * @return <CODE>true</CODE> if the client has authenticated using * the specified authentication type, or <CODE>false</CODE> * if not. * @return {@code true} if the client has authenticated using the * specified authentication type, or {@code false} if not. */ public boolean hasAuthenticationType(AuthenticationType authenticationType) @@ -368,9 +386,9 @@ * @param types The collection of authentication types for which * to make the determination. * * @return <CODE>true</CODE> if the client has authenticated using * any of the specified authentication types, or * <CODE>false</CODE> if not. * @return {@code true} if the client has authenticated using any * of the specified authentication types, or {@code false} * if not. */ public boolean hasAnyAuthenticationType( Collection<AuthenticationType> types) @@ -426,30 +444,83 @@ /** * Retrieves the DN of the user as whom the client is authenticated. * Retrieves the entry for the user as whom the client is * authenticated. * * @return The DN of the user as whom the client is authenticated, * or <CODE>null</CODE> if the client is unauthenticated. * @return The entry for the user as whom the client is * authenticated, or {@code null} if the client is * unauthenticated. */ public DN getAuthenticationDN() public Entry getAuthenticationEntry() { assert debugEnter(CLASS_NAME, "getAuthenticationDN"); assert debugEnter(CLASS_NAME, "getAuthenticationEntry"); return authenticationDN; return authenticationEntry; } /** * Retrieves the authorization DN for this client. * Retrieves the DN of the user as whom the client is authenticated. * * @return The authorization DN for this client. * @return The DN of the user as whom the client is authenticated, * or {@code null} if the client is unauthenticated. */ public DN getAuthenticationDN() { assert debugEnter(CLASS_NAME, "getAuthenticationDN"); if (authenticationEntry == null) { return null; } else { return authenticationEntry.getDN(); } } /** * Retrieves the entry for the user that should be used as the * default authorization identity. * * @return The entry for the user that should be used as the * default authorization identity, or {@code null} if the * authorization identity should be the unauthenticated * user. */ public Entry getAuthorizationEntry() { assert debugEnter(CLASS_NAME, "getAuthorizationEntry"); return authorizationEntry; } /** * Retrieves the DN for the user that should be used as the default * authorization identity. * * @return The DN for the user that should be used as the default * authorization identity, or {@code null} if the * authorization identity should be the unauthenticated * user. */ public DN getAuthorizationDN() { assert debugEnter(CLASS_NAME, "getAuthorizationDN"); return authorizationDN; if (authorizationEntry == null) { return null; } else { return authorizationEntry.getDN(); } } @@ -459,8 +530,8 @@ * authentication. * * @return The password that the client used for simple * authentication, or <CODE>null</CODE> if the client is * not authenticated using simple authentication. * authentication, or {@code null} if the client is not * authenticated using simple authentication. */ public ByteString getSimplePassword() { @@ -479,9 +550,8 @@ * determination. Note that this must be * provided in all uppercase characters. * * @return <CODE>true</CODE> if the client is authenticated using * the specified SASL mechanism, or <CODE>false</CODE> if * not. * @return {@code true} if the client is authenticated using the * specified SASL mechanism, or {@code false} if not. */ public boolean hasSASLMechanism(String saslMechanism) { @@ -500,9 +570,9 @@ * @param mechanisms The collection of SASL mechanisms for which * to make the determination. * * @return <CODE>true</CODE> if the client has authenticated using * any of the provided SASL mechanisms, or * <CODE>false</CODE> if not. * @return {@code true} if the client has authenticated using any * of the provided SASL mechanisms, or {@code false} if * not. */ public boolean hasAnySASLMechanism(Collection<String> mechanisms) { @@ -560,39 +630,6 @@ /** * Indicates whether the user associated with this authentication * info is a member of the group with the specified DN. * * @param groupDN The DN of the group for which to make the * determination. * * @return <CODE>true</CODE> if the authenticated user is a member * of the specified group, or <CODE>false</CODE> if not. */ public boolean isMemberOf(DN groupDN) { // NYI return false; } /** * Retrieves the DNs of the groups in which the user associated with * this authentication info is a member. * * @return The DNs of the groups in which the user associated with * this authentication info is a member. */ public Collection<DN> getMembershipDNs() { // NYI return null; } /** * Retrieves a string representation of this authentication info * structure. * @@ -630,16 +667,22 @@ buffer.append(",mustChangePassword="); buffer.append(mustChangePassword); buffer.append(",authenticationDN=\""); buffer.append(authenticationDN); if ((authorizationDN == null) || authorizationDN.equals(authenticationDN)) if (authenticationEntry != null) { buffer.append("\",authorizationDN=\""); buffer.append(authorizationDN); authenticationEntry.getDN().toString(buffer); } buffer.append("\""); if (authorizationEntry == null) { buffer.append("\",authorizationDN=\"\""); } else { buffer.append("\",authorizationDN=\""); authorizationEntry.getDN().toString(buffer); buffer.append("\""); } if (! authenticationTypes.isEmpty()) { @@ -694,5 +737,44 @@ buffer.append(")"); } /** * Creates a duplicate of this {@code AuthenticationInfo} object * with the new authentication and authorization entries. * * @param newAuthenticationEntry The updated entry for the user * as whom the associated client * connection is authenticated. * @param newAuthorizationEntry The updated entry for the default * authorization identity for the * associated client connection. * * @return The duplicate of this {@code AuthenticationInfo} object * with the specified authentication and authorization * entries. */ public AuthenticationInfo duplicate(Entry newAuthenticationEntry, Entry newAuthorizationEntry) { assert debugEnter(CLASS_NAME, "duplicate", String.valueOf(newAuthenticationEntry), String.valueOf(newAuthorizationEntry)); AuthenticationInfo authInfo = new AuthenticationInfo(); authInfo.simplePassword = simplePassword; authInfo.isAuthenticated = isAuthenticated; authInfo.isRoot = isRoot; authInfo.mustChangePassword = mustChangePassword; authInfo.authenticationEntry = newAuthenticationEntry; authInfo.authorizationEntry = newAuthorizationEntry; authInfo.authenticationTypes.addAll(authenticationTypes); authInfo.saslMechanisms.addAll(saslMechanisms); return authInfo; } } opends/src/server/org/opends/server/util/ServerConstants.java
@@ -338,6 +338,14 @@ /** * The name of the standard attribute that is used to hold surnames, formatted * in all lowercase. */ public static final String ATTR_SN = "sn"; /** * The name of the standard attribute that is used to specify the location * for the Directory Server schema, formatted in camel case. */ @@ -719,6 +727,13 @@ /** * The name of the person objectclass, formatted in all lowercase characters. */ public static final String OC_PERSON = "person"; /** * The name of the standard objectclass that is used to indicate that an entry * is a smart referral, formatted in all lowercase. */ opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV1ControlTestCase.java
@@ -419,7 +419,7 @@ ProxiedAuthV1Control proxyControl = new ProxiedAuthV1Control(DN.nullDN()); assertTrue(proxyControl.getValidatedAuthorizationDN().isNullDN()); assertNull(proxyControl.getAuthorizationEntry()); } @@ -450,7 +450,7 @@ ProxiedAuthV1Control proxyControl = new ProxiedAuthV1Control(DN.decode("uid=test,o=test")); assertEquals(proxyControl.getValidatedAuthorizationDN(), assertEquals(proxyControl.getAuthorizationEntry().getDN(), DN.decode("uid=test,o=test")); } @@ -471,7 +471,7 @@ ProxiedAuthV1Control proxyControl = new ProxiedAuthV1Control(DN.decode("uid=test,o=test")); proxyControl.getValidatedAuthorizationDN(); proxyControl.getAuthorizationEntry(); } @@ -501,7 +501,7 @@ ProxiedAuthV1Control proxyControl = new ProxiedAuthV1Control(DN.decode("uid=test,o=test")); proxyControl.getValidatedAuthorizationDN(); proxyControl.getAuthorizationEntry(); } opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV2ControlTestCase.java
@@ -309,7 +309,7 @@ { ProxiedAuthV2Control proxyControl = new ProxiedAuthV2Control(new ASN1OctetString("")); assertEquals(proxyControl.getValidatedAuthorizationDN(), DN.nullDN()); assertNull(proxyControl.getAuthorizationEntry()); } @@ -326,7 +326,7 @@ { ProxiedAuthV2Control proxyControl = new ProxiedAuthV2Control(new ASN1OctetString("dn:")); assertEquals(proxyControl.getValidatedAuthorizationDN(), DN.nullDN()); assertNull(proxyControl.getAuthorizationEntry()); } @@ -355,7 +355,7 @@ ProxiedAuthV2Control proxyControl = new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test")); assertEquals(proxyControl.getValidatedAuthorizationDN(), assertEquals(proxyControl.getAuthorizationEntry().getDN(), DN.decode("uid=test,o=test")); } @@ -375,7 +375,7 @@ ProxiedAuthV2Control proxyControl = new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test")); proxyControl.getValidatedAuthorizationDN(); proxyControl.getAuthorizationEntry(); } @@ -406,7 +406,7 @@ ProxiedAuthV2Control proxyControl = new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test")); proxyControl.getValidatedAuthorizationDN(); proxyControl.getAuthorizationEntry(); } @@ -423,7 +423,7 @@ { ProxiedAuthV2Control proxyControl = new ProxiedAuthV2Control(new ASN1OctetString("u:")); assertEquals(proxyControl.getValidatedAuthorizationDN(), DN.nullDN()); assertNull(proxyControl.getAuthorizationEntry()); } @@ -452,7 +452,7 @@ ProxiedAuthV2Control proxyControl = new ProxiedAuthV2Control(new ASN1OctetString("u:test")); assertEquals(proxyControl.getValidatedAuthorizationDN(), assertEquals(proxyControl.getAuthorizationEntry().getDN(), DN.decode("uid=test,o=test")); } @@ -472,7 +472,7 @@ ProxiedAuthV2Control proxyControl = new ProxiedAuthV2Control(new ASN1OctetString("u:test")); proxyControl.getValidatedAuthorizationDN(); proxyControl.getAuthorizationEntry(); } @@ -503,7 +503,7 @@ ProxiedAuthV2Control proxyControl = new ProxiedAuthV2Control(new ASN1OctetString("u:test")); proxyControl.getValidatedAuthorizationDN(); proxyControl.getAuthorizationEntry(); } @@ -520,7 +520,7 @@ { ProxiedAuthV2Control proxyControl = new ProxiedAuthV2Control(new ASN1OctetString("invalid")); proxyControl.getValidatedAuthorizationDN(); proxyControl.getAuthorizationEntry(); } opends/tests/unit-tests-testng/src/server/org/opends/server/core/GroupManagerTestCase.java
@@ -831,7 +831,7 @@ // Get a client connection authenticated as user1 and make sure it handles // group operations correctly. authInfo = new AuthenticationInfo(user1DN, false); authInfo = new AuthenticationInfo(DirectoryServer.getEntry(user1DN), false); InternalClientConnection conn1 = new InternalClientConnection(authInfo); searchOperation = new InternalSearchOperation(conn1, conn1.nextOperationID(), @@ -862,7 +862,7 @@ // Get a client connection authenticated as user2 and make sure it handles // group operations correctly. authInfo = new AuthenticationInfo(user2DN, false); authInfo = new AuthenticationInfo(DirectoryServer.getEntry(user2DN), false); InternalClientConnection conn2 = new InternalClientConnection(authInfo); searchOperation = new InternalSearchOperation(conn2, conn2.nextOperationID(), @@ -893,7 +893,7 @@ // Get a client connection authenticated as user3 and make sure it handles // group operations correctly. authInfo = new AuthenticationInfo(user3DN, false); authInfo = new AuthenticationInfo(DirectoryServer.getEntry(user3DN), false); InternalClientConnection conn3 = new InternalClientConnection(authInfo); searchOperation = new InternalSearchOperation(conn3, conn3.nextOperationID(), opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/WhoAmIExtendedOperationTestCase.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.extensions; @@ -143,8 +143,7 @@ assertEquals(addOp.getResultCode(), ResultCode.SUCCESS); conn = new InternalClientConnection(new AuthenticationInfo(e.getDN(), false)); conn = new InternalClientConnection(new AuthenticationInfo(e, false)); ExtendedOperation extOp = conn.processExtendedOperation(OID_WHO_AM_I_REQUEST, null); assertEquals(extOp.getResultCode(), ResultCode.SUCCESS); opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java
@@ -108,14 +108,31 @@ public Object[][] getInternalConnections() throws Exception { DN dmDN = DN.decode("cn=Directory Manager,cn=Root DNs,cn=config"); Entry dmEntry = DirectoryServer.getEntry(dmDN); TestCaseUtils.initializeTestBackend(true); Entry userEntry = TestCaseUtils.makeEntry( "dn: uid=test.user,o=test", "objectClass: top", "objectClass: person", "objectClass: organizationalPerson", "objectClass: inetOrgPerson", "uid: test.user", "givenName: Test", "sn: User", "cn: Test User", "userPassword: password"); TestCaseUtils.addEntry(userEntry); return new Object[][] { new Object[] { InternalClientConnection.getRootConnection() }, new Object[] { new InternalClientConnection(new AuthenticationInfo()) }, new Object[] { new InternalClientConnection( new AuthenticationInfo(DN.decode("cn=Directory Manager"), true)) }, new AuthenticationInfo(dmEntry, true)) }, new Object[] { new InternalClientConnection( new AuthenticationInfo(DN.decode("uid=test,o=test"), false)) }, new AuthenticationInfo(userEntry, false)) } }; }