From d048be119faafbb9d83bb2f0f8995d6070b16d52 Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Mon, 01 Dec 2008 19:16:36 +0000
Subject: [PATCH] These changes implement a new ACI bind rule keyword "ssf". This keyword allows users to control the level of access based on the security level of the connection.
---
opends/src/server/org/opends/server/extensions/SASLSecurityProvider.java | 10
opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java | 9
opends/src/server/org/opends/server/extensions/SASLContext.java | 102 ++++---
opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java | 7
opends/src/server/org/opends/server/api/ConnectionSecurityProvider.java | 7
opends/src/server/org/opends/server/extensions/TLSConnectionSecurityProvider.java | 51 +++
opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/SSFTestCase.java | 294 ++++++++++++++++++++++
opends/src/messages/messages/access_control.properties | 9
opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java | 5
opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java | 91 ++++--
opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java | 36 ++
opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java | 7
opends/src/server/org/opends/server/authorization/dseecompat/SSF.java | 120 +++++++++
opends/src/server/org/opends/server/extensions/NullConnectionSecurityProvider.java | 8
14 files changed, 669 insertions(+), 87 deletions(-)
diff --git a/opends/src/messages/messages/access_control.properties b/opends/src/messages/messages/access_control.properties
index b5d7767..d22b932 100644
--- a/opends/src/messages/messages/access_control.properties
+++ b/opends/src/messages/messages/access_control.properties
@@ -364,3 +364,12 @@
SEVERE_WARN_ACI_ATTRIBUTE_NOT_INDEXED_96=Backend %s does not have a \
presence index defined for attribute type %s. Access control initialization \
may take a very long time to complete in this backend
+ SEVERE_WARN_ACI_SYNTAX_INVALID_SSF_FORMAT_97=The provided Access Control \
+ Instruction (ACI) bind rule SSF expression "%s" failed to parse for \
+ the following reason: "%s"
+ SEVERE_WARN_ACI_SYNTAX_INVALID_SSF_RANGE_98=The provided Access Control \
+ Instruction (ACI) bind rule ssf expression value "%s" is not in the \
+ valid range. A valid ssf value is in the range of 1 to 1024
+ SEVERE_WARN_ACI_SYNTAX_INVALID_TIMEOFDAY_FORMAT_99=The provided Access Control \
+ Instruction (ACI) bind rule timeofday expression "%s" failed to parse for \
+ the following reason: "%s"
diff --git a/opends/src/server/org/opends/server/api/ConnectionSecurityProvider.java b/opends/src/server/org/opends/server/api/ConnectionSecurityProvider.java
index a2a510d..e7f4ca5 100644
--- a/opends/src/server/org/opends/server/api/ConnectionSecurityProvider.java
+++ b/opends/src/server/org/opends/server/api/ConnectionSecurityProvider.java
@@ -223,5 +223,12 @@
* already disconnected the client.
*/
public abstract boolean writeData(ByteBuffer clearData);
+
+ /**
+ * Return the Security Strength Factor.
+ *
+ * @return The SSF.
+ */
+ public abstract int getSSF();
}
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
index b661486..6a9c7b0 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -980,4 +980,11 @@
else
evalAllAttributes &= ~v;
}
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getCurrentSSF() {
+ return clientConnection.getConnectionSecurityProvider().getSSF();
+ }
}
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java
index e9b437c..ec47623 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java
@@ -87,7 +87,7 @@
/**
* Check if the remote client is bound anonymously.
- * @return True if client is bound anonymously.
+ * @return {@code true} if client is bound anonymously.
*/
public boolean isAnonymousUser();
@@ -118,6 +118,7 @@
* @param authMethod The required authentication method.
* @param saslMech The required SASL mechanism if the authentication method
* is SASL.
+ *
* @return An evaluation result indicating whether the client connection
* has been authenticated using the required authentication method.
*/
@@ -126,14 +127,15 @@
/**
* Get the address of the bound connection.
- * @return The address of the bound connection.
+ * @return The address of the bound connection.
*/
public InetAddress getRemoteAddress();
/**
- * Return true if this is an add operation, needed by the userattr
+ * Return true if this is an add operation needed by the userattr
* USERDN parent inheritance level 0 processing.
- * @return True if this is an add operation.
+ *
+ * @return {@code true} if this is an add operation.
*/
public boolean isAddOperation();
@@ -143,60 +145,61 @@
* ClientConnection.isMemberOf() method, which checks authorization
* DN membership in the specified group.
* @param group The group to check membership in.
- * @return True if the authorization DN of the operation is a
+ * @return {@code true} if the authorization DN of the operation is a
* member of the specified group.
*/
public boolean isMemberOf(Group<?> group);
/**
* Returns true if the hashtable of ACIs that matched the targattrfilters
- * keyword evaluation is empty. Used by geteffectiverights evaluation to
- * determine the access value to put in the "write" rights evaluation field.
+ * keyword evaluation is empty. Used in a geteffectiverights control
+ * evaluation to determine the access value to put in the "write" rights
+ * evaluation field.
*
- * @return True if there were not any ACIs that matched targattrfilters
- * keyword evaluation.
+ * @return {@code true} if there were not any ACIs that matched
+ * targattrfilters keyword evaluation.
*/
public boolean isTargAttrFilterMatchAciEmpty();
/**
* The context maintains a hashtable of ACIs that matched the targattrfilters
* keyword evaluation. The hasTargAttrFiltersMatchAci method returns true if
- * the specified ACI is contained in that hashtable. Used by
- * geteffectiverights evaluation to determine the access value to put in the
- * "write" rights evaluation field.
+ * the specified ACI is contained in that hashtable. Used in a
+ * geteffectiverights control evaluation to determine the access value to put
+ * in the "write" rights evaluation field.
*
* @param aci The ACI that to evaluate if it contains a match during
* targattrfilters keyword evaluation.
*
- * @return True if a specified ACI matched targattrfilters evaluation.
+ * @return {@code true} if a specified ACI matched targattrfilters evaluation.
*/
public boolean hasTargAttrFiltersMatchAci(Aci aci);
/**
* Return true if an ACI that evaluated to deny or allow has an
- * targattrfilters keyword. Used by geteffectiverights
+ * targattrfilters keyword. Used by geteffectiverights control
* evaluation to determine the access value to put in the "write" rights
* evaluation field.
*
* @param flag The integer value specifying either a deny or allow, but not
* both.
*
- * @return True if the ACI that evaluated to
+ * @return {@code true} if the ACI has an targetattrfilters keyword.
*/
public boolean hasTargAttrFiltersMatchOp(int flag);
/**
- * Returns true if the evaluation context is being used in a
- * geteffectiverights evaluation.
+ * Returns {@code true} if the evaluation context is being used in a
+ * geteffectiverights control evaluation.
*
- * @return True if the evaluation context is being used in a
- * geteffectiverights evaluation.
+ * @return {@code true} if the evaluation context is being used in a
+ * geteffectiverights control evaluation.
*/
public boolean isGetEffectiveRightsEval();
/**
* Set the name of the ACI that last matched a targattrfilters rule. Used
- * in geteffectiverights targattrfilters "write" rights evaluation.
+ * in geteffectiverights control targattrfilters "write" evaluation.
*
* @param name The ACI name string matching the targattrfilters rule.
*/
@@ -205,8 +208,8 @@
/**
* Set a flag that specifies that a ACI that evaluated to either deny or
* allow contains a targattrfilters keyword. Used by geteffectiverights
- * evaluation to determine the access value to put in the "write" rights
- * evaluation field.
+ * control evaluation to determine the access value to put in the "write"
+ * rights evaluation field.
*
* @param flag Either the integer value representing an allow or a deny,
* but not both.
@@ -215,7 +218,7 @@
/**
* Set the reason the last access evaluation was evaluated the way it
- * was. Used by geteffectiverights evaluation to eventually build the
+ * was. Used by geteffectiverights control evaluation to eventually build the
* summary string.
*
* @param reason The enumeration representing the reason of the last access
@@ -225,7 +228,8 @@
/**
* Return the reason the last access evaluation was evaluated the way it
- * was. Used by geteffectiverights evaluation to build the summary string.
+ * was. Used by geteffectiverights control evaluation to build the summary
+ * string.
*
* @return The enumeration representing the reason of the last access
* evaluation.
@@ -234,7 +238,7 @@
/**
* Set the ACI that decided that last access evaluation. Used by
- * geteffectiverights evaluation to the build summary string.
+ * geteffectiverights control evaluation to the build summary string.
*
* @param aci The ACI that decided the last access evaluation.
*/
@@ -245,13 +249,13 @@
*
* @param rights The rights mask to check.
*
- * @return True if the evaluation context contains a access right set.
+ * @return {@code true} if the evaluation context contains a access right set.
*/
public boolean hasRights(int rights);
/**
* Return the name of the ACI that decided the last access evaluation. Used
- * by geteffectiverights evaluation to build the summmary string.
+ * by geteffectiverights control evaluation to build the summary string.
*
* @return The name of the ACI that decided the last access evaluation.
*/
@@ -259,10 +263,10 @@
/**
* Return true if a evaluation context is being used in proxied authorization
- * evaluation.
+ * control evaluation.
*
- * @return True if evaluation context is being used in proxied authorization
- * evaluation.
+ * @return {@code true} if evaluation context is being used in proxied
+ * authorization control evaluation.
*/
public boolean isProxiedAuthorization();
@@ -275,15 +279,16 @@
/**
* Set the value of the summary string to the specified string.
- * Used in geteffectiverights evaluation to build summary string.
+ * Used in get effective rights evaluation to build summary string.
*
* @param summary The string to set the summary string to
*/
public void setEvalSummary(String summary);
/**
- * Return the access evaluation summary string. Used by the geteffectiverights
- * evaluation when a aclRightsInfo attribute was specified in a search.
+ * Return the access evaluation summary string. Used in a geteffectiverights
+ * control evaluation when an aclRightsInfo attribute was specified in a
+ * search request.
*
* @return The string describing the access evaluation.
*/
@@ -291,7 +296,7 @@
/**
* Return a string representation of the current right being evaluated.
- * Used in geteffectiverights evaluation to build summary string.
+ * Used in geteffectiverights control evaluation to build summary string.
*
* @return String representation of the current right being evaluated.
*/
@@ -299,9 +304,9 @@
/**
* Return the name of the ACI that last matched a targattrfilters rule. Used
- * in geteffectiverights evaluation.
+ * in geteffectiverights control evaluation.
*
- * @return The name of the ACI that last matched a targattrfilters rule.
+ * @return The name of the ACI that last matched a targattrfilters rule.
*/
public String getTargAttrFiltersAciName();
@@ -315,9 +320,19 @@
* This method is used to replace the current resource entry with that saved
* entry and back.
*
- * @param val Specifies if the saved entry should be used or not. True if it
- * should be used, false if the original resource entry should be used.
+ * @param val Specifies if the saved entry should be used or not. {@code true}
+ * if it should be used, {@code false} if the original resource entry should
+ * be used.
*
*/
public void useFullResourceEntry(boolean val);
+
+
+ /**
+ * Return the current SSF (Security Strength Factor) of the underlying
+ * connection.
+ *
+ * @return The current SSF of the connection.
+ */
+ public int getCurrentSSF();
}
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java b/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java
index 8ab34e6..18e3611 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java
@@ -534,6 +534,11 @@
rule = UserAttr.decode(expr, op);
break;
}
+ case SSF:
+ {
+ rule = SSF.decode(expr, op);
+ break;
+ }
default: {
Message message = WARN_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD.get(
keyword.toString());
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java b/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java
index e645fe2..5772743 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java
@@ -77,7 +77,12 @@
* The enumeration type when the bind rule has specified keyword of
* authmethod.
*/
- AUTHMETHOD ("authmethod");
+ AUTHMETHOD ("authmethod"),
+ /**
+ * The enumeration type when the bind rule has specified keyword of
+ * ssf.
+ */
+ SSF("ssf");
/*
* The keyword name.
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/SSF.java b/opends/src/server/org/opends/server/authorization/dseecompat/SSF.java
new file mode 100644
index 0000000..0f227b2
--- /dev/null
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/SSF.java
@@ -0,0 +1,120 @@
+/*
+ * 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
+ *
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.authorization.dseecompat;
+
+import org.opends.messages.Message;
+import static org.opends.messages.AccessControlMessages.*;
+
+/**
+ * The class represents the ssf keyword in a bind rule.SSF stands for
+ * security strength factor.
+ *
+ */
+public class SSF implements KeywordBindRule {
+
+ /*
+ * Enumeration representing the bind rule operation type.
+ */
+ private EnumBindRuleType type=null;
+
+ private static final int MAX_KEY_BITS=1024;
+ private int ssf;
+
+ private SSF(int ssf, EnumBindRuleType type) {
+ this.ssf = ssf;
+ this.type = type;
+ }
+
+ /**
+ * Create SSF instance using the specified expression string and bind rule
+ * type enumeration.
+ * @param expr The expression string.
+ * @param type The bind rule type enumeration.
+ * @return A SSF instance.
+ * @throws AciException If the SSF instance cannot be created.
+ */
+ static SSF
+ decode(String expr, EnumBindRuleType type) throws AciException {
+ int valueAsInt = 0;
+ try {
+ valueAsInt = Integer.parseInt(expr);
+ } catch (NumberFormatException nfe) {
+ Message message =
+ WARN_ACI_SYNTAX_INVALID_SSF_FORMAT.get(expr, nfe.getMessage());
+ throw new AciException(message);
+ }
+ if ((valueAsInt <= 0) || (valueAsInt > MAX_KEY_BITS)) {
+ Message message = WARN_ACI_SYNTAX_INVALID_SSF_RANGE.get(expr);
+ throw new AciException(message);
+ }
+ return new SSF(valueAsInt, type);
+ }
+
+ /**
+ * Evaluate the specified evaluation context.
+ * @param evalCtx The evaluation context to evaluate.
+ *
+ * @return An evaluation result enumeration containing the result of the
+ * context evaluation.
+ */
+ public EnumEvalResult evaluate(AciEvalContext evalCtx) {
+ EnumEvalResult matched=EnumEvalResult.FALSE;
+ int currentSSF = evalCtx.getCurrentSSF();
+ switch (type) {
+ case EQUAL_BINDRULE_TYPE:
+ if (currentSSF == ssf)
+ matched=EnumEvalResult.TRUE;
+ break;
+
+ case NOT_EQUAL_BINDRULE_TYPE:
+ if (currentSSF != ssf)
+ matched=EnumEvalResult.TRUE;
+ break;
+
+ case LESS_OR_EQUAL_BINDRULE_TYPE:
+ if (currentSSF <= ssf)
+ matched=EnumEvalResult.TRUE;
+ break;
+
+ case LESS_BINDRULE_TYPE:
+ if (currentSSF < ssf)
+ matched=EnumEvalResult.TRUE;
+ break;
+
+ case GREATER_OR_EQUAL_BINDRULE_TYPE:
+ if (currentSSF >= ssf)
+ matched=EnumEvalResult.TRUE;
+ break;
+
+ case GREATER_BINDRULE_TYPE:
+ if (currentSSF > ssf)
+ matched=EnumEvalResult.TRUE;
+ }
+ return matched.getRet(type, false);
+ }
+}
\ No newline at end of file
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java b/opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java
index 6d62ccf..4a7358f 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java
@@ -71,12 +71,19 @@
*/
public static TimeOfDay decode(String expr, EnumBindRuleType type)
throws AciException {
+ int valueAsInt = 0;
if (!Pattern.matches(timeofdayRegex, expr))
{
Message message = WARN_ACI_SYNTAX_INVALID_TIMEOFDAY.get(expr);
throw new AciException(message);
}
- int valueAsInt = Integer.parseInt(expr);
+ try {
+ valueAsInt = Integer.parseInt(expr);
+ } catch (NumberFormatException nfe) {
+ Message message =
+ WARN_ACI_SYNTAX_INVALID_TIMEOFDAY_FORMAT.get(expr, nfe.getMessage());
+ throw new AciException(message);
+ }
if ((valueAsInt < 0) || (valueAsInt > 2359))
{
Message message = WARN_ACI_SYNTAX_INVALID_TIMEOFDAY_RANGE.get(expr);
diff --git a/opends/src/server/org/opends/server/extensions/NullConnectionSecurityProvider.java b/opends/src/server/org/opends/server/extensions/NullConnectionSecurityProvider.java
index 0aa9ae0..3563114 100644
--- a/opends/src/server/org/opends/server/extensions/NullConnectionSecurityProvider.java
+++ b/opends/src/server/org/opends/server/extensions/NullConnectionSecurityProvider.java
@@ -498,5 +498,13 @@
}
}
}
+
+ /**
+ * Always returns 0, there is no cipher used.
+ * @return Returns 0 always.
+ */
+ public int getSSF() {
+ return 0;
+ }
}
diff --git a/opends/src/server/org/opends/server/extensions/SASLContext.java b/opends/src/server/org/opends/server/extensions/SASLContext.java
index 2ccc27f..c4ba120 100644
--- a/opends/src/server/org/opends/server/extensions/SASLContext.java
+++ b/opends/src/server/org/opends/server/extensions/SASLContext.java
@@ -86,7 +86,7 @@
private String serverFQDN;
//The SASL mechanism name.
- private final String mech;
+ private final String mechanism;
//The authorization entry used in the authentication.
private Entry authEntry=null;
@@ -116,19 +116,19 @@
* @param saslProps The properties to use in creating the SASL server.
* @param serverFQDN The fully qualified domain name to use in creating the
* SASL server.
- * @param mech The SASL mechanism name.
+ * @param mechanism The SASL mechanism name.
* @param identityMapper The identity mapper to use in mapping identities.
*
* @throws SaslException If the SASL server can not be instantiated.
*/
private SASLContext(HashMap<String, String>saslProps, String serverFQDN,
- String mech, IdentityMapper<?> identityMapper)
+ String mechanism, IdentityMapper<?> identityMapper)
throws SaslException {
this.identityMapper = identityMapper;
- this.mech = mech;
+ this.mechanism = mechanism;
this.saslProps = saslProps;
this.serverFQDN = serverFQDN;
- if(mech.equals(SASL_MECHANISM_DIGEST_MD5)) {
+ if(mechanism.equals(SASL_MECHANISM_DIGEST_MD5)) {
initSASLServer();
}
}
@@ -141,7 +141,7 @@
* @param saslProps The properties to use in creating the SASL server.
* @param serverFQDN The fully qualified domain name to use in creating the
* SASL server.
- * @param mech The SASL mechanism name.
+ * @param mechanism The SASL mechanism name.
* @param identityMapper The identity mapper to use in mapping identities.
* @return A fully instantiated SASL context to use in processing a SASL
* bind for the GSSAPI or DIGEST-MD5 mechanisms.
@@ -150,21 +150,19 @@
*/
public static
SASLContext createSASLContext(HashMap<String,String>saslProps,
- String serverFQDN, String mech,
+ String serverFQDN, String mechanism,
IdentityMapper<?> identityMapper) throws SaslException {
- return (new SASLContext(saslProps,serverFQDN, mech, identityMapper));
+ return (new SASLContext(saslProps,serverFQDN, mechanism, identityMapper));
}
/**
* Initialize the SASL server using parameters specified in the
* constructor.
- *
- * @throws SaslException If the SASL server can not be instantiated.
*/
private void initSASLServer() throws SaslException {
- this.saslServer = Sasl.createSaslServer(mech, SASL_DEFAULT_PROTOCOL,
- serverFQDN, saslProps, this);
+ this.saslServer = Sasl.createSaslServer(mechanism, SASL_DEFAULT_PROTOCOL,
+ serverFQDN, saslProps, this);
}
@@ -189,7 +187,7 @@
/**
* Unwrap the specified byte array using the provided offset and length
* values. Used only when the SASL server has negotiated
- * confidentiality/integrity processing.
+ * confidentiality or integrity processing.
*
* @param bytes The byte array to unwrap.
* @param offset The offset in the array.
@@ -230,15 +228,38 @@
return Integer.parseInt(sizeStr);
}
+ /**
+ * Return the Security Strength Factor of the cipher if the QOP property
+ * is confidentiality, or, 1 if it is integrity.
+ *
+ * @return The SSF of the cipher used during confidentiality or
+ * integrity processing.
+ */
+ int getSSF() {
+ int ssf = 0;
+ String qop = (String) saslServer.getNegotiatedProperty(Sasl.QOP);
+ if(qop.equalsIgnoreCase(integrity)) {
+ ssf = 1;
+ } else {
+ String negStrength =
+ (String) saslServer.getNegotiatedProperty(Sasl.STRENGTH);
+ if(negStrength.equalsIgnoreCase("low"))
+ ssf = 40;
+ else if (negStrength.equalsIgnoreCase("medium"))
+ ssf = 56;
+ else
+ ssf = 128;
+ }
+ return ssf;
+ }
/**
- * Return true if the bind has been completed. If the context is supporting
- * confidentiality/integrity, the security provider will need to check
- * if the context has completed its handshakes with the client and is
- * ready to process confidentiality/integrity messages.
+ * Return {@code true} if the bind has been completed. If the context is
+ * supporting confidentiality or integrity, the security provider will need
+ * to check if the context has completed the handshake with the client
+ * and is ready to process confidentiality or integrity messages.
*
- * @return {@code true} if the handshaking is complete,
- * {@code false} if further handshaking is needed.
+ * @return {@code true} if the handshaking is complete.
*/
boolean isBindComplete() {
return saslServer.isComplete();
@@ -247,10 +268,10 @@
/**
* Return true if the SASL server has negotiated with the client to support
- * confidentiality/integrity.
+ * confidentiality or integrity.
*
- * @return {@code true} if the context support
- * confidentiality/integrity, or, {@code false} otherwise.
+ * @return {@code true} if the context supports confidentiality or
+ * integrity.
*/
private boolean isConfidentialIntegrity() {
boolean ret = false;
@@ -312,7 +333,7 @@
*
* @param authInfo The authentication information to use in the check.
* @return {@code true} if the authentication information has
- * PROXIED_AUTH privileges, {@code false} otherwise.
+ * PROXIED_AUTH privileges.
*/
private boolean
hasPrivilege(AuthenticationInfo authInfo) {
@@ -334,7 +355,7 @@
*
* @param authInfo The authentication information to check access on.
* @return {@code true} if the authentication information has
- * proxy access, {@code false} otherwise.
+ * proxy access.
*/
private boolean
hasPermission(AuthenticationInfo authInfo) {
@@ -388,7 +409,7 @@
authorizeCallback((AuthorizeCallback) callback);
} else {
Message message =
- INFO_SASL_UNSUPPORTED_CALLBACK.get(mech,
+ INFO_SASL_UNSUPPORTED_CALLBACK.get(mechanism,
String.valueOf(callback));
throw new UnsupportedCallbackException(callback,
message.toString());
@@ -586,7 +607,7 @@
clearPasswords = pwPolicyState.getClearPasswords();
if ((clearPasswords == null) || clearPasswords.isEmpty()) {
setCallbackMsg(
- ERR_SASL_NO_REVERSIBLE_PASSWORDS.get(mech,
+ ERR_SASL_NO_REVERSIBLE_PASSWORDS.get(mechanism,
String.valueOf(authEntry.getDN())));
return;
}
@@ -596,7 +617,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
setCallbackMsg(ERR_SASL_CANNOT_GET_REVERSIBLE_PASSWORDS.get(
- String.valueOf(authEntry.getDN()),mech,
+ String.valueOf(authEntry.getDN()),mechanism,
String.valueOf(e)));
return;
}
@@ -625,13 +646,13 @@
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
setCallbackMsg(ERR_SASL_CANNOT_DECODE_USERNAME_AS_DN.get(
- mech,
+ mechanism,
userName, e.getMessageObject()));
return;
}
if (userDN.isNullDN()) {
setCallbackMsg(ERR_SASL_USERNAME_IS_NULL_DN.get(
- mech));
+ mechanism));
return;
}
DN rootDN = DirectoryServer.getActualRootBindDN(userDN);
@@ -646,7 +667,7 @@
if (lowerUserName.startsWith("u:")) {
if (lowerUserName.equals("u:")) {
setCallbackMsg(ERR_SASL_ZERO_LENGTH_USERNAME.get(
- mech,mech));
+ mechanism,mechanism));
return;
}
entryID = userName.substring(2);
@@ -707,8 +728,7 @@
* The method performs all GSSAPI processing. It is run as the context of
* the login context performed by the GSSAPI mechanism handler. See comments
* for processing overview.
- * @return {@code true} if the authentication processing was successful,
- * or, {@code false} otherwise.
+ * @return {@code true} if the authentication processing was successful.
*/
public Boolean run() {
ClientConnection clientConn = bindOp.getClientConnection();
@@ -751,7 +771,7 @@
bindOp.setSASLAuthUserEntry(authEntry);
AuthenticationInfo authInfo =
new AuthenticationInfo(authEntry, authzEntry,
- mech,
+ mechanism,
DirectoryServer.isRootDN(authEntry.getDN()));
bindOp.setAuthenticationInfo(authInfo);
//If confidentiality/integrity has been negotiated then
@@ -760,7 +780,7 @@
//negotiated, dispose of the SASL server.
if(isConfidentialIntegrity()) {
SASLSecurityProvider secProvider =
- new SASLSecurityProvider(clientConn, mech, this);
+ new SASLSecurityProvider(clientConn, mechanism, this);
LDAPClientConnection ldapConn =
(LDAPClientConnection) clientConn;
ldapConn.setSASLConnectionSecurityProvider(secProvider);
@@ -778,7 +798,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
Message msg =
- ERR_SASL_PROTOCOL_ERROR.get(mech, getExceptionMessage(e));
+ ERR_SASL_PROTOCOL_ERROR.get(mechanism, getExceptionMessage(e));
handleError(msg);
return false;
}
@@ -806,7 +826,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
Message msg =
- ERR_SASL_PROTOCOL_ERROR.get(mech, getExceptionMessage(e));
+ ERR_SASL_PROTOCOL_ERROR.get(mechanism, getExceptionMessage(e));
handleError(msg);
}
}
@@ -832,7 +852,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
Message msg =
- ERR_SASL_PROTOCOL_ERROR.get(mech,getExceptionMessage(e));
+ ERR_SASL_PROTOCOL_ERROR.get(mechanism,getExceptionMessage(e));
handleError(msg);
}
}
@@ -850,7 +870,7 @@
if ((clientCredentials == null) ||
(clientCredentials.value().length == 0)) {
Message msg =
- ERR_SASL_NO_CREDENTIALS.get(mech, mech);
+ ERR_SASL_NO_CREDENTIALS.get(mechanism, mechanism);
handleError(msg);
return;
}
@@ -866,7 +886,7 @@
bindOp.setSASLAuthUserEntry(authEntry);
AuthenticationInfo authInfo =
new AuthenticationInfo(authEntry, authzEntry,
- mech,
+ mechanism,
DirectoryServer.isRootDN(authEntry.getDN()));
bindOp.setAuthenticationInfo(authInfo);
//If confidentiality/integrity has been negotiated, then create a
@@ -874,7 +894,7 @@
//use in later processing.
if(isConfidentialIntegrity()) {
SASLSecurityProvider secProvider =
- new SASLSecurityProvider(clientConn, mech, this);
+ new SASLSecurityProvider(clientConn, mechanism, this);
LDAPClientConnection ldapConn =
(LDAPClientConnection) clientConn;
ldapConn.setSASLConnectionSecurityProvider(secProvider);
@@ -887,7 +907,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
Message msg =
- ERR_SASL_PROTOCOL_ERROR.get(mech, getExceptionMessage(e));
+ ERR_SASL_PROTOCOL_ERROR.get(mechanism, getExceptionMessage(e));
handleError(msg);
}
}
diff --git a/opends/src/server/org/opends/server/extensions/SASLSecurityProvider.java b/opends/src/server/org/opends/server/extensions/SASLSecurityProvider.java
index 0ee7e0c..64a64b7 100644
--- a/opends/src/server/org/opends/server/extensions/SASLSecurityProvider.java
+++ b/opends/src/server/org/opends/server/extensions/SASLSecurityProvider.java
@@ -454,4 +454,14 @@
public boolean isActive() {
return saslContext.isBindComplete();
}
+
+ /**
+ * Return the cipher Security Strength Function of the cipher used in the
+ * SSAL context.
+ *
+ * @return The cipher SSF of the cipher used in the SASL context.
+ */
+ public int getSSF() {
+ return saslContext.getSSF();
+ }
}
diff --git a/opends/src/server/org/opends/server/extensions/TLSConnectionSecurityProvider.java b/opends/src/server/org/opends/server/extensions/TLSConnectionSecurityProvider.java
index 7b26abc..9b99eaa 100644
--- a/opends/src/server/org/opends/server/extensions/TLSConnectionSecurityProvider.java
+++ b/opends/src/server/org/opends/server/extensions/TLSConnectionSecurityProvider.java
@@ -34,6 +34,8 @@
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.security.cert.Certificate;
+import java.util.LinkedHashMap;
+import java.util.Map;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
@@ -76,16 +78,12 @@
*/
private static final DebugTracer TRACER = getTracer();
-
-
/**
* The SSL context name that should be used for this TLS connection security
* provider.
*/
private static final String SSL_CONTEXT_INSTANCE_NAME = "TLS";
-
-
// The buffer that will be used when reading clear-text data.
private ByteBuffer clearInBuffer;
@@ -127,6 +125,27 @@
// The set of protocols to allow.
private String[] enabledProtocols;
+ //Map of cipher phrases to effective key size (bits). Taken from the
+ //following RFCs: 5289, 4346, 3268,4132 and 4162.
+ private static final Map<String, Integer> cipherMap;
+
+ static {
+ cipherMap = new LinkedHashMap<String, Integer>();
+ cipherMap.put("_WITH_AES_256_CBC_", new Integer(256));
+ cipherMap.put("_WITH_CAMELLIA_256_CBC_", new Integer(256));
+ cipherMap.put("_WITH_AES_256_GCM_", new Integer(256));
+ cipherMap.put("_WITH_3DES_EDE_CBC_", new Integer(168));
+ cipherMap.put("_WITH_AES_128_GCM_", new Integer(128));
+ cipherMap.put("_WITH_SEED_CBC_", new Integer(128));
+ cipherMap.put("_WITH_CAMELLIA_128_CBC_", new Integer(128));
+ cipherMap.put("_WITH_AES_128_CBC_", new Integer(128));
+ cipherMap.put("_WITH_IDEA_CBC_", new Integer(128));
+ cipherMap.put("_WITH_DES_CBC_", new Integer(56));
+ cipherMap.put("_WITH_RC2_CBC_40_", new Integer(40));
+ cipherMap.put("_WITH_RC4_40_", new Integer(40));
+ cipherMap.put("_WITH_DES40_CBC_", new Integer(40));
+ cipherMap.put("_WITH_NULL_", new Integer(0));
+ };
/**
@@ -175,7 +194,7 @@
// Create an SSL session based on the configured key and trust stores in the
// Directory Server.
- KeyManagerProvider keyManagerProvider =
+ KeyManagerProvider<?> keyManagerProvider =
DirectoryServer.getKeyManagerProvider(
clientConnection.getKeyManagerProviderDN());
if (keyManagerProvider == null)
@@ -183,7 +202,7 @@
keyManagerProvider = new NullKeyManagerProvider();
}
- TrustManagerProvider trustManagerProvider =
+ TrustManagerProvider<?> trustManagerProvider =
DirectoryServer.getTrustManagerProvider(
clientConnection.getTrustManagerProviderDN());
if (trustManagerProvider == null)
@@ -1039,5 +1058,25 @@
return null;
}
}
+
+
+ /**
+ * Return the Security Strength FActor of the cipher used in the current
+ * TLS session.
+ *
+ * @return The cipher SSF used in the current TLS session.
+ */
+
+ public int getSSF() {
+ int cipherKeySSF = 0;
+ String cipherString = sslEngine.getSession().getCipherSuite();
+ for(Map.Entry<String, Integer> mapEntry : cipherMap.entrySet()) {
+ if(cipherString.indexOf(mapEntry.getKey()) >= 0) {
+ cipherKeySSF = mapEntry.getValue().intValue();
+ break;
+ }
+ }
+ return cipherKeySSF;
+ }
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
index 5cef3bc..eb6f158 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
@@ -29,6 +29,8 @@
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.TestCaseUtils;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.protocols.ldap.LDAPResultCode;
import org.opends.server.tools.LDAPModify;
import org.opends.server.tools.LDAPSearch;
import org.opends.server.tools.LDAPDelete;
@@ -38,10 +40,24 @@
import org.testng.Assert;
import java.io.*;
+import java.util.Hashtable;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.NoPermissionException;
+import javax.naming.directory.AttributeModificationException;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.ldap.InitialLdapContext;
+import javax.naming.ldap.LdapContext;
+import javax.naming.ldap.StartTlsRequest;
+import javax.naming.ldap.StartTlsResponse;
+
@Test(groups = {"precommit", "dseecompat"}, sequential = true)
public abstract class AciTestCase extends DirectoryServerTestCase {
@@ -335,6 +351,25 @@
ldapModify(argList.toArray(args), rc);
}
+ protected void JNDIModify(Hashtable<?, ?> env, String name,
+ String attr, String val, int rc) {
+ try {
+ DirContext ctx = new InitialDirContext(env);
+ ModificationItem[] mods = new ModificationItem[1 ];
+ mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE,
+ new BasicAttribute(attr, val));
+ ctx.modifyAttributes(name, mods);
+ ctx.close();
+ } catch (NoPermissionException npe) {
+ Assert.assertEquals(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS, rc,
+ "Returned error: " + npe.getMessage());
+ return;
+ } catch (NamingException ex) {
+ Assert.assertEquals(-1, rc, "Returned error: " + ex.getMessage());
+ }
+ Assert.assertEquals(LDAPResultCode.SUCCESS, rc, "");
+ }
+
private void ldapModify(String[] args, int rc) {
oStream.reset();
int retVal =LDAPModify.mainModify(args, false, oStream, oStream);
@@ -616,4 +651,5 @@
}
return attrMap;
}
+
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/SSFTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/SSFTestCase.java
new file mode 100644
index 0000000..0011e41
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/SSFTestCase.java
@@ -0,0 +1,294 @@
+/*
+ * 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
+ *
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ */
+
+/**
+ * Unit test to test the ssf ACI bind rule keyword.
+ */
+
+package org.opends.server.authorization.dseecompat;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.testng.annotations.*;
+import static org.opends.server.config.ConfigConstants.*;
+
+public class SSFTestCase extends AciTestCase {
+
+ private static final String newUser="uid=new.user,ou=People,o=test";
+ private static final String descriptionStr = "description of user.1";
+ private static final String factory = "com.sun.jndi.ldap.LdapCtxFactory";
+ private static final String pwdPolicy = "Aci Temp Policy";
+ private static final String pwdPolicyDN =
+ "cn=" + pwdPolicy + ",cn=Password Policies,cn=config";
+
+ private static final String[] newEntry = new String[] {
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "uid: new.user",
+ "givenName: New",
+ "sn: User",
+ "cn: New User",
+ "mail: new.user@test.com",
+ "ds-pwp-password-policy-dn:" + pwdPolicyDN
+ };
+
+ private static final
+ String integrityACI = "(targetattr=\"" + "*" + "\")" +
+ "(version 3.0; acl \"integrity aci\";" +
+ "allow(all) (userdn=\"ldap:///self\" and ssf = \"1\");)";
+
+ private static final
+ String greaterIntegrityACI = "(targetattr=\"" + "*" + "\")" +
+ "(version 3.0; acl \"greater integrity aci\";" +
+ "allow(all) (userdn=\"ldap:///self\" and ssf > \"1\");)";
+
+
+ private static final
+ String medStrengthACI = "(targetattr=\"" + "*" + "\")" +
+ "(version 3.0; acl \"56 bit key aci\";" +
+ "allow(all) (userdn=\"ldap:///self\" and ssf = \"56\");)";
+
+
+ private static final
+ String hiStrengthACI = "(targetattr=\"" + "*" + "\")" +
+ "(version 3.0; acl \"128 bit key aci\";" +
+ "allow(all) (userdn=\"ldap:///self\" and ssf = \"128\");)";
+
+
+ private static final
+ String hiPlusStrengthACI = "(targetattr=\"" + "*" + "\")" +
+ "(version 3.0; acl \"greater 128 bit aci\";" +
+ "allow(all) (userdn=\"ldap:///self\" and ssf > \"128\");)";
+
+
+ @BeforeClass
+ public void setupClass() throws Exception {
+ TestCaseUtils.startServer();
+ TestCaseUtils.dsconfig(
+ "create-password-policy",
+ "--policy-name", pwdPolicy,
+ "--set", "password-attribute:userPassword",
+ "--set", "default-password-storage-scheme: Clear"
+ );
+ TestCaseUtils.dsconfig(
+ "set-sasl-mechanism-handler-prop",
+ "--handler-name", "DIGEST-MD5",
+ "--set", "server-fqdn:localhost");
+ deleteAttrFromAdminEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
+ String aciLdif=makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
+ G_SCHEMA, G_DSE, G_USER_OPS, G_CONTROL, E_EXTEND_OP);
+ LDIFAdminModify(aciLdif, DIR_MGR_DN, PWD);
+ addEntries("o=test");
+ String newUserLDIF=makeAddEntryLDIF(newUser, newEntry);
+ LDIFAdd(newUserLDIF, DIR_MGR_DN, PWD, null, LDAPResultCode.SUCCESS);
+ String pwdILDIF =
+ makeAddLDIF("userpassword", newUser, "password");
+ LDIFModify(pwdILDIF, DIR_MGR_DN, PWD);
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void tearDown() throws Exception {
+ String aciLdif=makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
+ G_READ_ACI, G_SELF_MOD, G_SCHEMA, G_DSE, G_USER_OPS, G_CONTROL,
+ E_EXTEND_OP);
+ LDIFAdminModify(aciLdif, DIR_MGR_DN, PWD);
+ TestCaseUtils.dsconfig(
+ "delete-password-policy",
+ "--policy-name", pwdPolicy
+ );
+ TestCaseUtils.dsconfig(
+ "set-sasl-mechanism-handler-prop",
+ "--handler-name", "DIGEST-MD5",
+ "--reset", "server-fqdn",
+ "--reset", "quality-of-protection");
+
+ }
+
+ //Valid ssf statements. Not the complete ACI.
+ @DataProvider(name = "validStatements")
+ public Object[][] valids() {
+ return new Object[][] {
+ {"1"},
+ {"40"},
+ {"56"},
+ {"128"},
+ {"256"},
+ {"129"},
+ };
+ }
+
+ //Invalid ssf statements. Not the complete ACI.
+ @DataProvider(name = "invalidStatements")
+ public Object[][] invalids() {
+ return new Object[][] {
+ {"-1"},
+ {"0"},
+ {"not valid"},
+ {"1025"},
+ {"10000"},
+ };
+ }
+
+ private EnumBindRuleType bindRuleType = EnumBindRuleType.EQUAL_BINDRULE_TYPE;
+
+ /**
+ * Test valid ssf statements.
+ *
+ * @param statement The ssf statement to attempt to decode.
+ * @throws AciException If an unexpected result happens.
+ */
+ @Test(dataProvider = "validStatements")
+ public void testValidStatements(String statement) throws AciException {
+ SSF.decode(statement, bindRuleType);
+ }
+
+ /**
+ * Test invalid ssf statements.
+ *
+ * @param statement The ssf statement to attempt to decode.
+ * @throws Exception If an unexpected result happens.
+ */
+ @Test(expectedExceptions= AciException.class,
+ dataProvider="invalidStatements")
+ public void testInvalidStatements(String statement) throws Exception {
+ try {
+ SSF.decode(statement, bindRuleType);
+ } catch (AciException e) {
+ throw e;
+ } catch (Exception e) {
+ System.out.println(
+ "Invalid ssf <" + statement +
+ "> threw wrong exception type.");
+ throw e;
+ }
+ throw new RuntimeException(
+ "Invalid ssf <" + statement +
+ "> did not throw an exception.");
+ }
+
+ /**
+ * Test ssf bind rule using ssf value for integrity.
+ *
+ * @throws Exception If a test doesn't pass.
+ */
+ @Test()
+ public void testIntegrity() throws Exception {
+ //set QOP to integrity.
+ TestCaseUtils.dsconfig(
+ "set-sasl-mechanism-handler-prop",
+ "--handler-name", "DIGEST-MD5",
+ "--set", "quality-of-protection:" + "integrity");
+
+ //Configure JNDI props.
+ Hashtable<String, String> env = new Hashtable<String, String>();
+ env.put(Context.INITIAL_CONTEXT_FACTORY, factory);
+ int port = TestCaseUtils.getServerLdapPort();
+ String url = "ldap://localhost:" + Integer.valueOf(port);
+ env.put(Context.PROVIDER_URL, url);
+ env.put(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5");
+ String principal = "dn:" + newUser;
+ env.put(Context.SECURITY_PRINCIPAL, principal);
+ env.put(Context.SECURITY_CREDENTIALS, "password");
+ //Select integrity QOP.
+ env.put("javax.security.sasl.qop", "auth-int");
+ //Add ACI with ssf > 1, should fail.
+ String addACILDIF = makeAddLDIF("aci", newUser, greaterIntegrityACI);
+ LDIFModify(addACILDIF, DIR_MGR_DN, PWD);
+ JNDIModify(env, newUser, "description", descriptionStr,
+ LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ deleteAttrFromEntry(newUser, "aci");
+ //Add ACI with ssf = 1.
+ addACILDIF = makeAddLDIF("aci", newUser, integrityACI);
+ LDIFModify(addACILDIF, DIR_MGR_DN, PWD);
+ //Should succeed.
+ JNDIModify(env, newUser, "description", descriptionStr,
+ LDAPResultCode.SUCCESS);
+ deleteAttrFromEntry(newUser, "aci");
+ deleteAttrFromEntry(newUser, "description");
+ }
+
+ /**
+ * Test confidentiality settings using DIGEST-MD5.
+ * @throws Exception
+ */
+ @Test()
+ public void testConfidentiality() throws Exception {
+ //set QOP to integrity.
+ TestCaseUtils.dsconfig(
+ "set-sasl-mechanism-handler-prop",
+ "--handler-name", "DIGEST-MD5",
+ "--set", "quality-of-protection:" + "confidentiality");
+ Hashtable<String, String> env = new Hashtable<String, String>();
+ env.put(Context.INITIAL_CONTEXT_FACTORY, factory);
+ int port = TestCaseUtils.getServerLdapPort();
+ String url = "ldap://localhost:" + Integer.valueOf(port);
+ env.put(Context.PROVIDER_URL, url);
+ env.put(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5");
+ String principal = "dn:" + newUser;
+ env.put(Context.SECURITY_PRINCIPAL, principal);
+ env.put(Context.SECURITY_CREDENTIALS, "password");
+ //Select integrity QOP.
+ env.put("javax.security.sasl.qop", "auth-conf");
+ //Add ACI with ssf > 1, should succeed.
+ String addACILDIF = makeAddLDIF("aci", newUser, greaterIntegrityACI);
+ LDIFModify(addACILDIF, DIR_MGR_DN, PWD);
+ JNDIModify(env, newUser, "description", descriptionStr,
+ LDAPResultCode.SUCCESS);
+ deleteAttrFromEntry(newUser, "aci");
+ deleteAttrFromEntry(newUser, "description");
+ //Test medium strength.
+ addACILDIF = makeAddLDIF("aci", newUser, medStrengthACI);
+ LDIFModify(addACILDIF, DIR_MGR_DN, PWD);
+ env.put("javax.security.sasl.strength", "medium");
+ JNDIModify(env, newUser, "description", descriptionStr,
+ LDAPResultCode.SUCCESS);
+ deleteAttrFromEntry(newUser, "aci");
+ deleteAttrFromEntry(newUser, "description");
+ //Test high strength.
+ addACILDIF = makeAddLDIF("aci", newUser, hiStrengthACI);
+ LDIFModify(addACILDIF, DIR_MGR_DN, PWD);
+ env.put("javax.security.sasl.strength", "high");
+ JNDIModify(env, newUser, "description", descriptionStr,
+ LDAPResultCode.SUCCESS);
+ deleteAttrFromEntry(newUser, "aci");
+ deleteAttrFromEntry(newUser, "description");
+ //Fail DIGEST-MD5 only goes to 128.
+ addACILDIF = makeAddLDIF("aci", newUser, hiPlusStrengthACI);
+ LDIFModify(addACILDIF, DIR_MGR_DN, PWD);
+ env.put("javax.security.sasl.strength", "high");
+ JNDIModify(env, newUser, "description", descriptionStr,
+ LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ deleteAttrFromEntry(newUser, "aci");
+ deleteAttrFromEntry(newUser, "description");
+ }
+}
--
Gitblit v1.10.0