Hi, I've attached a patch to issue WSS-68 that includes the following: 1) Allow for a PasswordNone option to configure passwordless UsernameTokens 2) Allow Password callbacks to also provide the username
For this some (small) changes and cleanups were needed, as it is now permissable to return 'null' passwords. Checks related to this have been removed (which I think is not a real problem as code depending on passwords not being null, will now get a NullPointerException instead). Also, it is allowable to always set the identity in the callback handler, but I've only tested it for the UsernameToken. Extending it to work for Signatures as well seems logical, but I'd first like to hear feedback on a smaller scale change before making more changes. I've attached the patch to this mail as well. Regards, Marcel Ammerlaan.
Index: org/apache/ws/security/processor/DerivedKeyTokenProcessor.java =================================================================== --- org/apache/ws/security/processor/DerivedKeyTokenProcessor.java (revision 608810) +++ org/apache/ws/security/processor/DerivedKeyTokenProcessor.java (working copy) @@ -33,8 +33,6 @@ import org.apache.ws.security.util.Base64; import org.w3c.dom.Element; -import sun.security.x509.KeyIdentifier; - import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; Index: org/apache/ws/security/message/token/UsernameToken.java =================================================================== --- org/apache/ws/security/message/token/UsernameToken.java (revision 608810) +++ org/apache/ws/security/message/token/UsernameToken.java (working copy) @@ -45,6 +45,7 @@ * UsernameToken according to WS Security specifications, UsernameToken profile. * * Enhanced to support digest password type for username token signature + * Enhanced to support passwordless usernametokens as allowed by spec. * * @author Davanum Srinivas ([EMAIL PROTECTED]) * @author Werner Dittmann ([EMAIL PROTECTED]) @@ -168,7 +169,8 @@ * @param pwType * the required password encoding, either * [EMAIL PROTECTED] WSConstants#PASSWORD_DIGEST} or - * [EMAIL PROTECTED] WSConstants#PASSWORD_TEXT} or <code>null</code> if no + * [EMAIL PROTECTED] WSConstants#PASSWORD_TEXT} or + * [EMAIL PROTECTED] WSConstants#PASSWORD_NONE} <code>null</code> if no * password required */ public UsernameToken(boolean milliseconds, Document doc, String pwType) { @@ -399,8 +401,14 @@ */ public void setPassword(String pwd) { if (pwd == null) { - throw new IllegalArgumentException("pwd == null"); + if(this.passwordType != null) { + throw new IllegalArgumentException("pwd == null but a password is needed"); + } else { + // Ignore setting the password. + return; + } } + raw_password = pwd; // enhancement by Alberto coletti Text node = getFirstNode(this.elementPassword); try { Index: org/apache/ws/security/message/WSSecUsernameToken.java =================================================================== --- org/apache/ws/security/message/WSSecUsernameToken.java (revision 608810) +++ org/apache/ws/security/message/WSSecUsernameToken.java (working copy) @@ -63,14 +63,10 @@ * contains the password type. Only allowed values are * [EMAIL PROTECTED] WSConstants#PASSWORD_DIGEST} and * [EMAIL PROTECTED] WSConstants#PASSWORD_TEXT}. + * or null when no password is needed. */ public void setPasswordType(String pwType) { - if (pwType == null) { - passwordType = WSConstants.PASSWORD_DIGEST; - } else if (pwType.equals(WSConstants.PASSWORD_DIGEST) - || pwType.equals(WSConstants.PASSWORD_TEXT)) { - passwordType = pwType; - } + this.passwordType = pwType; } /** Index: org/apache/ws/security/WSConstants.java =================================================================== --- org/apache/ws/security/WSConstants.java (revision 608810) +++ org/apache/ws/security/WSConstants.java (working copy) @@ -177,6 +177,15 @@ * The password type URI used in the username token */ public static final String PASSWORD_TEXT = USERNAMETOKEN_NS + "#PasswordText"; + + /** + * Sets the [EMAIL PROTECTED] org.apache.ws.security.message.WSSAddUsernameToken#build(Document, String, String) UserNameToken} + * method to send _no_ password related information. + * <p/> + * This is a required method as defined by WS Specification, Username token profile as passwords are optional. + * Also see the WS-I documentation for scenario's using this feature in a trust environment. + */ + public static final String PW_NONE = "PasswordNone"; /** * Sets the [EMAIL PROTECTED] org.apache.ws.security.message.WSEncryptBody#build(Document, Crypto) encryption} Index: org/apache/ws/security/WSPasswordCallback.java =================================================================== --- org/apache/ws/security/WSPasswordCallback.java (revision 608810) +++ org/apache/ws/security/WSPasswordCallback.java (working copy) @@ -75,7 +75,7 @@ public final static int SECURITY_CONTEXT_TOKEN = 6; public final static int CUSTOM_TOKEN = 7; public final static int ENCRYPTED_KEY_TOKEN = 8; - + private String identifier; private String password; private byte[] key; @@ -114,6 +114,19 @@ public String getIdentifer() { return identifier; } + + /** + * Extended callback interface allows for setting the username as well. + * Callback functions can change the identifier, this is intended in the usernametoken scenario + * where the usernametoken denotes the identity, but a fixed identity for signing is used + * The initial value is that from the configuration file. If this method is not called, the + * configured identity is used. + * + * @param ident The identity. + */ + public void setIdentifier(String ident) { + this.identifier = ident; + } /** * Set the password. Index: org/apache/ws/security/handler/WSHandler.java =================================================================== --- org/apache/ws/security/handler/WSHandler.java (revision 608810) +++ org/apache/ws/security/handler/WSHandler.java (working copy) @@ -51,10 +51,11 @@ /** * Extracted from WSDoAllReceiver and WSDoAllSender + * Extended to all passwordless UsernameTokens and configurable identities. * - * * @author Davanum Srinivas ([EMAIL PROTECTED]). * @author Werner Dittmann ([EMAIL PROTECTED]). + * @author Marcel Ammerlaan ([EMAIL PROTECTED]). */ public abstract class WSHandler { public static String DONE = "done"; @@ -430,11 +431,17 @@ Object mc = reqData.getMsgContext(); String type = getString(WSHandlerConstants.PASSWORD_TYPE, mc); - reqData.setPwType(type); if (type != null) { - reqData.setPwType(type.equals(WSConstants.PW_TEXT) - ? WSConstants.PASSWORD_TEXT - : WSConstants.PASSWORD_DIGEST); + if(WSConstants.PW_TEXT.equals(type)) { + reqData.setPwType(WSConstants.PASSWORD_TEXT); + } else if(WSConstants.PW_DIGEST.equals(type)) { + reqData.setPwType(WSConstants.PASSWORD_DIGEST); + } else if(WSConstants.PW_NONE.equals(type)) { + // No password requested. + reqData.setPwType(null); + } else { + throw new WSSecurityException("Unknown password type encoding: " + type); + } } String add = getString(WSHandlerConstants.ADD_UT_ELEMENTS, mc); @@ -604,8 +611,7 @@ throw new WSSecurityException( "WSHandler: illegal timestampStrict parameter"); } - - + /** * Get a password to construct a UsernameToken or sign a message. * <p/> @@ -620,25 +626,19 @@ WSPasswordCallback pwCb = null; String password = null; CallbackHandler cbHandler = null; - String err = "provided null or empty password"; - Object mc = reqData.getMsgContext(); + String err = "provided null or empty password"; + Object mc = reqData.getMsgContext(); String callback = getString(clsProp, mc); if (callback != null) { // we have a password callback class pwCb = readPwViaCallbackClass(callback, username, doAction, reqData); - if ((pwCb.getPassword() == null) && (pwCb.getKey() == null)) { - throw new WSSecurityException("WSHandler: password callback class " - +err); - } - } else if ((cbHandler = (CallbackHandler) getProperty(mc, refProp)) - != null) { + // Null passwords are not always a problem: if the callback was called to provide a username instead. + } else if ((cbHandler = (CallbackHandler) getProperty(mc, refProp)) != null) { pwCb = performCallback(cbHandler, username, doAction); - if ((pwCb.getPassword() == null) && (pwCb.getKey() == null)) { - throw new WSSecurityException("WSHandler: password callback " - +err); - } } else if ((password = getPassword(mc)) == null) { - throw new WSSecurityException("WSHandler: application "+err); + // TODO: hmm. does this also need changed for username processing? + throw new WSSecurityException("WSHandler: application " + err); } else { + // TODO: hmm. does this also need changed for username processing? setPassword(mc, null); pwCb = new WSPasswordCallback("", WSPasswordCallback.UNKNOWN); pwCb.setPassword(password); Index: org/apache/ws/security/action/UsernameTokenAction.java =================================================================== --- org/apache/ws/security/action/UsernameTokenAction.java (revision 608810) +++ org/apache/ws/security/action/UsernameTokenAction.java (working copy) @@ -17,6 +17,8 @@ package org.apache.ws.security.action; +import org.apache.ws.security.WSConstants; +import org.apache.ws.security.WSPasswordCallback; import org.apache.ws.security.WSSecurityException; import org.apache.ws.security.handler.RequestData; import org.apache.ws.security.handler.WSHandler; @@ -27,18 +29,20 @@ public class UsernameTokenAction implements Action { public void execute(WSHandler handler, int actionToDo, Document doc, RequestData reqData) throws WSSecurityException { - String password; - password = - handler.getPassword(reqData.getUsername(), + String password = null; + + // Always call the callback for the username. We mis-use the configured password callback class and callback methods for this. + String providedUsername = reqData.getUsername(); + WSPasswordCallback callbackData = handler.getPassword(reqData.getUsername(), actionToDo, WSHandlerConstants.PW_CALLBACK_CLASS, - WSHandlerConstants.PW_CALLBACK_REF, reqData) - .getPassword(); + WSHandlerConstants.PW_CALLBACK_REF, reqData); + providedUsername = callbackData.getIdentifer(); WSSecUsernameToken builder = new WSSecUsernameToken(); builder.setWsConfig(reqData.getWssConfig()); builder.setPasswordType(reqData.getPwType()); - builder.setUserInfo(reqData.getUsername(), password); + builder.setUserInfo(providedUsername, password); if (reqData.getUtElements() != null && reqData.getUtElements().length > 0) { for (int j = 0; j < reqData.getUtElements().length; j++) {
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]