SWS-711 - Upgrade to wss4j 1.6

This commit is contained in:
Arjen Poutsma
2012-05-09 10:30:37 +00:00
parent d567c3a3fb
commit 1f15b8cc2b
12 changed files with 141 additions and 349 deletions

View File

@@ -526,15 +526,11 @@
<dependency>
<groupId>org.apache.ws.security</groupId>
<artifactId>wss4j</artifactId>
<version>1.5.8</version>
<version>1.6.5</version>
<exclusions>
<exclusion>
<groupId>axis</groupId>
<artifactId>axis</artifactId>
</exclusion>
<exclusion>
<groupId>axis</groupId>
<artifactId>axis-ant</artifactId>
<groupId>xalan</groupId>
<artifactId>xalan</artifactId>
</exclusion>
<exclusion>
<groupId>xerces</groupId>
@@ -544,10 +540,6 @@
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
</exclusion>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring Security -->

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2008 the original author or authors.
* Copyright 2005-2012 the original author or authors.
*
* Licensed 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
* 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,
@@ -68,7 +68,7 @@ public abstract class KeyStoreUtils {
factoryBean.setPassword(password);
factoryBean.setType(type);
factoryBean.afterPropertiesSet();
return (KeyStore) factoryBean.getObject();
return factoryBean.getObject();
}
/**
@@ -117,7 +117,7 @@ public abstract class KeyStoreUtils {
factoryBean.setPassword(password);
factoryBean.setType(type);
factoryBean.afterPropertiesSet();
return (KeyStore) factoryBean.getObject();
return factoryBean.getObject();
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2005-2010 the original author or authors.
* Copyright 2005-2012 the original author or authors.
*
* Licensed 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
* 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,
@@ -16,26 +16,19 @@
package org.springframework.ws.soap.security.wss4j;
import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSPasswordCallback;
import org.springframework.ws.context.MessageContext;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.handler.RequestData;
import org.apache.ws.security.handler.WSHandler;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.message.token.Timestamp;
import org.w3c.dom.Document;
import org.springframework.ws.context.MessageContext;
/**
* @author Tareq Abed Rabbo
* @author Arjen Poutsma
@@ -46,8 +39,6 @@ class Wss4jHandler extends WSHandler {
/** Keys are constants from {@link WSHandlerConstants}; values are strings. */
private Properties options = new Properties();
private CallbackHandler securementCallbackHandler;
private String securementPassword;
private Crypto securementEncryptionCrypto;
@@ -61,12 +52,7 @@ class Wss4jHandler extends WSHandler {
}
@Override
protected boolean checkReceiverResults(Vector wsResult, Vector actions) {
return super.checkReceiverResults(wsResult, actions);
}
@Override
protected boolean checkReceiverResultsAnyOrder(Vector wsResult, Vector actions) {
protected boolean checkReceiverResultsAnyOrder(List<WSSecurityEngineResult> wsResult, List<Integer> actions) {
return super.checkReceiverResultsAnyOrder(wsResult, actions);
}
@@ -83,10 +69,6 @@ class Wss4jHandler extends WSHandler {
return options.getProperty(key);
}
void setSecurementCallbackHandler(CallbackHandler securementCallbackHandler) {
this.securementCallbackHandler = securementCallbackHandler;
}
void setSecurementPassword(String securementPassword) {
this.securementPassword = securementPassword;
}
@@ -99,48 +81,6 @@ class Wss4jHandler extends WSHandler {
this.securementSignatureCrypto = securementSignatureCrypto;
}
/** Gets the password first from securementCallbackHandler, then from securementPassword if not found. */
@Override
public WSPasswordCallback getPassword(String username,
int doAction,
String clsProp,
String refProp,
RequestData reqData) {
WSPasswordCallback callback;
if (securementCallbackHandler != null) {
int reason = 0;
switch (doAction) {
case WSConstants.UT:
case WSConstants.UT_SIGN:
reason = WSPasswordCallback.USERNAME_TOKEN;
break;
case WSConstants.SIGN:
reason = WSPasswordCallback.SIGNATURE;
break;
case WSConstants.ENCR:
reason = WSPasswordCallback.KEY_NAME;
break;
}
callback = new WSPasswordCallback(username, reason);
Callback[] callbacks = new Callback[]{callback};
try {
securementCallbackHandler.handle(callbacks);
}
catch (UnsupportedCallbackException ex) {
throw new Wss4jSecuritySecurementException(ex.getMessage(), ex);
}
catch (IOException ex) {
throw new Wss4jSecuritySecurementException(ex.getMessage(), ex);
}
}
else {
callback = new WSPasswordCallback(username, WSPasswordCallback.UNKNOWN);
callback.setPassword(securementPassword);
}
return callback;
}
@Override
public String getPassword(Object msgContext) {
return securementPassword;
@@ -172,18 +112,11 @@ class Wss4jHandler extends WSHandler {
}
@Override
protected void doSenderAction(int doAction, Document doc, RequestData reqData, Vector actions, boolean isRequest)
throws WSSecurityException {
protected void doSenderAction(int doAction,
Document doc,
RequestData reqData,
List<Integer> actions,
boolean isRequest) throws WSSecurityException {
super.doSenderAction(doAction, doc, reqData, actions, isRequest);
}
@Override
protected boolean verifyTimestamp(Timestamp timestamp, int timeToLive) throws WSSecurityException {
return super.verifyTimestamp(timestamp, timeToLive);
}
@Override
protected boolean verifyTrust(X509Certificate cert, RequestData reqData) throws WSSecurityException {
return super.verifyTrust(cert, reqData);
}
}

View File

@@ -19,7 +19,8 @@ package org.springframework.ws.soap.security.wss4j;
import java.io.IOException;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.Vector;
import java.util.ArrayList;
import java.util.List;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
@@ -49,6 +50,9 @@ import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.handler.WSHandlerResult;
import org.apache.ws.security.message.token.Timestamp;
import org.apache.ws.security.util.WSSecurityUtil;
import org.apache.ws.security.validate.Credential;
import org.apache.ws.security.validate.SignatureTrustValidator;
import org.apache.ws.security.validate.TimestampValidator;
import org.w3c.dom.Document;
/**
@@ -88,7 +92,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
private String securementActions;
private Vector<Integer> securementActionsVector;
private List<Integer> securementActionsVector;
private String securementUsername;
@@ -98,7 +102,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
private String validationActions;
private Vector<Integer> validationActionsVector;
private List<Integer> validationActionsVector;
private String validationActor;
@@ -118,11 +122,17 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
private final Wss4jHandler handler = new Wss4jHandler();
private final WSSecurityEngine securityEngine = WSSecurityEngine.getInstance();
private final WSSecurityEngine securityEngine = new WSSecurityEngine();
private boolean enableRevocation;
private boolean bspCompliant;
private boolean securementUseDerivedKey;
public void setSecurementActions(String securementActions) {
this.securementActions = securementActions;
securementActionsVector = new Vector<Integer>();
securementActionsVector = new ArrayList<Integer>();
try {
securementAction = WSSecurityUtil.decodeAction(securementActions, securementActionsVector);
}
@@ -142,24 +152,6 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
handler.setOption(WSHandlerConstants.ACTOR, securementActor);
}
/**
* Sets the {@link org.apache.ws.security.WSPasswordCallback} handler to use when securing messages.
*
* @see #setSecurementCallbackHandlers(CallbackHandler[])
*/
public void setSecurementCallbackHandler(CallbackHandler securementCallbackHandler) {
handler.setSecurementCallbackHandler(securementCallbackHandler);
}
/**
* Sets the {@link org.apache.ws.security.WSPasswordCallback} handlers to use when securing messages.
*
* @see #setSecurementCallbackHandler(CallbackHandler)
*/
public void setSecurementCallbackHandlers(CallbackHandler[] securementCallbackHandler) {
handler.setSecurementCallbackHandler(new CallbackHandlerChain(securementCallbackHandler));
}
public void setSecurementEncryptionCrypto(Crypto securementEncryptionCrypto) {
handler.setSecurementEncryptionCrypto(securementEncryptionCrypto);
}
@@ -354,6 +346,13 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
this.securementTimeToLive = securementTimeToLive;
}
/**
* Enables the derivation of keys as per the UsernameTokenProfile 1.1 spec. Default is {@code true}.
*/
public void setSecurementUseDerivedKey(boolean securementUseDerivedKey) {
this.securementUseDerivedKey = securementUseDerivedKey;
}
/** Sets the server-side time to live */
public void setValidationTimeToLive(int validationTimeToLive) {
if (validationTimeToLive <= 0) {
@@ -362,19 +361,11 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
this.validationTimeToLive = validationTimeToLive;
}
/** Sets the server-side time to live
* @deprecated Use {@link #setValidationTimeToLive(int)} instead.
*/
@Deprecated
public void setTimeToLive(int timeToLive) {
setValidationTimeToLive(timeToLive);
}
/** Sets the validation actions to be executed by the interceptor. */
public void setValidationActions(String actions) {
this.validationActions = actions;
try {
validationActionsVector = new Vector<Integer>();
validationActionsVector = new ArrayList<Integer>();
validationAction = WSSecurityUtil.decodeAction(actions, validationActionsVector);
}
catch (WSSecurityException ex) {
@@ -464,6 +455,20 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
wssConfig = config;
}
/**
* Set whether to enable CRL checking or not when verifying trust in a certificate.
*/
public void setEnableRevocation(boolean enableRevocation) {
this.enableRevocation = enableRevocation;
}
/**
* Set the WS-I Basic Security Profile compliance mode. Default is {@code true}.
*/
public void setBspCompliant(boolean bspCompliant) {
this.bspCompliant = bspCompliant;
}
public void afterPropertiesSet() throws Exception {
Assert.isTrue(validationActions != null || securementActions != null,
"validationActions or securementActions are required");
@@ -481,6 +486,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
// allow for qualified password types for .Net interoperability
securityEngine.getWssConfig().setAllowNamespaceQualifiedPasswordTypes(true);
securityEngine.getWssConfig().setWsiBSPCompliant(bspCompliant);
}
@Override
@@ -500,7 +506,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
// action, we need to pass an empty securementActionsVector to avoid
// NPE
if (securementAction == WSConstants.NO_SECURITY) {
securementActionsVector = new Vector<Integer>(0);
securementActionsVector = new ArrayList<Integer>(0);
}
handler.doSenderAction(securementAction, envelopeAsDocument, requestData, securementActionsVector, false);
@@ -532,6 +538,8 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
}
requestData.setTimeToLive(securementTimeToLive);
requestData.setUseDerivedKey(securementUseDerivedKey);
requestData.setWssConfig(wssConfig);
@@ -555,7 +563,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
// Header processing
try {
Vector<WSSecurityEngineResult> results = securityEngine
List<WSSecurityEngineResult> results = securityEngine
.processSecurityHeader(envelopeAsDocument, validationActor, validationCallbackHandler,
validationSignatureCrypto, validationDecryptionCrypto);
@@ -588,13 +596,15 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
/**
* Checks whether the received headers match the configured validation actions. Subclasses could override this method
* for custom verification behavior.
*
*
* @param results the results of the validation function
* @param validationActionsVector the decoded validation actions
* @param validationActions the decoded validation actions
* @throws Wss4jSecurityValidationException if the results are deemed invalid
*/
protected void checkResults(Vector<WSSecurityEngineResult> results, Vector<Integer> validationActionsVector)
protected void checkResults(List<WSSecurityEngineResult> results, List<Integer> validationActions)
throws Wss4jSecurityValidationException {
if (!handler.checkReceiverResultsAnyOrder(results, validationActionsVector)) {
if (!handler.checkReceiverResultsAnyOrder(results, validationActions)) {
throw new Wss4jSecurityValidationException("Security processing failed (actions mismatch)");
}
}
@@ -604,10 +614,10 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
* Confirmation require this.
*/
@SuppressWarnings("unchecked")
private void updateContextWithResults(MessageContext messageContext, Vector<WSSecurityEngineResult> results) {
Vector<WSHandlerResult> handlerResults;
if ((handlerResults = (Vector<WSHandlerResult>) messageContext.getProperty(WSHandlerConstants.RECV_RESULTS)) == null) {
handlerResults = new Vector<WSHandlerResult>();
private void updateContextWithResults(MessageContext messageContext, List<WSSecurityEngineResult> results) {
List<WSHandlerResult> handlerResults;
if ((handlerResults = (List<WSHandlerResult>) messageContext.getProperty(WSHandlerConstants.RECV_RESULTS)) == null) {
handlerResults = new ArrayList<WSHandlerResult>();
messageContext.setProperty(WSHandlerConstants.RECV_RESULTS, handlerResults);
}
WSHandlerResult rResult = new WSHandlerResult(validationActor, results);
@@ -616,35 +626,47 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
}
/** Verifies the trust of a certificate. */
protected void verifyCertificateTrust(Vector<WSSecurityEngineResult> results) throws WSSecurityException {
RequestData requestData = new RequestData();
requestData.setSigCrypto(validationSignatureCrypto);
protected void verifyCertificateTrust(List<WSSecurityEngineResult> results) throws WSSecurityException {
WSSecurityEngineResult actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
if (actionResult != null) {
X509Certificate returnCert = (X509Certificate) actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE)
;
if (!handler.verifyTrust(returnCert, requestData)) {
throw new Wss4jSecurityValidationException("The certificate used for the signature is not trusted");
}
X509Certificate returnCert =
(X509Certificate) actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
Credential credential = new Credential();
credential.setCertificates(new X509Certificate[] { returnCert});
RequestData requestData = new RequestData();
requestData.setSigCrypto(validationSignatureCrypto);
requestData.setEnableRevocation(enableRevocation);
SignatureTrustValidator validator = new SignatureTrustValidator();
validator.validate(credential, requestData);
}
}
/** Verifies the timestamp. */
protected void verifyTimestamp(Vector<WSSecurityEngineResult> results) throws WSSecurityException {
protected void verifyTimestamp(List<WSSecurityEngineResult> results) throws WSSecurityException {
WSSecurityEngineResult actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.TS);
if (actionResult != null) {
Timestamp timestamp = (Timestamp) actionResult.get(WSSecurityEngineResult.TAG_TIMESTAMP);
if (timestamp != null && timestampStrict) {
if (!handler.verifyTimestamp(timestamp, validationTimeToLive)) {
throw new Wss4jSecurityValidationException("Invalid timestamp : " + timestamp.getID());
}
Credential credential = new Credential();
credential.setTimestamp(timestamp);
RequestData requestData = new RequestData();
WSSConfig config = new WSSConfig();
config.setTimeStampTTL(validationTimeToLive);
config.setTimeStampStrict(timestampStrict);
requestData.setWssConfig(config);
TimestampValidator validator = new TimestampValidator();
validator.validate(credential, requestData);
}
}
}
private void processPrincipal(Vector<WSSecurityEngineResult> results) {
private void processPrincipal(List<WSSecurityEngineResult> results) {
WSSecurityEngineResult actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.UT);
if (actionResult != null) {

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2005-2010 the original author or authors.
* Copyright 2005-2012 the original author or authors.
*
* Licensed 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
* 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,
@@ -20,11 +20,11 @@ import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
import org.springframework.ws.soap.security.callback.CleanupCallback;
import org.apache.ws.security.WSPasswordCallback;
/**
* Abstract base class for {@link javax.security.auth.callback.CallbackHandler} implementations that handle {@link
* WSPasswordCallback} callbacks.
@@ -56,20 +56,14 @@ public abstract class AbstractWsPasswordCallbackHandler extends AbstractCallback
case WSPasswordCallback.SIGNATURE:
handleSignature(passwordCallback);
break;
case WSPasswordCallback.KEY_NAME:
handleKeyName(passwordCallback);
break;
case WSPasswordCallback.USERNAME_TOKEN_UNKNOWN:
handleUsernameTokenUnknown(passwordCallback);
break;
case WSPasswordCallback.SECURITY_CONTEXT_TOKEN:
handleSecurityContextToken(passwordCallback);
break;
case WSPasswordCallback.CUSTOM_TOKEN:
handleCustomToken(passwordCallback);
break;
case WSPasswordCallback.ENCRYPTED_KEY_TOKEN:
handleEncryptedKeyToken(callback);
case WSPasswordCallback.SECRET_KEY:
handleSecretKey(passwordCallback);
break;
default:
throw new UnsupportedCallbackException(callback,
@@ -91,7 +85,7 @@ public abstract class AbstractWsPasswordCallbackHandler extends AbstractCallback
* Invoked when the callback has a {@link WSPasswordCallback#DECRYPT} usage.
* <p/>
* This method is invoked when WSS4J needs a password to get the private key of the {@link
* WSPasswordCallback#getIdentifer() identifier} (username) from the keystore. WSS4J uses this private key to
* WSPasswordCallback#getIdentifier() identifier} (username) from the keystore. WSS4J uses this private key to
* decrypt the session (symmetric) key. Because the encryption method uses the public key to encrypt the session key
* it needs no password (a public key is usually not protected by a password).
* <p/>
@@ -116,7 +110,7 @@ public abstract class AbstractWsPasswordCallbackHandler extends AbstractCallback
* Invoked when the callback has a {@link WSPasswordCallback#SIGNATURE} usage.
* <p/>
* This method is invoked when WSS4J needs the password to get the private key of the {@link
* WSPasswordCallback#getIdentifer() identifier} (username) from the keystore. WSS4J uses this private key to
* WSPasswordCallback#getIdentifier() identifier} (username) from the keystore. WSS4J uses this private key to
* produce a signature. The signature verfication uses the public key to verfiy the signature.
* <p/>
* Default implementation throws an {@link UnsupportedCallbackException}.
@@ -125,33 +119,6 @@ public abstract class AbstractWsPasswordCallbackHandler extends AbstractCallback
throw new UnsupportedCallbackException(callback);
}
/**
* Invoked when the callback has a {@link WSPasswordCallback#KEY_NAME} usage.
* <p/>
* This method is invoked when WSS4J needs the key associated with the {@link WSPasswordCallback#getIdentifer()
* identifier}. WSS4J uses this key to encrypt or decrypt parts of the SOAP request. Note, the key must match the
* symmetric encryption/decryption algorithm specified (refer to {@link org.apache.ws.security.handler.WSHandlerConstants#ENC_SYM_ALGO}).
* <p/>
* Default implementation throws an {@link UnsupportedCallbackException}.
*/
protected void handleKeyName(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
throw new UnsupportedCallbackException(callback);
}
/**
* Invoked when the callback has a {@link WSPasswordCallback#USERNAME_TOKEN_UNKNOWN} usage.
* <p/>
* This method is invoked for a not specified password type or a plain text password type. Only the {@link
* WSPasswordCallback#getPassword() password} is set. The callback class now may check if the username and password
* match. If they don't match, the subclass should throw an exception.
* <p/>
* Default implementation throws an {@link UnsupportedCallbackException}.
*/
protected void handleUsernameTokenUnknown(WSPasswordCallback callback)
throws IOException, UnsupportedCallbackException {
throw new UnsupportedCallbackException(callback);
}
/**
* Invoked when the callback has a {@link WSPasswordCallback#SECURITY_CONTEXT_TOKEN} usage.
* <p/>
@@ -174,11 +141,11 @@ public abstract class AbstractWsPasswordCallbackHandler extends AbstractCallback
}
/**
* Invoked when the callback has a {@link WSPasswordCallback#ENCRYPTED_KEY_TOKEN} usage.
* Invoked when the callback has a {@link WSPasswordCallback#SECRET_KEY} usage.
* <p/>
* Default implementation throws an {@link UnsupportedCallbackException}.
*/
protected void handleEncryptedKeyToken(Callback callback) throws IOException, UnsupportedCallbackException {
protected void handleSecretKey(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
throw new UnsupportedCallbackException(callback);
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2005-2010 the original author or authors.
* Copyright 2005-2012 the original author or authors.
*
* Licensed 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
* 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,
@@ -23,12 +23,11 @@ import java.security.KeyStore;
import javax.crypto.SecretKey;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSSecurityException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.ws.soap.security.support.KeyStoreUtils;
import org.apache.ws.security.WSPasswordCallback;
/**
* Callback handler that uses Java Security <code>KeyStore</code>s to handle cryptographic callbacks. Allows for
* specific key stores to be set for various cryptographic operations.
@@ -87,8 +86,9 @@ public class KeyStoreCallbackHandler extends AbstractWsPasswordCallbackHandler i
callback.setPassword(privateKeyPassword);
}
@Override
protected void handleKeyName(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
protected void handleSecretKey(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
try {
String identifier = callback.getIdentifier();
Key key = keyStore.getKey(identifier, symmetricKeyPassword);
@@ -96,11 +96,11 @@ public class KeyStoreCallbackHandler extends AbstractWsPasswordCallbackHandler i
callback.setKey(key.getEncoded());
}
else {
throw new WSSecurityException("Key [" + key + "] is not a javax.crypto.SecretKey");
logger.error("Key [" + key + "] is not a javax.crypto.SecretKey");
}
}
catch (GeneralSecurityException ex) {
throw new WSSecurityException("Could not obtain symmetric key", ex);
logger.error("Could not obtain symmetric key", ex);
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2005-2010 the original author or authors.
* Copyright 2005-2012 the original author or authors.
*
* Licensed 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
* 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,
@@ -26,10 +26,9 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSSecurityException;
/**
* Simple callback handler that validates passwords agains a in-memory <code>Properties</code> object. Password
* Simple callback handler that validates passwords against a in-memory <code>Properties</code> object. Password
* validation is done on a case-sensitive basis.
*
* @author Tareq Abed Rabbo
@@ -65,15 +64,4 @@ public class SimplePasswordValidationCallbackHandler extends AbstractWsPasswordC
callback.setPassword(users.get(identifier));
}
@Override
protected void handleUsernameTokenUnknown(WSPasswordCallback callback)
throws IOException, UnsupportedCallbackException {
String identifier = callback.getIdentifier();
String storedPassword = users.get(identifier);
String givenPassword = callback.getPassword();
if (storedPassword == null || !storedPassword.equals(givenPassword)) {
throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
}
}
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed 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.springframework.ws.soap.security.wss4j.callback;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSSecurityException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.Assert;
import org.springframework.ws.soap.security.callback.CleanupCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
/**
* Callback handler that validates a certificate uses an Spring Security <code>AuthenticationManager</code>. Logic based
* on Spring Security's <code>BasicProcessingFilter</code>.
* <p/>
* This handler requires an Spring Security <code>AuthenticationManager</code> to operate. It can be set using the
* <code>authenticationManager</code> property. An Spring Security <code>UsernamePasswordAuthenticationToken</code> is
* created with the username as principal and password as credentials.
*
* @author Arjen Poutsma
* @see org.springframework.security.authentication.UsernamePasswordAuthenticationToken
* @see org.springframework.security.ui.basicauth.BasicProcessingFilter
* @since 1.5.0
*/
public class SpringPlainTextPasswordValidationCallbackHandler extends AbstractWsPasswordCallbackHandler
implements InitializingBean {
private AuthenticationManager authenticationManager;
private boolean ignoreFailure = false;
/** Sets the Spring Security authentication manager. Required. */
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public void setIgnoreFailure(boolean ignoreFailure) {
this.ignoreFailure = ignoreFailure;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(authenticationManager, "authenticationManager is required");
}
@Override
protected void handleCleanup(CleanupCallback callback) throws IOException, UnsupportedCallbackException {
SecurityContextHolder.clearContext();
}
@Override
protected void handleUsernameTokenUnknown(WSPasswordCallback callback)
throws IOException, UnsupportedCallbackException {
String identifier = callback.getIdentifier();
try {
Authentication authResult = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(identifier, callback.getPassword()));
if (logger.isDebugEnabled()) {
logger.debug("Authentication success: " + authResult.toString());
}
SecurityContextHolder.getContext().setAuthentication(authResult);
}
catch (AuthenticationException failed) {
if (logger.isDebugEnabled()) {
logger.debug("Authentication request for user '" + identifier + "' failed: " + failed.toString());
}
SecurityContextHolder.clearContext();
if (!ignoreFailure) {
throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION, null, null, failed);
}
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2005-2010 the original author or authors.
* Copyright 2005-2012 the original author or authors.
*
* Licensed 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
* 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,
@@ -19,35 +19,32 @@ package org.springframework.ws.soap.security.wss4j.callback;
import java.io.IOException;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSUsernameTokenPrincipal;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.cache.NullUserCache;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.userdetails.cache.NullUserCache;
import org.springframework.util.Assert;
import org.springframework.ws.soap.security.callback.CleanupCallback;
import org.springframework.ws.soap.security.support.SpringSecurityUtils;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSUsernameTokenPrincipal;
/**
* Callback handler that validates a password digest using an Spring Security <code>UserDetailsService</code>. Logic
* based on Spring Security's <code>DigestProcessingFilter</code>.
* Callback handler that validates a plain text or digest password using an Spring Security {@code UserDetailsService}.
* <p/>
* An Spring Security <code>UserDetailService</code> is used to load <code>UserDetails</code> from. The digest of the
* An Spring Security {@link UserDetailsService} is used to load {@link UserDetails} from. The digest of the
* password contained in this details object is then compared with the digest in the message.
*
* @author Arjen Poutsma
* @see org.springframework.security.core.userdetails.UserDetailsService
* @see org.springframework.security.ui.digestauth.DigestProcessingFilter
* @since 1.5.0
*/
public class SpringDigestPasswordValidationCallbackHandler extends AbstractWsPasswordCallbackHandler
public class SpringSecurityPasswordValidationCallbackHandler extends AbstractWsPasswordCallbackHandler
implements InitializingBean {
private UserCache userCache = new NullUserCache();

View File

@@ -19,17 +19,13 @@ package org.springframework.ws.soap.security.wss4j;
import java.util.Properties;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.memory.InMemoryDaoImpl;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.security.wss4j.callback.SpringDigestPasswordValidationCallbackHandler;
import org.springframework.ws.soap.security.wss4j.callback.SpringPlainTextPasswordValidationCallbackHandler;
import org.springframework.ws.soap.security.wss4j.callback.SpringSecurityPasswordValidationCallbackHandler;
import org.apache.ws.security.WSConstants;
import org.junit.After;
@@ -104,28 +100,18 @@ public abstract class Wss4jMessageInterceptorSpringSecurityCallbackHandlerTestCa
else {
interceptor.setSecurementActions(actions);
}
SpringSecurityPasswordValidationCallbackHandler callbackHandler =
new SpringSecurityPasswordValidationCallbackHandler();
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager(users);
callbackHandler.setUserDetailsService(userDetailsManager);
if (digest) {
SpringDigestPasswordValidationCallbackHandler callbackHandler =
new SpringDigestPasswordValidationCallbackHandler();
InMemoryDaoImpl userDetailsService = new InMemoryDaoImpl();
userDetailsService.setUserProperties(users);
userDetailsService.afterPropertiesSet();
callbackHandler.setUserDetailsService(userDetailsService);
interceptor.setSecurementPasswordType(WSConstants.PW_DIGEST);
interceptor.setValidationCallbackHandler(callbackHandler);
interceptor.afterPropertiesSet();
}
else {
SpringPlainTextPasswordValidationCallbackHandler callbackHandler =
new SpringPlainTextPasswordValidationCallbackHandler();
Authentication authResult = new TestingAuthenticationToken("Bert", "Ernie");
expect(authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("Bert", "Ernie"))).andReturn(authResult);
callbackHandler.setAuthenticationManager(authenticationManager);
callbackHandler.afterPropertiesSet();
interceptor.setSecurementPasswordType(WSConstants.PW_TEXT);
interceptor.setValidationCallbackHandler(callbackHandler);
interceptor.afterPropertiesSet();
}
interceptor.setValidationCallbackHandler(callbackHandler);
interceptor.afterPropertiesSet();
replay(authenticationManager);
return interceptor;
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2005-2010 the original author or authors.
* Copyright 2005-2012 the original author or authors.
*
* Licensed 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
* 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,
@@ -35,14 +35,14 @@ public class KeyStoreCallbackHandlerTest {
@Before
public void setUp() throws Exception {
callbackHandler = new KeyStoreCallbackHandler();
callback = new WSPasswordCallback("secretkey", WSPasswordCallback.KEY_NAME);
callback = new WSPasswordCallback("secretkey", WSPasswordCallback.SECRET_KEY);
KeyStoreFactoryBean factory = new KeyStoreFactoryBean();
factory.setLocation(new ClassPathResource("private.jks"));
factory.setPassword("123456");
factory.setType("JCEKS");
factory.afterPropertiesSet();
KeyStore keyStore = (KeyStore) factory.getObject();
KeyStore keyStore = factory.getObject();
callbackHandler.setKeyStore(keyStore);
callbackHandler.setSymmetricKeyPassword("123456");
}

View File

@@ -36,9 +36,9 @@ import org.junit.Test;
import static org.easymock.EasyMock.*;
/** @author tareq */
public class SpringDigestPasswordValidationCallbackHandlerTest {
public class SpringSecurityPasswordValidationCallbackHandlerTest {
private SpringDigestPasswordValidationCallbackHandler callbackHandler;
private SpringSecurityPasswordValidationCallbackHandler callbackHandler;
private SimpleGrantedAuthority grantedAuthority;
@@ -48,7 +48,7 @@ public class SpringDigestPasswordValidationCallbackHandlerTest {
@Before
public void setUp() throws Exception {
callbackHandler = new SpringDigestPasswordValidationCallbackHandler();
callbackHandler = new SpringSecurityPasswordValidationCallbackHandler();
grantedAuthority = new SimpleGrantedAuthority("ROLE_1");
user = new User("Ernie", "Bert", true, true, true, true, Collections.singleton(grantedAuthority));