Permalink
Browse files

Enforce UsernameToken Password type checking for StaX inbound, removi…

…ng DOM's PASSWORD_TYPE_STRICT configuration parameter

git-svn-id: https://svn.apache.org/repos/asf/webservices/wss4j/trunk@1467270 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information...
1 parent 01d5b59 commit a4a6d99b0f12c3cc0e8a55773ed28c122251536f @coheigea coheigea committed Apr 12, 2013
@@ -278,10 +278,9 @@ protected void doReceiverAction(int doAction, RequestData reqData)
enableSigConf || ((doAction & WSConstants.SC) != 0)
);
wssConfig.setTimeStampStrict(decodeTimestampStrict(reqData));
- if (decodePasswordTypeStrict(reqData)) {
- String passwordType = decodePasswordType(reqData);
- wssConfig.setRequiredPasswordType(passwordType);
- }
+ String passwordType = decodePasswordType(reqData);
+ wssConfig.setRequiredPasswordType(passwordType);
+
wssConfig.setTimeStampTTL(decodeTimeToLive(reqData, true));
wssConfig.setTimeStampFutureTTL(decodeFutureTimeToLive(reqData, true));
wssConfig.setUtTTL(decodeTimeToLive(reqData, false));
@@ -785,13 +784,6 @@ protected boolean decodeTimestampStrict(RequestData reqData)
);
}
- protected boolean decodePasswordTypeStrict(RequestData reqData)
- throws WSSecurityException {
- return decodeBooleanConfigValue(
- reqData, WSHandlerConstants.PASSWORD_TYPE_STRICT, false
- );
- }
-
protected boolean decodeUseSingleCertificate(RequestData reqData)
throws WSSecurityException {
return decodeBooleanConfigValue(
@@ -392,15 +392,6 @@ private WSHandlerConstants() {
public static final String ALLOW_USERNAMETOKEN_NOPASSWORD = "allowUsernameTokenNoPassword";
/**
- * Set the value of this parameter to true to enable strict Username Token password type
- * handling. The default value is "false".
- *
- * If this parameter is set to true, it throws an exception if the password type of
- * the Username Token does not match that of the configured PASSWORD_TYPE parameter.
- */
- public static final String PASSWORD_TYPE_STRICT = "passwordTypeStrict";
-
- /**
* This variable controls whether (wsse) namespace qualified password types are
* accepted when processing UsernameTokens. The default value is "false".
*/
@@ -492,17 +483,17 @@ private WSHandlerConstants() {
public static final String ENC_KEY_NAME = "embeddedKeyName";
/**
- * Specific parameter for UsernameToken action to define the encoding
- * of the password.
- * <p/>
- * The parameter can be set to either {@link WSConstants#PW_DIGEST}
- * or to {@link WSConstants#PW_TEXT}.
- * <p/>
- * The application may set this parameter using the following method:
- * <pre>
- * call.setProperty(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);
- * </pre>
- * The default setting is PW_DIGEST.
+ * Specific parameter for UsernameTokens to define the encoding of the password. It can
+ * be used on either the outbound or inbound side. The valid values are:
+ *
+ * - {@link WSConstants#PW_DIGEST}
+ * - {@link WSConstants#PW_TEXT}
+ * - {@link WSConstants#PW_NONE}
+ *
+ * On the Outbound side, the default value is PW_DIGEST. There is no default value on
+ * the inbound side. If a value is specified on the inbound side, the password type of
+ * the received UsernameToken must match the specified type, or an exception will be
+ * thrown.
*/
public static final String PASSWORD_TYPE = "passwordType";
@@ -170,22 +170,14 @@ public void testUsernameTokenWSHandler() throws Exception {
}
//
- // It should pass even on a different password type, as we haven't set the
- // processing to be strict
+ // It should fail on a different password type
//
config.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);
reqData.setMsgContext(config);
handler.receive(WSConstants.UT, reqData);
WSSecurityEngine secEngine = new WSSecurityEngine();
secEngine.setWssConfig(reqData.getWssConfig());
- secEngine.processSecurityHeader(doc, null, callbackHandler, null);
- //
- // It should fail on strict password type processing
- //
- config.put(WSHandlerConstants.PASSWORD_TYPE_STRICT, "true");
- reqData.setMsgContext(config);
- handler.receive(WSConstants.UT, reqData);
try {
secEngine.processSecurityHeader(doc, null, callbackHandler, null);
fail("Expected failure on the wrong password type");
@@ -35,6 +35,8 @@
import org.apache.xml.security.stax.securityToken.InboundSecurityToken;
public class UsernameTokenValidatorImpl implements UsernameTokenValidator {
+
+ private static final transient org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UsernameTokenValidatorImpl.class);
@Override
public <T extends UsernameSecurityToken & InboundSecurityToken> T validate(
@@ -57,6 +59,28 @@
final byte[] nonceVal;
+ // Check received password type against required type
+ WSSConstants.UsernameTokenPasswordType requiredPasswordType =
+ tokenContext.getWssSecurityProperties().getUsernameTokenPasswordType();
+ if (requiredPasswordType != null) {
+ if (passwordType == null || passwordType.getType() == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Authentication failed as the received password type does not "
+ + "match the required password type of: " + requiredPasswordType);
+ }
+ throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
+ }
+ WSSConstants.UsernameTokenPasswordType usernameTokenPasswordType =
+ WSSConstants.UsernameTokenPasswordType.getUsernameTokenPasswordType(passwordType.getType());
+ if (requiredPasswordType != usernameTokenPasswordType) {
+ if (log.isDebugEnabled()) {
+ log.debug("Authentication failed as the received password type does not "
+ + "match the required password type of: " + requiredPasswordType);
+ }
+ throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
+ }
+ }
+
WSSConstants.UsernameTokenPasswordType usernameTokenPasswordType = WSSConstants.UsernameTokenPasswordType.PASSWORD_NONE;
if (passwordType != null && passwordType.getType() != null) {
usernameTokenPasswordType = WSSConstants.UsernameTokenPasswordType.getUsernameTokenPasswordType(passwordType.getType());
@@ -0,0 +1,185 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.wss4j.stax.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.Properties;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.dom.WSConstants;
+import org.apache.wss4j.dom.handler.WSHandlerConstants;
+import org.apache.wss4j.stax.WSSec;
+import org.apache.wss4j.stax.ext.InboundWSSec;
+import org.apache.wss4j.stax.ext.WSSConstants;
+import org.apache.wss4j.stax.ext.WSSSecurityProperties;
+import org.apache.wss4j.stax.test.utils.StAX2DOM;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * This is a test for processing a Username Token to enforce either a plaintext or digest
+ * password type.
+ */
+public class PasswordTypeTest extends AbstractTestBase {
+
+ @Test
+ public void testPasswordDigest() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ {
+ InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml");
+ String action = WSHandlerConstants.USERNAME_TOKEN;
+ Properties properties = new Properties();
+ Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties);
+
+ //some test that we can really sure we get what we want from WSS4J
+ NodeList nodeList = securedDocument.getElementsByTagNameNS(WSSConstants.TAG_wsse_UsernameToken.getNamespaceURI(), WSSConstants.TAG_wsse_UsernameToken.getLocalPart());
+ Assert.assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_wsse_Security.getLocalPart());
+
+ nodeList = securedDocument.getElementsByTagNameNS(WSSConstants.TAG_wsse_Password.getNamespaceURI(), WSSConstants.TAG_wsse_Password.getLocalPart());
+ Assert.assertEquals(nodeList.getLength(), 1);
+ Assert.assertEquals(((Element) nodeList.item(0)).getAttributeNS(null, WSSConstants.ATT_NULL_Type.getLocalPart()), WSSConstants.UsernameTokenPasswordType.PASSWORD_DIGEST.getNamespace());
+
+ javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
+ transformer.transform(new DOMSource(securedDocument), new StreamResult(baos));
+ }
+
+ // It should pass with PASSWORD_DIGEST
+ {
+ WSSSecurityProperties securityProperties = new WSSSecurityProperties();
+ securityProperties.setCallbackHandler(new CallbackHandlerImpl());
+ securityProperties.setUsernameTokenPasswordType(WSSConstants.UsernameTokenPasswordType.PASSWORD_DIGEST);
+ InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
+
+ XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), null, null);
+
+ StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
+ }
+
+ // It should pass with null
+ {
+ WSSSecurityProperties securityProperties = new WSSSecurityProperties();
+ securityProperties.setCallbackHandler(new CallbackHandlerImpl());
+ securityProperties.setUsernameTokenPasswordType(null);
+ InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
+
+ XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), null, null);
+
+ StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
+ }
+
+ // It should fail with PASSWORD_TEXT
+ {
+ WSSSecurityProperties securityProperties = new WSSSecurityProperties();
+ securityProperties.setCallbackHandler(new CallbackHandlerImpl());
+ securityProperties.setUsernameTokenPasswordType(WSSConstants.UsernameTokenPasswordType.PASSWORD_TEXT);
+ InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
+
+ XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), null, null);
+
+ try {
+ StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
+ Assert.fail("Expected XMLStreamException");
+ } catch (XMLStreamException e) {
+ Assert.assertNotNull(e.getCause());
+ Assert.assertTrue(e.getCause() instanceof WSSecurityException);
+ Assert.assertEquals(e.getCause().getMessage(), "The security token could not be authenticated or authorized");
+ Assert.assertEquals(((WSSecurityException) e.getCause()).getFaultCode(), WSSecurityException.FAILED_AUTHENTICATION);
+ }
+ }
+ }
+
+ @Test
+ public void testPasswordText() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ {
+ InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml");
+ String action = WSHandlerConstants.USERNAME_TOKEN;
+ Properties properties = new Properties();
+ properties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
+ Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties);
+
+ //some test that we can really sure we get what we want from WSS4J
+ NodeList nodeList = securedDocument.getElementsByTagNameNS(WSSConstants.TAG_wsse_UsernameToken.getNamespaceURI(), WSSConstants.TAG_wsse_UsernameToken.getLocalPart());
+ Assert.assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_wsse_Security.getLocalPart());
+
+ nodeList = securedDocument.getElementsByTagNameNS(WSSConstants.TAG_wsse_Password.getNamespaceURI(), WSSConstants.TAG_wsse_Password.getLocalPart());
+ Assert.assertEquals(nodeList.getLength(), 1);
+ Assert.assertEquals(((Element) nodeList.item(0)).getAttributeNS(null, WSSConstants.ATT_NULL_Type.getLocalPart()), WSSConstants.UsernameTokenPasswordType.PASSWORD_TEXT.getNamespace());
+
+ javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
+ transformer.transform(new DOMSource(securedDocument), new StreamResult(baos));
+ }
+
+ // It should pass with PASSWORD_TEXT
+ {
+ WSSSecurityProperties securityProperties = new WSSSecurityProperties();
+ securityProperties.setCallbackHandler(new CallbackHandlerImpl());
+ securityProperties.setUsernameTokenPasswordType(WSSConstants.UsernameTokenPasswordType.PASSWORD_TEXT);
+ InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
+
+ XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), null, null);
+
+ StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
+ }
+
+ // It should pass with null
+ {
+ WSSSecurityProperties securityProperties = new WSSSecurityProperties();
+ securityProperties.setCallbackHandler(new CallbackHandlerImpl());
+ securityProperties.setUsernameTokenPasswordType(null);
+ InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
+
+ XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), null, null);
+
+ StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
+ }
+
+ // It should fail with PASSWORD_DIGEST
+ {
+ WSSSecurityProperties securityProperties = new WSSSecurityProperties();
+ securityProperties.setCallbackHandler(new CallbackHandlerImpl());
+ securityProperties.setUsernameTokenPasswordType(WSSConstants.UsernameTokenPasswordType.PASSWORD_DIGEST);
+ InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
+
+ XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), null, null);
+
+ try {
+ StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
+ Assert.fail("Expected XMLStreamException");
+ } catch (XMLStreamException e) {
+ Assert.assertNotNull(e.getCause());
+ Assert.assertTrue(e.getCause() instanceof WSSecurityException);
+ Assert.assertEquals(e.getCause().getMessage(), "The security token could not be authenticated or authorized");
+ Assert.assertEquals(((WSSecurityException) e.getCause()).getFaultCode(), WSSecurityException.FAILED_AUTHENTICATION);
+ }
+ }
+ }
+
+
+}

0 comments on commit a4a6d99

Please sign in to comment.