From 10d7c1ea90c6016ab1e6cc2218c44dcb74a5fdb3 Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Tue, 10 Apr 2007 21:02:22 +0000
Subject: [PATCH] Add ACI support for proxy right. Issue #1489.
---
opendj-sdk/opends/src/server/org/opends/server/core/DeleteOperation.java | 20 ++
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java | 2
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java | 82 +++++++-
opendj-sdk/opends/src/server/org/opends/server/authorization/BasicAccessControlHandler.java | 18 +
opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java | 21 ++
opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java | 20 ++
opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java | 20 ++
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java | 185 ++++++++++++++++-
opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlProvider.java | 9
opendj-sdk/opends/src/server/org/opends/server/core/ModifyDNOperation.java | 21 ++
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java | 94 +++++++++
opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java | 29 ++
opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java | 21 ++
13 files changed, 493 insertions(+), 49 deletions(-)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java b/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
index fccc56c..eec0fac 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
@@ -28,17 +28,10 @@
-import org.opends.server.core.AddOperation;
-import org.opends.server.core.BindOperation;
-import org.opends.server.core.CompareOperation;
-import org.opends.server.core.DeleteOperation;
-import org.opends.server.core.ExtendedOperation;
-import org.opends.server.core.ModifyDNOperation;
-import org.opends.server.core.ModifyOperation;
-import org.opends.server.core.SearchOperation;
+import org.opends.server.core.*;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
-
+import org.opends.server.types.Entry;
/**
@@ -237,5 +230,23 @@
*/
public abstract boolean maySend(SearchOperation searchOperation,
SearchResultReference searchReference);
+
+ /**
+ * Indicates whether a proxied authorization control is allowed
+ * based on the current operation and the new authorization
+ * entry.
+ *
+ * @param operation
+ * The operation with which the proxied authorization
+ * control is associated.
+ * @param newAuthorizationEntry
+ * The new authorization entry related to the
+ * proxied authorization control authorization ID.
+ * @return <CODE>true</CODE> if the operation should be allowed by
+ * the access control configuration, or <CODE>false</CODE>
+ * if not.
+ */
+ public abstract boolean isProxiedAuthAllowed(Operation operation,
+ Entry newAuthorizationEntry);
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/BasicAccessControlHandler.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/BasicAccessControlHandler.java
index 4e4c71a..756c8e0 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/BasicAccessControlHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/BasicAccessControlHandler.java
@@ -28,16 +28,10 @@
import org.opends.server.api.AccessControlHandler;
-import org.opends.server.core.AddOperation;
-import org.opends.server.core.BindOperation;
-import org.opends.server.core.CompareOperation;
-import org.opends.server.core.DeleteOperation;
-import org.opends.server.core.ExtendedOperation;
-import org.opends.server.core.ModifyDNOperation;
-import org.opends.server.core.ModifyOperation;
-import org.opends.server.core.SearchOperation;
+import org.opends.server.core.*;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
+import org.opends.server.types.Entry;
/**
* This class provides the implementation of the basic access control
@@ -169,4 +163,12 @@
return true;
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isProxiedAuthAllowed(Operation operation, Entry entry) {
+ return true;
+ }
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
index 5308889..2d6869a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
@@ -194,7 +194,7 @@
public static final int ACI_ALL = 0x007F;
/**
- * ACI_PROXY is used for the PROXY right. Currently not used.
+ * ACI_PROXY is used for the PROXY right.
*/
public static final int ACI_PROXY = 0x0080;
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
index baea9bd..c4ac14c 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -36,6 +36,7 @@
import org.opends.server.extensions.TLSConnectionSecurityProvider;
import java.net.InetAddress;
import java.util.LinkedList;
+import static org.opends.server.authorization.dseecompat.AciHandler.*;
/**
* The AciContainer class contains all of the needed information to perform
@@ -109,6 +110,41 @@
*/
private boolean targAttrFiltersMatch=false;
+ /*
+ * The authorization entry currently being evaluated. If proxied
+ * authorization is being used and the handler is doing a proxy access
+ * check, then this entry will switched to the original authorization entry
+ * rather than the proxy ID entry. If the check succeeds, it will be
+ * switched back for non-proxy access checking. If proxied authentication
+ * is not being used then this entry never changes.
+ */
+ private Entry authorizationEntry;
+
+ /*
+ * Used to save the current authorization entry when the authorization
+ * entry is switched during a proxy access check.
+ */
+ private Entry saveAuthorizationEntry;
+
+ /*
+ * This entry is only used if proxied authorization is being used. It is
+ * the original authorization entry before the proxied authorization change.
+ */
+ private Entry origAuthorizationEntry=null;
+
+ /*
+ * True if proxied authorization is being used.
+ */
+ private boolean proxiedAuthorization=false;
+
+ /*
+ * Used by proxied authorization processing. True if the entry has already
+ * been processed by an access proxy check. Some operations might perform
+ * several access checks on the same entry (modify DN), this
+ * flag is used to bypass the proxy check after the initial evaluation.
+ */
+ private boolean seenEntry=false;
+
/**
* This constructor is used by all currently supported LDAP operations.
*
@@ -123,9 +159,63 @@
this.clientConnection=operation.getClientConnection();
if(operation instanceof AddOperation)
this.isAddOp=true;
+
+ //If the proxied authorization control was processed, then the operation
+ //will contain an attachment containing the original authorization entry.
+ this.origAuthorizationEntry =
+ (Entry) operation.getAttachment(ORIG_AUTH_ENTRY);
+ if(origAuthorizationEntry != null)
+ this.proxiedAuthorization=true;
+ this.authorizationEntry=operation.getAuthorizationEntry();
+
+ //Reference the current authorization entry, so it can be put back
+ //if an access proxy check was performed.
+ this.saveAuthorizationEntry=this.authorizationEntry;
this.rights = rights;
}
+ /**
+ * Returns true if an entry has already been processed by an access proxy
+ * check.
+ * @return True if an entry has already been processed by an access proxy
+ * check.
+ */
+ public boolean hasSeenEntry() {
+ return this.seenEntry;
+ }
+
+ /**
+ * Set to true if an entry has already been processsed by an access proxy
+ * check.
+ * @param val The value to set the seenEntry boolean to.
+ */
+ public void setSeenEntry(boolean val) {
+ this.seenEntry=val;
+ }
+
+ /**
+ * Returns true if proxied authorization is being used.
+ * @return True if proxied authorization is being used.
+ */
+ public boolean isProxiedAuthorization() {
+ return this.proxiedAuthorization;
+ }
+
+ /**
+ * If the specified value is true, then the original authorization entry,
+ * which is the entry before the switch performed by the proxied
+ * authorization control processing should be set to the current
+ * authorization entry. If the specified value is false then the proxied
+ * authorization entry is switched back using the saved copy.
+ * @param val The value used to select the authorization entry to use.
+ */
+ public void useOrigAuthorizationEntry(boolean val) {
+ if(val)
+ authorizationEntry=origAuthorizationEntry;
+ else
+ authorizationEntry=saveAuthorizationEntry;
+ }
+
/**
* The list of deny ACIs. These are all of the applicable
* ACIs that have a deny permission. Note that an ACI can
@@ -226,7 +316,7 @@
* @return The client entry.
*/
public Entry getClientEntry() {
- return operation.getAuthorizationEntry();
+ return this.authorizationEntry;
}
/**
@@ -275,7 +365,7 @@
* @return The client's authorization DN.
*/
public DN getClientDN() {
- return operation.getAuthorizationDN();
+ return this.authorizationEntry.getDN();
}
/**
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
index 8544649..ea636bc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -72,6 +72,12 @@
public static AttributeType globalAciType;
/**
+ * String used to save the original authorization entry in an operation
+ * attachment if a proxied authorization control was seen.
+ */
+ public static String ORIG_AUTH_ENTRY="origAuthorizationEntry";
+
+ /**
* This constructor instantiates the ACI handler class that performs the
* main processing for the dseecompat ACI package. It does the following
* initializations:
@@ -443,6 +449,32 @@
return false;
}
}
+
+ //Check proxy authorization only if the entry has not already been
+ //processed (working on a new entry). If working on a new entry, then
+ //only do a proxy check if the right is not set to ACI_PROXY and the
+ //proxied authorization control has been decoded.
+ if(!container.hasSeenEntry()) {
+ if(!container.hasRights(ACI_PROXY) &&
+ container.isProxiedAuthorization()) {
+ int currentRights=container.getRights();
+ //Save the current rights so they can be put back if on success.
+ container.setRights(ACI_PROXY);
+ //Switch to the original authorization entry, not the proxied one.
+ container.useOrigAuthorizationEntry(true);
+ if(!accessAllowed(container))
+ return false;
+ //Access is ok, put the original rights back.
+ container.setRights(currentRights);
+ //Put the proxied authorization entry back to the current
+ //authorization entry.
+ container.useOrigAuthorizationEntry(false);
+ }
+ //Set the seen flag so proxy processing is not performed for this
+ //entry again.
+ container.setSeenEntry(true);
+ }
+
/*
* First get all allowed candidate ACIs.
*/
@@ -714,7 +746,6 @@
* @return True if access is allowed.
*/
public boolean isAllowed(CompareOperation operation) {
-
AciLDAPOperationContainer operationContainer =
new AciLDAPOperationContainer(operation, ACI_COMPARE);
String baseName;
@@ -803,10 +834,12 @@
*/
public SearchResultEntry filterEntry(SearchOperation operation,
SearchResultEntry entry) {
-
AciLDAPOperationContainer operationContainer =
new AciLDAPOperationContainer(operation,
(ACI_READ), entry);
+ //Proxy access check has already been done for this entry in the maySend
+ //method, set the seen flag to true to bypass any proxy check.
+ operationContainer.setSeenEntry(true);
SearchResultEntry returnEntry;
if(!skipAccessCheck(operation)) {
returnEntry=accessAllowedAttrs(operationContainer);
@@ -816,10 +849,10 @@
}
/**
- * Perform all needed RDN checks for the modifyDN operation. These checks
- * are:
+ * Perform all needed RDN checks for the modifyDN operation. The old RDN is
+ * not equal to the new RDN. The access checks are:
*
- * - Verify WRITE access to the entry.
+ * - Verify WRITE access to the original entry.
* - Verfiy WRITE_ADD access on each RDN component of the new RDN. The
* WRITE_ADD access is used because this access could be restricted by
* the targattrfilters keyword.
@@ -829,18 +862,21 @@
*
* @param operation The ModifyDN operation class containing information to
* check access on.
+ * @param oldRDN The old RDN component.
+ * @param newRDN The new RDN component.
* @return True if access is allowed.
*/
- private boolean aciCheckRDNs(ModifyDNOperation operation) {
+ private boolean aciCheckRDNs(ModifyDNOperation operation, RDN oldRDN,
+ RDN newRDN) {
boolean ret;
+
AciLDAPOperationContainer operationContainer =
new AciLDAPOperationContainer(operation, (ACI_WRITE),
operation.getOriginalEntry());
ret=accessAllowed(operationContainer);
if(ret)
- ret=checkRDN(ACI_WRITE_ADD,operation.getNewRDN(),operationContainer);
+ ret=checkRDN(ACI_WRITE_ADD, newRDN, operationContainer);
if(ret && operation.deleteOldRDN()) {
- RDN oldRDN=operation.getOriginalEntry().getDN().getRDN();
ret =
checkRDN(ACI_WRITE_DELETE, oldRDN, operationContainer);
}
@@ -923,6 +959,8 @@
public boolean isAllowed(ModifyDNOperation operation) {
boolean ret=true;
DN newSuperiorDN;
+ RDN oldRDN=operation.getOriginalEntry().getDN().getRDN();
+ RDN newRDN=operation.getNewRDN();
if(!skipAccessCheck(operation)) {
//If this is a modifyDN move to a new superior, then check if the
//superior DN has import accesss.
@@ -933,21 +971,41 @@
ret=false;
}
}
- //Perform the RDN access checks.
- if(ret)
- ret=aciCheckRDNs(operation);
+ boolean rdnEquals=oldRDN.equals(newRDN);
+ //Perform the RDN access checks only if the RDNs are not equal.
+ if(ret && !rdnEquals)
+ ret=aciCheckRDNs(operation, oldRDN, newRDN);
+
//If this is a modifyDN move to a new superior, then check if the
//original entry DN has export access.
if(ret && (newSuperiorDN != null)) {
AciLDAPOperationContainer operationContainer =
new AciLDAPOperationContainer(operation, (ACI_EXPORT),
- operation.getOriginalEntry());
+ operation.getOriginalEntry());
+ //The RDNs are not equal, skip the proxy check since it was
+ //already performed in the aciCheckRDNs call above.
+ if(!rdnEquals)
+ operationContainer.setSeenEntry(true);
ret=accessAllowed(operationContainer);
}
}
return ret;
}
+ //TODO Check access to control, issue #452.
+ /**
+ * Called when a proxied authorization control was decoded. Currently used
+ * to save the current authorization entry in an operation attachment, but
+ * eventually will be used to check access to the actual control.
+ * @param operation The operation to save the attachment to.
+ * @param entry The new authorization entry.
+ * @return True if the control is allowed access.
+ */
+ public boolean isProxiedAuthAllowed(Operation operation, Entry entry) {
+ operation.setAttachment(ORIG_AUTH_ENTRY, operation.getAuthorizationEntry());
+ return true;
+ }
+
//Not planned to be implemented methods.
/**
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java
index ef72f64..e5f77dd 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java
@@ -1767,7 +1767,17 @@
break addProcessing;
}
+ if (AccessControlConfigManager.getInstance()
+ .getAccessControlHandler().isProxiedAuthAllowed(this,
+ authorizationEntry) == false) {
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ int msgID = MSGID_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break addProcessing;
+ }
setAuthorizationEntry(authorizationEntry);
}
else if (oid.equals(OID_PROXIED_AUTH_V2))
@@ -1827,7 +1837,17 @@
break addProcessing;
}
+ if (AccessControlConfigManager.getInstance()
+ .getAccessControlHandler().isProxiedAuthAllowed(this,
+ authorizationEntry) == false) {
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ int msgID = MSGID_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break addProcessing;
+ }
setAuthorizationEntry(authorizationEntry);
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java
index ff1843b..09a6f16 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java
@@ -824,7 +824,17 @@
break compareProcessing;
}
+ if (AccessControlConfigManager.getInstance()
+ .getAccessControlHandler().isProxiedAuthAllowed(this,
+ authorizationEntry) == false) {
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break compareProcessing;
+ }
setAuthorizationEntry(authorizationEntry);
}
else if (oid.equals(OID_PROXIED_AUTH_V2))
@@ -884,7 +894,17 @@
break compareProcessing;
}
+ if (AccessControlConfigManager.getInstance()
+ .getAccessControlHandler().isProxiedAuthAllowed(this,
+ authorizationEntry) == false) {
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break compareProcessing;
+ }
setAuthorizationEntry(authorizationEntry);
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlProvider.java b/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlProvider.java
index 9bccfd3..612890e 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlProvider.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlProvider.java
@@ -33,6 +33,7 @@
import org.opends.server.types.InitializationException;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
+import org.opends.server.types.Entry;
/**
* This class implements a default access control provider for the
@@ -197,5 +198,13 @@
return true;
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isProxiedAuthAllowed(Operation operation, Entry entry) {
+ return true;
+ }
}
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DeleteOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/DeleteOperation.java
index 32ac395..906aa35 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DeleteOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/DeleteOperation.java
@@ -817,7 +817,17 @@
break deleteProcessing;
}
+ if (AccessControlConfigManager.getInstance()
+ .getAccessControlHandler().isProxiedAuthAllowed(this,
+ authorizationEntry) == false) {
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ int msgID = MSGID_DELETE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break deleteProcessing;
+ }
setAuthorizationEntry(authorizationEntry);
}
else if (oid.equals(OID_PROXIED_AUTH_V2))
@@ -876,7 +886,17 @@
break deleteProcessing;
}
+ if (AccessControlConfigManager.getInstance()
+ .getAccessControlHandler().isProxiedAuthAllowed(this,
+ authorizationEntry) == false) {
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ int msgID = MSGID_DELETE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break deleteProcessing;
+ }
setAuthorizationEntry(authorizationEntry);
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/ModifyDNOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/ModifyDNOperation.java
index 3b58b7d..0fefd47 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/ModifyDNOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/ModifyDNOperation.java
@@ -1277,7 +1277,17 @@
break modifyDNProcessing;
}
+ if (AccessControlConfigManager.getInstance()
+ .getAccessControlHandler().isProxiedAuthAllowed(this,
+ authorizationEntry) == false) {
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break modifyDNProcessing;
+ }
setAuthorizationEntry(authorizationEntry);
}
else if (oid.equals(OID_PROXIED_AUTH_V2))
@@ -1336,6 +1346,17 @@
break modifyDNProcessing;
}
+ if (AccessControlConfigManager.getInstance()
+ .getAccessControlHandler().isProxiedAuthAllowed(this,
+ authorizationEntry) == false) {
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+
+ int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break modifyDNProcessing;
+ }
setAuthorizationEntry(authorizationEntry);
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java
index 1c9ea1d..58cb53b 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java
@@ -101,6 +101,7 @@
import static org.opends.server.loggers.Error.*;
import static org.opends.server.messages.CoreMessages.*;
import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
@@ -1080,7 +1081,17 @@
break modifyProcessing;
}
+ if (AccessControlConfigManager.getInstance().
+ getAccessControlHandler().isProxiedAuthAllowed(this,
+ authorizationEntry) == false) {
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break modifyProcessing;
+ }
setAuthorizationEntry(authorizationEntry);
}
@@ -1141,7 +1152,17 @@
break modifyProcessing;
}
+ if (AccessControlConfigManager.getInstance().
+ getAccessControlHandler().isProxiedAuthAllowed(this,
+ authorizationEntry) == false) {
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break modifyProcessing;
+ }
setAuthorizationEntry(authorizationEntry);
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java
index 7d4f2f7..d4c3d49 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java
@@ -1758,7 +1758,17 @@
break searchProcessing;
}
+ if (AccessControlConfigManager.getInstance().
+ getAccessControlHandler().isProxiedAuthAllowed(this,
+ authorizationEntry) == false) {
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ int msgID = MSGID_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ appendErrorMessage(getMessage(msgID, String.valueOf(baseDN)));
+
+ skipPostOperation = true;
+ break searchProcessing;
+ }
setAuthorizationEntry(authorizationEntry);
}
else if (oid.equals(OID_PROXIED_AUTH_V2))
@@ -1818,6 +1828,17 @@
break searchProcessing;
}
+ if (AccessControlConfigManager.getInstance()
+ .getAccessControlHandler().isProxiedAuthAllowed(this,
+ authorizationEntry) == false) {
+ setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+
+ int msgID = MSGID_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ appendErrorMessage(getMessage(msgID, String.valueOf(baseDN)));
+
+ skipPostOperation = true;
+ break searchProcessing;
+ }
setAuthorizationEntry(authorizationEntry);
}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
index 7948766..5028fd7 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
@@ -182,6 +182,8 @@
private static final String LEVEL_1_USER_DN = "cn=level1 user," + OU_BASE_DN;
private static final String LEVEL_2_USER_DN = "cn=level2 user," + OU_INNER_DN;
private static final String LEVEL_3_USER_DN = "cn=level3 user," + OU_LEAF_DN;
+ //The proxy DN.
+ private static final String PROXY_USER_DN = "cn=proxy user," + OU_BASE_DN;
// We need to delete all of these between each test. This list needs to be
// bottom up so that it can be handed to LDAPDelete.
@@ -189,6 +191,7 @@
SALES_USER_1,
SALES_USER_2,
SALES_USER_3,
+ PROXY_USER_DN,
LEVEL_3_USER_DN,
LEVEL_2_USER_DN,
LEVEL_1_USER_DN,
@@ -209,6 +212,10 @@
private static final String BIND_RULE_USERDN_ALL = "userdn=\"ldap:///all\"";
private static final String BIND_RULE_USERDN_ADMIN = "userdn=\"ldap:///" + ADMIN_DN + "\"";
private static final String BIND_RULE_USERDN_LEVEL_1 = "userdn=\"ldap:///" + LEVEL_1_USER_DN + "\"";
+ //The proxy userdn bind rule.
+ private static final String BIND_RULE_USERDN_PROXY =
+ "userdn=\"ldap:///" + PROXY_USER_DN + "\"";
+
private static final String BIND_RULE_USERDN_ANYONE = "userdn=\"ldap:///anyone\"";
private static final String BIND_RULE_USERDN_PARENT = "userdn=\"ldap:///parent\"";
private static final String BIND_RULE_USERDN_CN_RDN = "userdn=\"ldap:///CN=*,dc=example,dc=com\"";
@@ -306,6 +313,36 @@
private static final String ALLOW_ALL_TO_COMPARE =
buildAciValue("name", "allow compare", "targetattr", "*", "target", "ldap:///cn=*," + OU_LEAF_DN, "allow(compare)", BIND_RULE_USERDN_ALL);
+ //The ACIs for the proxy tests.
+
+ private static final String ALLOW_PROXY_TO_IMPORT_MGR_NEW =
+ buildAciValue("name", "allow proxy import new mgr new tree", "target",
+ MGR_NEW_DN_URL, "allow(import)", BIND_RULE_USERDN_PROXY);
+
+ private static final String ALLOW_PROXY_TO_IMPORT_MGR=
+ buildAciValue("name", "allow proxy import mgr tree", "target",
+ MGR_DN_URL, "allow(import)", BIND_RULE_USERDN_PROXY);
+
+ private static final String ALLOW_PROXY_TO_EXPORT_MGR_NEW =
+ buildAciValue("name", "allow proxy export new mgr new tree", "target",
+ MGR_NEW_DN_URL, "allow(export)", BIND_RULE_USERDN_PROXY);
+
+ private static final String ALLOW_PROXY_TO_EXPORT_MGR=
+ buildAciValue("name", "allow proxy export mgr tree", "target",
+ MGR_DN_URL, "allow(export)", BIND_RULE_USERDN_PROXY);
+
+ private static final String ALLOW_PROXY_TO_WRITE_RDN_ATTRS=
+ buildAciValue("name", "allow proxy write to RDN attrs", "targetattr",
+ "uid || cn || sn", "allow(write)", BIND_RULE_USERDN_PROXY);
+
+ private static final String ALLOW_PROXY_TO_MOVED_ENTRY =
+ buildAciValue("name", "allow proxy to moved entry", "targetattr", "*",
+ "allow(search,read)", BIND_RULE_USERDN_PROXY);
+
+ private static final String ALLOW_PROXY_TO_LEVEL1 =
+ buildAciValue("name", "allow proxy to userdn level1", "targetattr", "*",
+ "allow(proxy)", BIND_RULE_USERDN_LEVEL_1);
+
private static final String ALLOW_ALL_TO_IMPORT_MGR_NEW =
buildAciValue("name", "allow import mgr new tree", "target", MGR_NEW_DN_URL, "allow(import)", BIND_RULE_USERDN_ALL);
@@ -959,6 +996,8 @@
private static final String LEVEL_1_USER_LDIF__SEARCH_TESTS = makeUserLdif(LEVEL_1_USER_DN, "level1", "user", "pa$$word");
private static final String LEVEL_2_USER_LDIF__SEARCH_TESTS = makeUserLdif(LEVEL_2_USER_DN, "level2", "user", "pa$$word");
private static final String LEVEL_3_USER_LDIF__SEARCH_TESTS = makeUserLdif(LEVEL_3_USER_DN, "level3", "user", "pa$$word");
+ private static final String PROXY_USER_LDIF__SEARCH_TESTS =
+ makeUserLdif(PROXY_USER_DN, "proxy", "user", "pa$$word");
private static final String SALES_USER_1__SEARCH_TESTS =
@@ -1050,7 +1089,7 @@
String SELFWRITE_ACI = makeAddAciLdif(OU_GROUP_1_DN,
ALLOW_ALL_TO_SELFWRITE);
- //ACIs used for modDN tests (export, import)
+ //ACIs used for standard modDN tests (export, import)
private static final String ACI_IMPORT_MGR_NEW =
makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_IMPORT_MGR_NEW);
@@ -1064,12 +1103,35 @@
private static final String ACI_EXPORT_MGR =
makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_EXPORT_MGR);
- private static final String ACI_WRITE_RDN_ATTRS =
+ private static final String ACI_WRITE_RDN_ATTRS =
makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_WRITE_RDN_ATTRS);
- private static final String ACI_MOVED_ENTRY =
+ private static final String ACI_MOVED_ENTRY =
makeAddAciLdif(SALES_USER_1, ALLOW_ALL_TO_MOVED_ENTRY);
+//ACIs used for proxied auth modDN tests
+
+ private static final String ACI_PROXY_IMPORT_MGR_NEW =
+ makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_IMPORT_MGR_NEW);
+
+ private static final String ACI_PROXY_IMPORT_MGR =
+ makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_IMPORT_MGR);
+
+ private static final String ACI_PROXY_EXPORT_MGR_NEW =
+ makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_EXPORT_MGR_NEW);
+
+ private static final String ACI_PROXY_EXPORT_MGR =
+ makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_EXPORT_MGR);
+
+ private static final String ACI_PROXY_WRITE_RDN_ATTRS =
+ makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_WRITE_RDN_ATTRS);
+
+ private static final String ACI_PROXY_LEVEL_1=
+ makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_LEVEL1);
+
+ private static final String ACI_PROXY_MOVED_ENTRY =
+ makeAddAciLdif(SALES_USER_1, ALLOW_PROXY_TO_MOVED_ENTRY);
+
//ACI used in testing the groupdn/roledn bind rule keywords.
private static final
@@ -1116,6 +1178,7 @@
GROUP_1_LDIF__SEARCH_TESTS +
GROUP_2_LDIF__SEARCH_TESTS +
LEVEL_1_USER_LDIF__SEARCH_TESTS +
+ PROXY_USER_LDIF__SEARCH_TESTS +
INNER_OU_FULL_LDIF__SEARCH_TESTS;
private static final String NO_ACIS_LDIF = "";
@@ -1484,6 +1547,7 @@
private static class SingleSearchParams {
private final String _bindDn;
private final String _bindPw;
+ private final String _proxyDN;
private final String _searchBaseDn;
private final String _searchFilter;
private final String _searchScope;
@@ -1491,9 +1555,25 @@
private final String _initialDitLdif;
private final String _aciLdif;
+ public SingleSearchParams(String bindDn, String bindPw, String proxyDN,
+ String searchBaseDn, String searchFilter,
+ String searchScope, String expectedResultsLdif,
+ String initialDitLdif, String aciLdif) {
+ _bindDn = bindDn;
+ _bindPw = bindPw;
+ _proxyDN=proxyDN;
+ _searchBaseDn = searchBaseDn;
+ _searchFilter = searchFilter;
+ _searchScope = searchScope;
+ _expectedResultsLdif = expectedResultsLdif;
+ _initialDitLdif = initialDitLdif;
+ _aciLdif = aciLdif;
+ }
+
public SingleSearchParams(String bindDn, String bindPw, String searchBaseDn, String searchFilter, String searchScope, String expectedResultsLdif, String initialDitLdif, String aciLdif) {
_bindDn = bindDn;
_bindPw = bindPw;
+ _proxyDN = null;
_searchBaseDn = searchBaseDn;
_searchFilter = searchFilter;
_searchScope = searchScope;
@@ -1505,6 +1585,7 @@
public SingleSearchParams(SingleSearchParams that, String initialDitLdif, String aciLdif) {
_bindDn = that._bindDn;
_bindPw = that._bindPw;
+ _proxyDN = null;
_searchBaseDn = that._searchBaseDn;
_searchFilter = that._searchFilter;
_searchScope = that._searchScope;
@@ -1525,6 +1606,16 @@
"-b", _searchBaseDn,
"-s", _searchScope,
_searchFilter};
+ } else if(_proxyDN != null) {
+ return new String[]{
+ "-h", "127.0.0.1",
+ "-p", getServerLdapPort(),
+ "-D", _bindDn,
+ "-w", _bindPw,
+ "-b", _searchBaseDn,
+ "-s", _searchScope,
+ "-Y", "dn:" + _proxyDN,
+ _searchFilter};
} else {
return new String[]{
"-h", "127.0.0.1",
@@ -1659,6 +1750,58 @@
}
}
+
+ /**
+ * Test proxy keyword using modify DN. Exact test as testModDN, except using
+ * proxied authorization for modifies and searches.
+ *
+ * Add a set of ACIs to allow exports, imports and write rights to the
+ * proxy user PROXY_USER_DN. Also add an aci low in the DIT, with search and
+ * read rights to the proxy user. This is ACI is to test the
+ * ACI list after a move has been made. Add an ACI that allows LEVEL_1_USER_DN
+ * proxy authorization rights (proxy).
+ *
+ * Move the subtree binding as LEVEL_1_USER_DN using proxied authorization,
+ * search with base at new DN binding as LEVEL_1_USER_DN proxied
+ * authorization, then move the tree back binding as LEVEL_1_USER_DN using
+ * proxied authorization and lastly re-search with base at orig DN
+ * binding as LEVEL_1_USER_DN using proxied authorization.
+ * @throws Throwable
+ */
+ @Test
+ public void testProxyModDN() throws Throwable {
+ SingleSearchParams userParamOrig = new SingleSearchParams(LEVEL_1_USER_DN,
+ "pa$$word",PROXY_USER_DN, SALES_USER_1,
+ OBJECTCLASS_STAR, SCOPE_BASE,
+ null, null, null);
+ SingleSearchParams userParamNew = new SingleSearchParams(LEVEL_1_USER_DN,
+ "pa$$word",PROXY_USER_DN, SALES_USER_NEW_1,
+ OBJECTCLASS_STAR, SCOPE_BASE,
+ null, null, null);
+ try {
+ addEntries(BASIC_LDIF__GROUP_SEARCH_TESTS, DIR_MGR_DN, DIR_MGR_PW);
+ modEntries(ACI_PROXY_IMPORT_MGR, DIR_MGR_DN, DIR_MGR_PW);
+ modEntries(ACI_PROXY_IMPORT_MGR_NEW, DIR_MGR_DN, DIR_MGR_PW);
+ modEntries(ACI_PROXY_EXPORT_MGR, DIR_MGR_DN, DIR_MGR_PW);
+ modEntries(ACI_PROXY_EXPORT_MGR_NEW, DIR_MGR_DN, DIR_MGR_PW);
+ modEntries(ACI_PROXY_WRITE_RDN_ATTRS, DIR_MGR_DN, DIR_MGR_PW);
+ modEntries(ACI_PROXY_MOVED_ENTRY, DIR_MGR_DN, DIR_MGR_PW);
+ modEntries(ACI_PROXY_LEVEL_1, DIR_MGR_DN, DIR_MGR_PW);
+ String modrdnLdif =
+ makeModDN(SALES_DN, "cn=sales dept", "0", MANAGER_NEW_DN);
+ modEntries(modrdnLdif, LEVEL_1_USER_DN, "pa$$word", PROXY_USER_DN);
+ String userNewResults = ldapSearch(userParamNew.getLdapSearchArgs());
+ Assert.assertFalse(userNewResults.equals(""));
+ String modrdnLdif1 =
+ makeModDN(SALES_NEW_DN, "cn=sales dept", "0", MANAGER_DN);
+ modEntries(modrdnLdif1, LEVEL_1_USER_DN, "pa$$word", PROXY_USER_DN);
+ String userOrigResults = ldapSearch(userParamOrig.getLdapSearchArgs());
+ Assert.assertFalse(userOrigResults.equals(""));
+ } catch (Throwable e) {
+ throw e;
+ }
+ }
+
/**
* Test modify DN. Add a set of ACIs to allow exports, imports and write
* rights. Also add an aci low in the DIT to test the ACI list after a move
@@ -1997,20 +2140,22 @@
Assert.assertEquals(0, retVal, "Non-zero return code because, error: " + getOutputStreamContents());
return getOutputStreamContents();
}
- /**
- *
- */
+
private void
modEntries(String ldif, String bindDn, String bindPassword)
throws Exception {
- modEntries(ldif, bindDn, bindPassword, true, false);
+ modEntries(ldif, bindDn, bindPassword, null, true, false);
}
- /**
- *
- */
- private void modEntriesExpectFailure(String ldif, String bindDn, String bindPassword) throws Exception {
- modEntries(ldif, bindDn, bindPassword, false, false);
+ private void
+ modEntries(String ldif, String bindDn, String bindPassword, String proxyDN)
+ throws Exception {
+ modEntries(ldif, bindDn, bindPassword, proxyDN, true, false);
+ }
+
+ private void modEntriesExpectFailure(String ldif, String bindDn,
+ String bindPassword) throws Exception {
+ modEntries(ldif, bindDn, bindPassword, null, false, false);
}
private void _modEntries(String ldif, String bindDn, String bindPassword,
@@ -2031,7 +2176,8 @@
}
private void modEntries(String ldif, String bindDn, String bindPassword,
- boolean expectSuccess, boolean contFlag)
+ String proxyDN, boolean expectSuccess,
+ boolean contFlag)
throws Exception {
File tempFile = getTemporaryLdifFile();
TestCaseUtils.writeFile(tempFile, ldif);
@@ -2048,6 +2194,10 @@
argList.add(tempFile.getAbsolutePath());
if(contFlag)
argList.add("-c");
+ if(proxyDN != null) {
+ argList.add("-Y");
+ argList.add("dn:" + proxyDN);
+ }
String[] args = new String[argList.size()];
ldapModify(argList.toArray(args), expectSuccess);
}
@@ -2065,7 +2215,7 @@
"changetype: modify",
"delete: " + attr,
attr + ":" + val));
- modEntries(ldif.toString(), bindDN, pwd, errorOk, false);
+ modEntries(ldif.toString(), bindDN, pwd, null, errorOk, false);
}
@@ -2090,7 +2240,7 @@
"dn: " + dn,
"changetype: modify",
"delete: " + attr));
- modEntries(ldif.toString(), DIR_MGR_DN, DIR_MGR_PW, errorOk, false);
+ modEntries(ldif.toString(), DIR_MGR_DN, DIR_MGR_PW, null, errorOk, false);
}
private void deleteEntries(String[] entries) throws Exception {
@@ -2102,7 +2252,7 @@
"changetype: delete"
));
}
- modEntries(ldif.toString(), DIR_MGR_DN, DIR_MGR_PW, true, true);
+ modEntries(ldif.toString(), DIR_MGR_DN, DIR_MGR_PW, null, true, true);
}
/**
@@ -2214,7 +2364,8 @@
"cn: " + cn,
"sn: " + sn,
"givenName: " + givenName,
- "userpassword: " + password);
+ "userpassword: " + password,
+ "ds-privilege-name: proxied-auth");
}
private static String makeUserLdif(String dn, String givenName, String sn,
--
Gitblit v1.10.0