You are viewing a plain text version of this content. The canonical link for it is here.
Posted to wss4j-dev@ws.apache.org by fa...@apache.org on 2008/04/17 18:58:02 UTC
svn commit: r649186 - in /webservices/wss4j/trunk:
src/org/apache/ws/security/ src/org/apache/ws/security/handler/
src/org/apache/ws/security/processor/ test/wssec/
Author: fadushin
Date: Thu Apr 17 09:58:01 2008
New Revision: 649186
URL: http://svn.apache.org/viewvc?rev=649186&view=rev
Log:
WSS-54 UsernameToken processor improvements
* Applied Colm's revised patch, which has been reviewed.
* Witholds information about authentication failures from
caller, but logs said information, instead
* Delegates custom password types to callback handler
Modified:
webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java
webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandler.java
webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandlerConstants.java
webservices/wss4j/trunk/src/org/apache/ws/security/processor/UsernameTokenProcessor.java
webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java
Modified: webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java?rev=649186&r1=649185&r2=649186&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java Thu Apr 17 09:58:01 2008
@@ -176,6 +176,15 @@
* expired.
*/
protected boolean timeStampStrict = true;
+
+ /**
+ * This variable controls whether types other than PasswordDigest or PasswordText
+ * are allowed when processing UsernameTokens.
+ *
+ * By default this is set to false so that the user doesn't have to explicitly
+ * reject custom token types in the callback handler.
+ */
+ protected boolean handleCustomPasswordTypes = false;
protected HashMap jceProvider = new HashMap(10);
@@ -320,6 +329,21 @@
public void setEnableSignatureConfirmation(
boolean enableSignatureConfirmation) {
this.enableSignatureConfirmation = enableSignatureConfirmation;
+ }
+
+ /**
+ * @param handleCustomTypes
+ * whether to handle custom UsernameToken password types or not
+ */
+ public void setHandleCustomPasswordTypes(boolean handleCustomTypes) {
+ this.handleCustomPasswordTypes = handleCustomTypes;
+ }
+
+ /**
+ * @return whether custom UsernameToken password types are allowed or not
+ */
+ public boolean getHandleCustomPasswordTypes() {
+ return handleCustomPasswordTypes;
}
/**
Modified: webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandler.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandler.java?rev=649186&r1=649185&r2=649186&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandler.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandler.java Thu Apr 17 09:58:01 2008
@@ -249,6 +249,7 @@
wssConfig
.setEnableSignatureConfirmation(decodeEnableSignatureConfirmation(reqData));
wssConfig.setTimeStampStrict(decodeTimestampStrict(reqData));
+ wssConfig.setHandleCustomPasswordTypes(decodeCustomPasswordTypes(reqData));
reqData.setWssConfig(wssConfig);
if ((doAction & WSConstants.SIGN) == WSConstants.SIGN) {
@@ -616,6 +617,22 @@
throw new WSSecurityException(
"WSHandler: illegal precisionInMilliSeconds parameter");
+ }
+
+ protected boolean decodeCustomPasswordTypes(RequestData reqData)
+ throws WSSecurityException {
+ String value = getString(
+ WSHandlerConstants.HANDLE_CUSTOM_PASSWORD_TYPES,
+ reqData.getMsgContext()
+ );
+
+ if (value == null) {return false;}
+
+ if ("0".equals(value) || "false".equals(value)) {return false;}
+ if ("1".equals(value) || "true".equals(value)) {return true;}
+
+ throw new WSSecurityException(
+ "WSHandler: illegal handleCustomPasswordTypes parameter");
}
protected boolean decodeTimestampStrict(RequestData reqData)
Modified: webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandlerConstants.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandlerConstants.java?rev=649186&r1=649185&r2=649186&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandlerConstants.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandlerConstants.java Thu Apr 17 09:58:01 2008
@@ -454,7 +454,7 @@
/**
* Specific parameter for UsernameToken action to define the encoding
- * of the passowrd.
+ * of the password.
* <p/>
* The parameter can be set to either {@link WSConstants#PW_DIGEST}
* or to {@link WSConstants#PW_TEXT}.
@@ -469,6 +469,15 @@
* The default setting is PW_DIGEST.
*/
public static final String PASSWORD_TYPE = "passwordType";
+
+ /**
+ * This variable controls whether types other than PasswordDigest or PasswordText
+ * are allowed when processing UsernameTokens.
+ *
+ * By default this is set to false so that the user doesn't have to explicitly
+ * reject custom token types in the callback handler.
+ */
+ public static final String HANDLE_CUSTOM_PASSWORD_TYPES = "handleCustomPasswordTypes";
/**
* Parameter to generate additional elements in <code>UsernameToken</code>.
Modified: webservices/wss4j/trunk/src/org/apache/ws/security/processor/UsernameTokenProcessor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/processor/UsernameTokenProcessor.java?rev=649186&r1=649185&r2=649186&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/processor/UsernameTokenProcessor.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/processor/UsernameTokenProcessor.java Thu Apr 17 09:58:01 2008
@@ -42,40 +42,41 @@
private String utId;
private UsernameToken ut;
+ private boolean handleCustomPasswordTypes;
public void handleToken(Element elem, Crypto crypto, Crypto decCrypto, CallbackHandler cb, WSDocInfo wsDocInfo, Vector returnResults, WSSConfig wsc) throws WSSecurityException {
if (log.isDebugEnabled()) {
log.debug("Found UsernameToken list element");
}
+ handleCustomPasswordTypes = wsc.getHandleCustomPasswordTypes();
+
Principal lastPrincipalFound = handleUsernameToken((Element) elem, cb);
returnResults.add(0, new WSSecurityEngineResult(WSConstants.UT,
lastPrincipalFound, null, null, null));
utId = elem.getAttributeNS(WSConstants.WSU_NS, "Id");
-
}
/**
* Check the UsernameToken element. Depending on the password type
* contained in the element the processing differs. If the password type
- * is password digest (a hashed password) then process the password
- * commpletely here. Use the callback class to get a stored password
- * perform hash algorithm and compare the result with the transmitted
- * password.
+ * is digested, then retrieve a password from the callback handler and
+ * authenticate the UsernameToken here.
* <p/>
- * If the password is of type password text or any other yet unknown
- * password type the delegate the password validation to the callback
- * class. To do so the security engine hands over all necessary data to
- * the callback class via the WSPasswordCallback object. To distinguish
- * from digested usernam token the usage parameter of WSPasswordCallback
- * is set to <code>USERNAME_TOKEN_UNKNOWN</code>
+ * If the password is in plaintext or any other yet unknown password type
+ * then delegate the password validation to the callback class. Note that for unknown
+ * password types an exception is thrown if WSSConfig.getHandleCustomPasswordTypes()
+ * is set to false (as it is by default). The security engine hands over all necessary
+ * data to the callback class via the WSPasswordCallback object. The usage parameter of
+ * WSPasswordCallback is set to <code>USERNAME_TOKEN_UNKNOWN</code>.
*
* @param token the DOM element that contains the UsernameToken
- * @param cb the refernce to the callback object
+ * @param cb the reference to the callback object
* @return WSUsernameTokenPrincipal that contain data that an application
* may use to further validate the password/user combination.
* @throws WSSecurityException
*/
- public WSUsernameTokenPrincipal handleUsernameToken(Element token, CallbackHandler cb) throws WSSecurityException {
+ public WSUsernameTokenPrincipal handleUsernameToken(Element token, CallbackHandler cb)
+ throws WSSecurityException {
ut = new UsernameToken(token);
String user = ut.getName();
String password = ut.getPassword();
@@ -90,10 +91,14 @@
Callback[] callbacks = new Callback[1];
String origPassword = null;
+ //
+ // If the UsernameToken is hashed, then retrieve the password from the callback handler
+ // and compare directly. If the UsernameToken is in plaintext or of some unknown type,
+ // then delegate authentication to the callback handler
+ //
if (ut.isHashed()) {
if (cb == null) {
- throw new WSSecurityException(WSSecurityException.FAILURE,
- "noCallback");
+ throw new WSSecurityException(WSSecurityException.FAILURE, "noCallback");
}
WSPasswordCallback pwCb = new WSPasswordCallback(user, WSPasswordCallback.USERNAME_TOKEN);
@@ -101,13 +106,15 @@
try {
cb.handle(callbacks);
} catch (IOException e) {
- throw new WSSecurityException(WSSecurityException.FAILURE,
- "noPassword",
- new Object[]{user}, e);
+ if (log.isDebugEnabled()) {
+ log.debug(e);
+ }
+ throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
} catch (UnsupportedCallbackException e) {
- throw new WSSecurityException(WSSecurityException.FAILURE,
- "noPassword",
- new Object[]{user}, e);
+ if (log.isDebugEnabled()) {
+ log.debug(e);
+ }
+ throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
}
origPassword = pwCb.getPassword();
if (log.isDebugEnabled()) {
@@ -122,18 +129,30 @@
throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
}
ut.setRawPassword(origPassword);
- } else if (cb != null) {
+ } else {
+ if (cb == null) {
+ throw new WSSecurityException(WSSecurityException.FAILURE, "noCallback");
+ } else if (!WSConstants.PASSWORD_TEXT.equals(pwType) && !handleCustomPasswordTypes) {
+ if (log.isDebugEnabled()) {
+ log.debug("Authentication failed as handleCustomUsernameTokenTypes is false");
+ }
+ throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
+ }
WSPasswordCallback pwCb = new WSPasswordCallback(user, password,
pwType, WSPasswordCallback.USERNAME_TOKEN_UNKNOWN);
callbacks[0] = pwCb;
try {
cb.handle(callbacks);
} catch (IOException e) {
- throw new WSSecurityException(WSSecurityException.FAILURE,
- "noPassword", new Object[]{user});
+ if (log.isDebugEnabled()) {
+ log.debug(e);
+ }
+ throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
} catch (UnsupportedCallbackException e) {
- throw new WSSecurityException(WSSecurityException.FAILURE,
- "noPassword", new Object[]{user});
+ if (log.isDebugEnabled()) {
+ log.debug(e);
+ }
+ throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
}
ut.setRawPassword(password);
}
Modified: webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java?rev=649186&r1=649185&r2=649186&view=diff
==============================================================================
--- webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java (original)
+++ webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java Thu Apr 17 09:58:01 2008
@@ -32,6 +32,7 @@
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSSecurityEngine;
import org.apache.ws.security.WSConstants;
+import org.apache.ws.security.WSSConfig;
import org.apache.ws.security.message.WSSecUsernameToken;
import org.apache.ws.security.message.WSSecHeader;
import org.w3c.dom.Document;
@@ -144,6 +145,41 @@
log.info("After adding UsernameToken PW Digest....");
verify(signedDoc);
}
+
+ /**
+ * Test that adds a UserNameToken with a bad password Digest to a WS-Security envelope
+ * <p/>
+ */
+ public void testUsernameTokenBadDigest() throws Exception {
+ WSSecUsernameToken builder = new WSSecUsernameToken();
+ builder.setUserInfo("wernerd", "verySecre");
+ log.info("Before adding UsernameToken PW Digest....");
+ Document doc = unsignedEnvelope.getAsDocument();
+ WSSecHeader secHeader = new WSSecHeader();
+ secHeader.insertSecurityHeader(doc);
+ Document signedDoc = builder.build(doc, secHeader);
+
+ /*
+ * convert the resulting document into a message first. The toAxisMessage()
+ * method performs the necessary c14n call to properly set up the signed
+ * document and convert it into a SOAP message. After that we extract it
+ * as a document again for further processing.
+ */
+
+ Message signedMsg = SOAPUtil.toAxisMessage(signedDoc);
+ if (log.isDebugEnabled()) {
+ log.debug("Message with UserNameToken PW Digest:");
+ XMLUtils.PrettyElementToWriter(signedMsg.getSOAPEnvelope().getAsDOM(), new PrintWriter(System.out));
+ }
+ signedDoc = signedMsg.getSOAPEnvelope().getAsDocument();
+ log.info("After adding UsernameToken PW Digest....");
+ try {
+ verify(signedDoc);
+ } catch (WSSecurityException ex) {
+ assertTrue(ex.getErrorCode() == WSSecurityException.FAILED_AUTHENTICATION);
+ // expected
+ }
+ }
/**
* Test that adds a UserNameToken with password text to a WS-Security envelope
@@ -169,6 +205,105 @@
}
/**
+ * Test that adds a UserNameToken with (bad) password text to a WS-Security envelope
+ * <p/>
+ */
+ public void testUsernameTokenBadText() throws Exception {
+ WSSecUsernameToken builder = new WSSecUsernameToken();
+ builder.setPasswordType(WSConstants.PASSWORD_TEXT);
+ builder.setUserInfo("wernerd", "verySecre");
+ log.info("Before adding UsernameToken PW Text....");
+ Document doc = unsignedEnvelope.getAsDocument();
+ WSSecHeader secHeader = new WSSecHeader();
+ secHeader.insertSecurityHeader(doc);
+ Document signedDoc = builder.build(doc, secHeader);
+ Message signedMsg = SOAPUtil.toAxisMessage(signedDoc);
+ if (log.isDebugEnabled()) {
+ log.debug("Message with UserNameToken PW Text:");
+ XMLUtils.PrettyElementToWriter(signedMsg.getSOAPEnvelope().getAsDOM(), new PrintWriter(System.out));
+ }
+ signedDoc = signedMsg.getSOAPEnvelope().getAsDocument();
+ log.info("After adding UsernameToken PW Text....");
+
+ try {
+ verify(signedDoc);
+ } catch (WSSecurityException ex) {
+ assertTrue(ex.getErrorCode() == WSSecurityException.FAILED_AUTHENTICATION);
+ // expected
+ }
+ }
+
+ /**
+ * Test with a null token type. This will fail as the default is to reject custom
+ * token types.
+ * <p/>
+ */
+ public void testUsernameTokenCustomFail() throws Exception {
+ WSSecUsernameToken builder = new WSSecUsernameToken();
+ builder.setPasswordType(null);
+ builder.setUserInfo("wernerd", null);
+
+ Document doc = unsignedEnvelope.getAsDocument();
+ WSSecHeader secHeader = new WSSecHeader();
+ secHeader.insertSecurityHeader(doc);
+ Document signedDoc = builder.build(doc, secHeader);
+ Message signedMsg = SOAPUtil.toAxisMessage(signedDoc);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Message with UserNameToken PW Text:");
+ XMLUtils.PrettyElementToWriter(signedMsg.getSOAPEnvelope().getAsDOM(), new PrintWriter(System.out));
+ }
+
+ signedDoc = signedMsg.getSOAPEnvelope().getAsDocument();
+ try {
+ verify(signedDoc);
+ throw new Exception("Custom token types are not permitted");
+ } catch (WSSecurityException ex) {
+ assertTrue(ex.getErrorCode() == WSSecurityException.FAILED_AUTHENTICATION);
+ // expected
+ }
+ }
+
+ /**
+ * Test with a null token type. This will pass as the WSSConfig is configured to
+ * handle custom token types.
+ * <p/>
+ */
+ public void testUsernameTokenCustomPass() throws Exception {
+ WSSecUsernameToken builder = new WSSecUsernameToken();
+ builder.setPasswordType(null);
+ builder.setUserInfo("wernerd", null);
+
+ Document doc = unsignedEnvelope.getAsDocument();
+ WSSecHeader secHeader = new WSSecHeader();
+ secHeader.insertSecurityHeader(doc);
+ Document signedDoc = builder.build(doc, secHeader);
+ Message signedMsg = SOAPUtil.toAxisMessage(signedDoc);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Message with UserNameToken PW Text:");
+ XMLUtils.PrettyElementToWriter(signedMsg.getSOAPEnvelope().getAsDOM(), new PrintWriter(System.out));
+ }
+
+ signedDoc = signedMsg.getSOAPEnvelope().getAsDocument();
+
+ //
+ // Configure so that custom token types are accepted
+ //
+ WSSConfig cfg = WSSConfig.getNewInstance();
+ cfg.setHandleCustomPasswordTypes(true);
+ secEngine.setWssConfig(cfg);
+ verify(signedDoc);
+
+ //
+ // Go back to default for other tests
+ //
+ cfg.setHandleCustomPasswordTypes(false);
+ secEngine.setWssConfig(cfg);
+ }
+
+
+ /**
* A test for WSS-66 - the nonce string is null
* http://issues.apache.org/jira/browse/WSS-66
* "Possible security hole when PasswordDigest is used by client."
@@ -266,17 +401,19 @@
}
public void handle(Callback[] callbacks)
- throws IOException, UnsupportedCallbackException {
+ throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof WSPasswordCallback) {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
- /*
- * here call a function/method to lookup the password for
- * the given identifier (e.g. a user name or keystore alias)
- * e.g.: pc.setPassword(passStore.getPassword(pc.getIdentfifier))
- * for Testing we supply a fixed name here.
- */
- pc.setPassword("verySecret");
+ if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN
+ && "wernerd".equals(pc.getIdentifer())) {
+ pc.setPassword("verySecret");
+ } else if (
+ pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN
+ && "wernerd".equals(pc.getIdentifer())
+ && "verySecret".equals(pc.getPassword())) {
+ return;
+ }
} else {
throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
}
---------------------------------------------------------------------
To unsubscribe, e-mail: wss4j-dev-unsubscribe@ws.apache.org
For additional commands, e-mail: wss4j-dev-help@ws.apache.org