Done implementing SWS-207
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2008 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.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
/**
|
||||
* Represents a chain of <code>CallbackHandler</code>s. For each callback, each of the handlers is called in term. If a
|
||||
* handler throws a <code>UnsupportedCallbackException</code>, the next handler is tried.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class CallbackHandlerChain extends AbstractCallbackHandler {
|
||||
|
||||
private final CallbackHandler[] callbackHandlers;
|
||||
|
||||
public CallbackHandlerChain(CallbackHandler[] callbackHandlers) {
|
||||
this.callbackHandlers = callbackHandlers;
|
||||
}
|
||||
|
||||
public CallbackHandler[] getCallbackHandlers() {
|
||||
return callbackHandlers;
|
||||
}
|
||||
|
||||
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
boolean allUnsupported = true;
|
||||
for (int i = 0; i < callbackHandlers.length; i++) {
|
||||
CallbackHandler callbackHandler = callbackHandlers[i];
|
||||
try {
|
||||
callbackHandler.handle(new Callback[]{callback});
|
||||
allUnsupported = false;
|
||||
}
|
||||
catch (UnsupportedCallbackException ex) {
|
||||
// if an UnsupportedCallbackException occurs, go to the next handler
|
||||
}
|
||||
}
|
||||
if (allUnsupported) {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ public class KeyStoreFactoryBean implements FactoryBean, InitializingBean {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
public Object getObject() {
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2008 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.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyStore;
|
||||
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Generic utility methods for dealing with {@link KeyStore} objects.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public abstract class KeyStoreUtils {
|
||||
|
||||
/**
|
||||
* Loads the key store indicated by system properties. This method tries to load a key store by consulting the
|
||||
* following system properties:<code>javax.net.ssl.keyStore</code>, <code>javax.net.ssl.keyStorePassword</code>, and
|
||||
* <code>javax.net.ssl.keyStoreType</code>.
|
||||
* <p/>
|
||||
* If these properties specify a file with an appropriate password, the factory uses this file for the key store. If
|
||||
* that file does not exist, then a default, empty keystore is created.
|
||||
* <p/>
|
||||
* This behavior corresponds to the standard J2SDK behavior for SSL key stores.
|
||||
*
|
||||
* @see <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html#X509KeyManager">The
|
||||
* standard J2SDK SSL key store mechanism</a>
|
||||
*/
|
||||
public static KeyStore loadDefaultKeyStore() throws GeneralSecurityException, IOException {
|
||||
Resource location = null;
|
||||
String type = null;
|
||||
String password = null;
|
||||
String locationProperty = System.getProperty("javax.net.ssl.keyStore");
|
||||
if (StringUtils.hasLength(locationProperty)) {
|
||||
File f = new File(locationProperty);
|
||||
if (f.exists() && f.isFile() && f.canRead()) {
|
||||
location = new FileSystemResource(f);
|
||||
}
|
||||
String passwordProperty = System.getProperty("javax.net.ssl.keyStorePassword");
|
||||
if (StringUtils.hasLength(passwordProperty)) {
|
||||
password = passwordProperty;
|
||||
}
|
||||
type = System.getProperty("javax.net.ssl.trustStore");
|
||||
}
|
||||
// use the factory bean here, easier to setup
|
||||
KeyStoreFactoryBean factoryBean = new KeyStoreFactoryBean();
|
||||
factoryBean.setLocation(location);
|
||||
factoryBean.setPassword(password);
|
||||
factoryBean.setType(type);
|
||||
factoryBean.afterPropertiesSet();
|
||||
return (KeyStore) factoryBean.getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a default trust store. This method uses the following algorithm: <ol> <li> If the system property
|
||||
* <code>javax.net.ssl.trustStore</code> is defined, its value is loaded. If the
|
||||
* <code>javax.net.ssl.trustStorePassword</code> system property is also defined, its value is used as a password.
|
||||
* If the <code>javax.net.ssl.trustStoreType</code> system property is defined, its value is used as a key store
|
||||
* type.
|
||||
* <p/>
|
||||
* If <code>javax.net.ssl.trustStore</code> is defined but the specified file does not exist, then a default, empty
|
||||
* trust store is created. </li> <li> If the <code>javax.net.ssl.trustStore</code> system property was not
|
||||
* specified, but if the file <code>$JAVA_HOME/lib/security/jssecacerts</code> exists, that file is used. </li>
|
||||
* Otherwise, <li>If the file <code>$JAVA_HOME/lib/security/cacerts</code> exists, that file is used. </ol>
|
||||
* <p/>
|
||||
* This behavior corresponds to the standard J2SDK behavior for SSL trust stores.
|
||||
*
|
||||
* @see <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager">The
|
||||
* standard J2SDK SSL trust store mechanism</a>
|
||||
*/
|
||||
public static KeyStore loadDefaultTrustStore() throws GeneralSecurityException, IOException {
|
||||
Resource location = null;
|
||||
String type = null;
|
||||
String password = null;
|
||||
String locationProperty = System.getProperty("javax.net.ssl.trustStore");
|
||||
if (StringUtils.hasLength(locationProperty)) {
|
||||
File f = new File(locationProperty);
|
||||
if (f.exists() && f.isFile() && f.canRead()) {
|
||||
location = new FileSystemResource(f);
|
||||
}
|
||||
String passwordProperty = System.getProperty("javax.net.ssl.trustStorePassword");
|
||||
if (StringUtils.hasLength(passwordProperty)) {
|
||||
password = passwordProperty;
|
||||
}
|
||||
type = System.getProperty("javax.net.ssl.trustStoreType");
|
||||
}
|
||||
else {
|
||||
String javaHome = System.getProperty("java.home");
|
||||
location = new FileSystemResource(javaHome + "/lib/security/jssecacerts");
|
||||
if (!location.exists()) {
|
||||
location = new FileSystemResource(javaHome + "/lib/security/cacerts");
|
||||
}
|
||||
}
|
||||
// use the factory bean here, easier to setup
|
||||
KeyStoreFactoryBean factoryBean = new KeyStoreFactoryBean();
|
||||
factoryBean.setLocation(location);
|
||||
factoryBean.setPassword(password);
|
||||
factoryBean.setType(type);
|
||||
factoryBean.afterPropertiesSet();
|
||||
return (KeyStore) factoryBean.getObject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,39 +46,31 @@ import org.springframework.ws.soap.saaj.SaajSoapMessage;
|
||||
import org.springframework.ws.soap.security.AbstractWsSecurityInterceptor;
|
||||
import org.springframework.ws.soap.security.WsSecuritySecurementException;
|
||||
import org.springframework.ws.soap.security.WsSecurityValidationException;
|
||||
import org.springframework.ws.soap.security.callback.CallbackHandlerChain;
|
||||
|
||||
/**
|
||||
* A WS-Security endpoint interceptor based on Apache's WSS4J. This inteceptor supports messages created by the {@link
|
||||
* org.springframework.ws.soap.axiom.AxiomSoapMessageFactory} and the {@link org.springframework.ws.soap.saaj.SaajSoapMessageFactory}.
|
||||
* <p/>
|
||||
* The validation and securement actions executed by this interceptor are configured via <code>validationActions</code> and
|
||||
* <code>securementActions</code> properties, respectively. Actions should be passed as a space-separated strings.
|
||||
* The validation and securement actions executed by this interceptor are configured via <code>validationActions</code>
|
||||
* and <code>securementActions</code> properties, respectively. Actions should be passed as a space-separated strings.
|
||||
* <p/>
|
||||
* Valid <strong>validation</strong> actions are:
|
||||
*
|
||||
* <blockquote><table>
|
||||
* <tr><th>Validation action</th><th>Description</th></tr>
|
||||
* <tr><td><code>UsernameToken</code></td><td>Validates username token</td></tr>
|
||||
* <tr><td><code>Timestamp</code></td><td>Validates the timestamp</td></tr>
|
||||
* <tr><td><code>Encrypt</code></td><td>Decrypts the message</td></tr>
|
||||
* <tr><td><code>Signature</code></td><td>Validates the signature</td></tr>
|
||||
* <tr><td><code>NoSecurity</code></td><td>No action performed</td></tr>
|
||||
* </table></blockquote>
|
||||
* <p/>
|
||||
* <strong>Securement</strong> actions are:
|
||||
* <blockquote><table>
|
||||
* <tr><th>Securement action</th><th>Description</th></tr>
|
||||
* <tr><td><code>UsernameToken</td></code><td>Adds a username token</td></tr>
|
||||
* <tr><td><code>UsernameTokenSignature</td></code><td>Adds a username token and a signature username token secrect key</td></tr>
|
||||
* <tr><td><code>Timestamp</td></code><td>Adds a timestamp</td></tr>
|
||||
* <tr><td><code>Encrypt</td></code><td>Encrypts the response</td></tr>
|
||||
* <tr><td><code>Signature</td></code><td>Signs the response</td></tr>
|
||||
* <tr><td><code>NoSecurity</td></code><td>No action performed</td></tr>
|
||||
* </table></blockquote>
|
||||
* <blockquote><table> <tr><th>Validation action</th><th>Description</th></tr> <tr><td><code>UsernameToken</code></td><td>Validates
|
||||
* username token</td></tr> <tr><td><code>Timestamp</code></td><td>Validates the timestamp</td></tr>
|
||||
* <tr><td><code>Encrypt</code></td><td>Decrypts the message</td></tr> <tr><td><code>Signature</code></td><td>Validates
|
||||
* the signature</td></tr> <tr><td><code>NoSecurity</code></td><td>No action performed</td></tr> </table></blockquote>
|
||||
* <p/>
|
||||
* The order of the actions that the client performed to secure the messages is significant and is
|
||||
* enforced by the interceptor.
|
||||
*
|
||||
* <strong>Securement</strong> actions are: <blockquote><table> <tr><th>Securement action</th><th>Description</th></tr>
|
||||
* <tr><td><code>UsernameToken</td></code><td>Adds a username token</td></tr> <tr><td><code>UsernameTokenSignature</td></code><td>Adds
|
||||
* a username token and a signature username token secrect key</td></tr> <tr><td><code>Timestamp</td></code><td>Adds a
|
||||
* timestamp</td></tr> <tr><td><code>Encrypt</td></code><td>Encrypts the response</td></tr>
|
||||
* <tr><td><code>Signature</td></code><td>Signs the response</td></tr> <tr><td><code>NoSecurity</td></code><td>No action
|
||||
* performed</td></tr> </table></blockquote>
|
||||
* <p/>
|
||||
* The order of the actions that the client performed to secure the messages is significant and is enforced by the
|
||||
* interceptor.
|
||||
*
|
||||
* @author Tareq Abed Rabbo
|
||||
* @author Arjen Poutsma
|
||||
@@ -89,8 +81,6 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
|
||||
|
||||
public static final String SECUREMENT_USER_PROPERTY_NAME = "Wss4jSecurityInterceptor.securementUser";
|
||||
|
||||
private CallbackHandler validationCallbackHandler;
|
||||
|
||||
private int securementAction;
|
||||
|
||||
private String securementActions;
|
||||
@@ -99,9 +89,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
|
||||
|
||||
private String securementUsername;
|
||||
|
||||
private boolean timestampStrict = true;
|
||||
|
||||
private int timeToLive = 300;
|
||||
private CallbackHandler validationCallbackHandler;
|
||||
|
||||
private int validationAction;
|
||||
|
||||
@@ -115,10 +103,14 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
|
||||
|
||||
private Crypto validationSignatureCrypto;
|
||||
|
||||
private Wss4jHandler handler = new Wss4jHandler();
|
||||
private boolean timestampStrict = true;
|
||||
|
||||
private boolean enableSignatureConfirmation;
|
||||
|
||||
private int timeToLive = 300;
|
||||
|
||||
private Wss4jHandler handler = new Wss4jHandler();
|
||||
|
||||
public void setSecurementActions(String securementActions) {
|
||||
this.securementActions = securementActions;
|
||||
securementActionsVector = new Vector();
|
||||
@@ -141,10 +133,24 @@ 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);
|
||||
}
|
||||
@@ -333,10 +339,24 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
|
||||
this.validationActor = validationActor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link org.apache.ws.security.WSPasswordCallback} handler to use when validating messages.
|
||||
*
|
||||
* @see #setValidationCallbackHandlers(CallbackHandler[])
|
||||
*/
|
||||
public void setValidationCallbackHandler(CallbackHandler callbackHandler) {
|
||||
this.validationCallbackHandler = callbackHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link org.apache.ws.security.WSPasswordCallback} handlers to use when validating messages.
|
||||
*
|
||||
* @see #setValidationCallbackHandler(CallbackHandler)
|
||||
*/
|
||||
public void setValidationCallbackHandlers(CallbackHandler[] callbackHandler) {
|
||||
this.validationCallbackHandler = new CallbackHandlerChain(callbackHandler);
|
||||
}
|
||||
|
||||
/** Sets the Crypto to use to decrypt incoming messages */
|
||||
public void setValidationDecryptionCrypto(Crypto decryptionCrypto) {
|
||||
this.validationDecryptionCrypto = decryptionCrypto;
|
||||
@@ -410,6 +430,9 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
|
||||
if (securementAction == WSConstants.NO_SECURITY && !enableSignatureConfirmation) {
|
||||
return;
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Securing message [" + soapMessage + "] with actions [" + securementActions + "]");
|
||||
}
|
||||
RequestData requestData = initializeRequestData(messageContext);
|
||||
|
||||
Document envelopeAsDocument = toDocument(soapMessage);
|
||||
@@ -450,7 +473,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
|
||||
protected void validateMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws WsSecurityValidationException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Validating message [" + soapMessage + "] with actions " + validationActions);
|
||||
logger.debug("Validating message [" + soapMessage + "] with actions [" + validationActions + "]");
|
||||
}
|
||||
|
||||
if (validationAction == WSConstants.NO_SECURITY) {
|
||||
@@ -508,11 +531,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
|
||||
messageContext.setProperty(WSHandlerConstants.RECV_RESULTS, handlerResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the trust of a certificate.
|
||||
* @param results
|
||||
* @throws WSSecurityException
|
||||
*/
|
||||
/** Verifies the trust of a certificate. */
|
||||
protected void verifyCertificateTrust(Vector results) throws WSSecurityException {
|
||||
RequestData requestData = new RequestData();
|
||||
requestData.setSigCrypto(validationSignatureCrypto);
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright 2008 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 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;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link javax.security.auth.callback.CallbackHandler} implementations that handle {@link
|
||||
* WSPasswordCallback} callbacks.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public abstract class AbstractWsPasswordCallbackHandler extends AbstractCallbackHandler {
|
||||
|
||||
/**
|
||||
* Handles {@link WSPasswordCallback} callbacks. Inspects the callback {@link WSPasswordCallback#getUsage() usage}
|
||||
* code, and calls the various <code>handle*</code> template methods.
|
||||
*
|
||||
* @param callback the callback
|
||||
* @throws IOException in case of I/O errors
|
||||
* @throws UnsupportedCallbackException when the callback is not supported
|
||||
*/
|
||||
protected final void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
if (callback instanceof WSPasswordCallback) {
|
||||
WSPasswordCallback passwordCallback = (WSPasswordCallback) callback;
|
||||
switch (passwordCallback.getUsage()) {
|
||||
case WSPasswordCallback.DECRYPT:
|
||||
handleDecrypt(passwordCallback);
|
||||
break;
|
||||
case WSPasswordCallback.USERNAME_TOKEN:
|
||||
handleUsernameToken(passwordCallback);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedCallbackException(callback,
|
||||
"Unknown usage [" + passwordCallback.getUsage() + "]");
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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/>
|
||||
* Default implementation throws an {@link UnsupportedCallbackException}.
|
||||
*/
|
||||
protected void handleDecrypt(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the callback has a {@link WSPasswordCallback#USERNAME_TOKEN} usage.
|
||||
* <p/>
|
||||
* This method is invoked when WSS4J needs the password to fill in or to verify a UsernameToken.
|
||||
* <p/>
|
||||
* Default implementation throws an {@link UnsupportedCallbackException}.
|
||||
*/
|
||||
protected void handleUsernameToken(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* produce a signature. The signature verfication uses the public key to verfiy the signature.
|
||||
* <p/>
|
||||
* Default implementation throws an {@link UnsupportedCallbackException}.
|
||||
*/
|
||||
protected void handleSignature(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
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/>
|
||||
* This method is invoked when WSS4J needs the key to to be associated with a SecurityContextToken.
|
||||
* <p/>
|
||||
* Default implementation throws an {@link UnsupportedCallbackException}.
|
||||
*/
|
||||
protected void handleSecurityContextToken(WSPasswordCallback callback)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the callback has a {@link WSPasswordCallback#CUSTOM_TOKEN} usage.
|
||||
* <p/>
|
||||
* Default implementation throws an {@link UnsupportedCallbackException}.
|
||||
*/
|
||||
protected void handleCustomToken(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the callback has a {@link WSPasswordCallback#ENCRYPTED_KEY_TOKEN} usage.
|
||||
* <p/>
|
||||
* Default implementation throws an {@link UnsupportedCallbackException}.
|
||||
*/
|
||||
protected void handleEncryptedKeyToken(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 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 java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStore.Entry;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.security.auth.callback.Callback;
|
||||
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.util.Assert;
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
|
||||
/**
|
||||
* A base class for callback handlers.
|
||||
*
|
||||
* @author Tareq Abed Rabbo
|
||||
*/
|
||||
public abstract class AbstractWss4jCallbackHandler extends AbstractCallbackHandler implements InitializingBean {
|
||||
|
||||
private boolean passwordDigestRequired;
|
||||
|
||||
private boolean passwordPlainTextRequired;
|
||||
|
||||
private String keyPassword;
|
||||
|
||||
private KeyStore keyStore;
|
||||
|
||||
/** Sets the key store to use if a symmetric key name is embedded. */
|
||||
public void setKeyStore(KeyStore keyStore) {
|
||||
this.keyStore = keyStore;
|
||||
}
|
||||
|
||||
/** Sets if a digest password is required. */
|
||||
public void setPasswordDigestRequired(boolean passwordDigestRequired) {
|
||||
this.passwordDigestRequired = passwordDigestRequired;
|
||||
}
|
||||
|
||||
/** Sets the password of the key used for decryption. */
|
||||
public void setKeyPassword(String keyPassword) {
|
||||
this.keyPassword = keyPassword;
|
||||
}
|
||||
|
||||
/** Sets if a plain text password is required. */
|
||||
public void setPasswordPlainTextRequired(boolean passwordPlainTextRequired) {
|
||||
this.passwordPlainTextRequired = passwordPlainTextRequired;
|
||||
}
|
||||
|
||||
/** Returns the password of the key used for decryption. */
|
||||
public String getKeyPassword() {
|
||||
return keyPassword;
|
||||
}
|
||||
|
||||
/** Returns if a digest password is required. */
|
||||
public boolean isPasswordDigestRequired() {
|
||||
return passwordDigestRequired;
|
||||
}
|
||||
|
||||
/** Returns if a plain text password is required. */
|
||||
public boolean isPasswordPlainTextRequired() {
|
||||
return passwordPlainTextRequired;
|
||||
}
|
||||
|
||||
/** Gets the key store to use if a symmetric key name is embedded. */
|
||||
public KeyStore getKeyStore() {
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert
|
||||
.isTrue(!(passwordDigestRequired && passwordPlainTextRequired),
|
||||
"passwordDigestRequired and passwordPlainTextRequired can not be true in the same time");
|
||||
}
|
||||
|
||||
protected final void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
|
||||
if (callback instanceof WSPasswordCallback) {
|
||||
WSPasswordCallback passwordCallback = (WSPasswordCallback) callback;
|
||||
|
||||
int usage = passwordCallback.getUsage();
|
||||
|
||||
if (passwordDigestRequired && !(usage == WSPasswordCallback.USERNAME_TOKEN)) {
|
||||
throw new WSSecurityException("digest password required");
|
||||
}
|
||||
|
||||
if (passwordPlainTextRequired && !(usage == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN)) {
|
||||
throw new WSSecurityException("plain text password required");
|
||||
}
|
||||
|
||||
String id = passwordCallback.getIdentifer();
|
||||
switch (usage) {
|
||||
|
||||
// plain text password
|
||||
case WSPasswordCallback.USERNAME_TOKEN_UNKNOWN:
|
||||
validateUsernameTokenPlainText(passwordCallback);
|
||||
return;
|
||||
|
||||
// digest password
|
||||
case WSPasswordCallback.USERNAME_TOKEN:
|
||||
validateUsernameTokenDigest(passwordCallback);
|
||||
return;
|
||||
|
||||
// decryption
|
||||
case WSPasswordCallback.DECRYPT:
|
||||
passwordCallback.setPassword(getDecryptionKeyPassword(id));
|
||||
return;
|
||||
|
||||
// decryption with an embedded symmetric key name
|
||||
case WSPasswordCallback.KEY_NAME:
|
||||
try {
|
||||
KeyStore.PasswordProtection protection =
|
||||
new KeyStore.PasswordProtection(getSymmetricKeyPassword(id).toCharArray());
|
||||
Entry entry = keyStore.getEntry(id, protection);
|
||||
if (entry instanceof KeyStore.SecretKeyEntry) {
|
||||
KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) entry;
|
||||
SecretKey secretKey = secretKeyEntry.getSecretKey();
|
||||
passwordCallback.setKey(secretKey.getEncoded());
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException("key must be instance of javax.crypto.SecretKey:" + id);
|
||||
}
|
||||
}
|
||||
catch (GeneralSecurityException ex) {
|
||||
throw new Wss4jSecurityCallbackHandlerException(ex
|
||||
.getMessage(), ex);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
throw new UnsupportedOperationException("usage type not suporrted:" + usage);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
protected String getDecryptionKeyPassword(String id) {
|
||||
return keyPassword;
|
||||
}
|
||||
|
||||
protected String getSymmetricKeyPassword(String id) {
|
||||
return keyPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* validates a Username token with a plain text password. The implementation must validate the username and the
|
||||
* password and must throw an exception if the token is not valid
|
||||
*
|
||||
* @param callback the callback created by Wss4j
|
||||
* @throws WSSecurityException if the token is not valid
|
||||
*/
|
||||
abstract protected void validateUsernameTokenPlainText(WSPasswordCallback callback) throws WSSecurityException;
|
||||
|
||||
/**
|
||||
* validates a Username token with a digest password. The implementation must fetch the clear password of the and
|
||||
* set the password attribute of the callback. Wss4j performs the validation logic.
|
||||
*
|
||||
* @param callback the callback created by Wss4j
|
||||
* @throws WSSecurityException if the token is not valid
|
||||
*/
|
||||
abstract protected void validateUsernameTokenDigest(WSPasswordCallback callback) throws WSSecurityException;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2008 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 java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @author Tareq Abed Rabbo
|
||||
* @author Arjen Poutsma
|
||||
* @see org.springframework.ws.soap.security.support.KeyStoreFactoryBean
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class KeyStoreCallbackHandler extends AbstractWsPasswordCallbackHandler implements InitializingBean {
|
||||
|
||||
private String privateKeyPassword;
|
||||
|
||||
private char[] symmetricKeyPassword;
|
||||
|
||||
private KeyStore keyStore;
|
||||
|
||||
/** Sets the key store to use if a symmetric key name is embedded. */
|
||||
public void setKeyStore(KeyStore keyStore) {
|
||||
this.keyStore = keyStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password used to retrieve private keys from the keystore. This property is required for decription based
|
||||
* on private keys, and signing.
|
||||
*/
|
||||
public void setPrivateKeyPassword(String privateKeyPassword) {
|
||||
if (privateKeyPassword != null) {
|
||||
this.privateKeyPassword = privateKeyPassword;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password used to retrieve keys from the symmetric keystore. If this property is not set, it default to
|
||||
* the private key password.
|
||||
*
|
||||
* @see #setPrivateKeyPassword(String)
|
||||
*/
|
||||
public void setSymmetricKeyPassword(String symmetricKeyPassword) {
|
||||
if (symmetricKeyPassword != null) {
|
||||
this.symmetricKeyPassword = symmetricKeyPassword.toCharArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (keyStore == null) {
|
||||
loadDefaultKeyStore();
|
||||
}
|
||||
if (symmetricKeyPassword == null) {
|
||||
symmetricKeyPassword = privateKeyPassword.toCharArray();
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleDecrypt(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
callback.setPassword(privateKeyPassword);
|
||||
}
|
||||
|
||||
protected void handleKeyName(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
try {
|
||||
String identifier = callback.getIdentifer();
|
||||
KeyStore.PasswordProtection protection = new KeyStore.PasswordProtection(symmetricKeyPassword);
|
||||
KeyStore.Entry entry = keyStore.getEntry(identifier, protection);
|
||||
if (entry instanceof KeyStore.SecretKeyEntry) {
|
||||
KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) entry;
|
||||
SecretKey secretKey = secretKeyEntry.getSecretKey();
|
||||
callback.setKey(secretKey.getEncoded());
|
||||
}
|
||||
else {
|
||||
throw new WSSecurityException("Key entry [" + entry + "] is not a javax.crypto.SecretKey");
|
||||
}
|
||||
}
|
||||
catch (GeneralSecurityException ex) {
|
||||
throw new WSSecurityException("Could not obtain symmetric key", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/** Loads the key store indicated by system properties. Delegates to {@link KeyStoreUtils#loadDefaultKeyStore()}. */
|
||||
protected void loadDefaultKeyStore() {
|
||||
try {
|
||||
keyStore = KeyStoreUtils.loadDefaultKeyStore();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loaded default key store");
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn("Could not open default key store", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 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 java.util.Properties;
|
||||
|
||||
import org.apache.ws.security.WSPasswordCallback;
|
||||
import org.apache.ws.security.WSSecurityException;
|
||||
|
||||
/** @author Tareq Abed Rabbo */
|
||||
public class SimpleCallbackHandler extends AbstractWss4jCallbackHandler {
|
||||
|
||||
private Properties users = new Properties();
|
||||
|
||||
public void setUsers(Properties users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
public Properties getUsers() {
|
||||
return users;
|
||||
}
|
||||
|
||||
protected void validateUsernameTokenPlainText(WSPasswordCallback callback) throws WSSecurityException {
|
||||
String storedPassword = users.getProperty(callback.getIdentifer());
|
||||
if (!(storedPassword != null && storedPassword.equals(callback
|
||||
.getPassword()))) {
|
||||
throw new WSSecurityException(WSSecurityException.FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
protected void validateUsernameTokenDigest(WSPasswordCallback callback) throws WSSecurityException {
|
||||
callback.setPassword(users.getProperty((callback.getIdentifer())));
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,25 @@
|
||||
/*
|
||||
* Copyright 2006 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.springframework.ws.soap.security.WsSecurityException;
|
||||
|
||||
public class Wss4jSecurityCallbackHandlerException extends WsSecurityException {
|
||||
|
||||
public Wss4jSecurityCallbackHandlerException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
public Wss4jSecurityCallbackHandlerException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2008 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;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class SimplePasswordCallbackHandler {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2008 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 java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
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.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple callback handler that validates passwords agains a in-memory <code>Properties</code> object. Password
|
||||
* validation is done on a case-sensitive basis.
|
||||
*
|
||||
* @author Tareq Abed Rabbo
|
||||
* @author Arjen Poutsma
|
||||
* @see #setUsers(java.util.Properties)
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class SimplePasswordValidationCallbackHandler extends AbstractWsPasswordCallbackHandler
|
||||
implements InitializingBean {
|
||||
|
||||
private Properties users = new Properties();
|
||||
|
||||
/** Sets the users to validate against. Property names are usernames, property values are passwords. */
|
||||
public void setUsers(Properties users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
public void setUsersMap(Map users) {
|
||||
for (Iterator iterator = users.keySet().iterator(); iterator.hasNext();) {
|
||||
String username = (String) iterator.next();
|
||||
String password = (String) users.get(username);
|
||||
this.users.setProperty(username, password);
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(users, "users is required");
|
||||
}
|
||||
|
||||
protected void handleUsernameToken(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
String identifier = callback.getIdentifer();
|
||||
callback.setPassword(users.getProperty(identifier));
|
||||
}
|
||||
|
||||
protected void handleUsernameTokenUnknown(WSPasswordCallback callback)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
String identifier = callback.getIdentifer();
|
||||
String storedPassword = users.getProperty(identifier);
|
||||
String givenPassword = callback.getPassword();
|
||||
if (storedPassword == null || !storedPassword.equals(givenPassword)) {
|
||||
throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2008 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.acegi;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import org.acegisecurity.providers.dao.UserCache;
|
||||
import org.acegisecurity.providers.dao.cache.NullUserCache;
|
||||
import org.acegisecurity.userdetails.UserDetails;
|
||||
import org.acegisecurity.userdetails.UserDetailsService;
|
||||
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
||||
import org.apache.ws.security.WSPasswordCallback;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.soap.security.wss4j.callback.AbstractWsPasswordCallbackHandler;
|
||||
|
||||
/**
|
||||
* Callback handler that validates a password digest using an Acegi <code>UserDetailsService</code>. Logic based on
|
||||
* Acegi's <code>DigestProcessingFilter</code>.
|
||||
* <p/>
|
||||
* An Acegi <code>UserDetailService</code> is used to load <code>UserDetails</code> 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.acegisecurity.userdetails.UserDetailsService
|
||||
* @see org.acegisecurity.ui.digestauth.DigestProcessingFilter
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AcegiDigestPasswordValidationCallbackHandler extends AbstractWsPasswordCallbackHandler {
|
||||
|
||||
private UserCache userCache = new NullUserCache();
|
||||
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
/** Sets the users cache. Not required, but can benefit performance. */
|
||||
public void setUserCache(UserCache userCache) {
|
||||
this.userCache = userCache;
|
||||
}
|
||||
|
||||
/** Sets the Acegi user details service. Required. */
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(userDetailsService, "userDetailsService is required");
|
||||
}
|
||||
|
||||
protected void handleUsernameToken(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
String identifier = callback.getIdentifer();
|
||||
UserDetails user = loadUserDetails(identifier);
|
||||
if (user != null) {
|
||||
callback.setPassword(user.getPassword());
|
||||
}
|
||||
}
|
||||
|
||||
private UserDetails loadUserDetails(String username) throws DataAccessException {
|
||||
UserDetails user = userCache.getUserFromCache(username);
|
||||
|
||||
if (user == null) {
|
||||
try {
|
||||
user = userDetailsService.loadUserByUsername(username);
|
||||
}
|
||||
catch (UsernameNotFoundException notFound) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Username '" + username + "' not found");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
userCache.putUserInCache(user);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2008 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.acegi;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import org.acegisecurity.Authentication;
|
||||
import org.acegisecurity.AuthenticationException;
|
||||
import org.acegisecurity.AuthenticationManager;
|
||||
import org.acegisecurity.context.SecurityContextHolder;
|
||||
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.apache.ws.security.WSPasswordCallback;
|
||||
import org.apache.ws.security.WSSecurityException;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.soap.security.wss4j.callback.AbstractWsPasswordCallbackHandler;
|
||||
|
||||
/**
|
||||
* Callback handler that validates a certificate uses an Acegi <code>AuthenticationManager</code>. Logic based on
|
||||
* Acegi's <code>BasicProcessingFilter</code>.
|
||||
* <p/>
|
||||
* This handler requires an Acegi <code>AuthenticationManager</code> to operate. It can be set using the
|
||||
* <code>authenticationManager</code> property. An Acegi <code>UsernamePasswordAuthenticationToken</code> is created
|
||||
* with the username as principal and password as credentials.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see org.acegisecurity.providers.UsernamePasswordAuthenticationToken
|
||||
* @see org.acegisecurity.ui.basicauth.BasicProcessingFilter
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class AcegiPlainTextPasswordValidationCallbackHandler extends AbstractWsPasswordCallbackHandler {
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
private boolean ignoreFailure = false;
|
||||
|
||||
/** Sets the Acegi 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");
|
||||
}
|
||||
|
||||
protected void handleUsernameTokenUnknown(WSPasswordCallback callback)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
String identifier = callback.getIdentifer();
|
||||
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.getContext().setAuthentication(null);
|
||||
if (!ignoreFailure) {
|
||||
throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
Contains <code>CallbackHandler</code> implementations for WSS4J that use the <a href="http://www.acegisecurity.org/">Acegi
|
||||
Security System for Spring</a>.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Contains <code>CallbackHandler</code> implementations for WSS4J.
|
||||
</body>
|
||||
</html>
|
||||
@@ -34,7 +34,7 @@ import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessage;
|
||||
import org.springframework.ws.soap.security.AbstractWsSecurityInterceptor;
|
||||
import org.springframework.ws.soap.security.WsSecurityValidationException;
|
||||
import org.springframework.ws.soap.security.xwss.callback.CallbackHandlerChain;
|
||||
import org.springframework.ws.soap.security.xwss.callback.XwssCallbackHandlerChain;
|
||||
|
||||
/**
|
||||
* WS-Security endpoint interceptor that is based on Sun's XML and Web Services Security package (XWSS). This
|
||||
@@ -86,7 +86,7 @@ public class XwsSecurityInterceptor extends AbstractWsSecurityInterceptor implem
|
||||
* @see #setCallbackHandler(javax.security.auth.callback.CallbackHandler)
|
||||
*/
|
||||
public void setCallbackHandlers(CallbackHandler[] callbackHandler) {
|
||||
this.callbackHandler = new CallbackHandlerChain(callbackHandler);
|
||||
this.callbackHandler = new XwssCallbackHandlerChain(callbackHandler);
|
||||
}
|
||||
|
||||
/** Sets the policy configuration to use for XWSS. Required. */
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.ws.soap.security.xwss.callback;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.GeneralSecurityException;
|
||||
@@ -42,11 +41,9 @@ import com.sun.xml.wss.impl.callback.EncryptionKeyCallback;
|
||||
import com.sun.xml.wss.impl.callback.SignatureKeyCallback;
|
||||
import com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback;
|
||||
import org.apache.xml.security.utils.RFC2253Parser;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.ws.soap.security.support.KeyStoreFactoryBean;
|
||||
import org.springframework.ws.soap.security.support.KeyStoreUtils;
|
||||
|
||||
/**
|
||||
* Callback handler that uses Java Security <code>KeyStore</code>s to handle cryptographic callbacks. Allows for
|
||||
@@ -562,43 +559,10 @@ public class KeyStoreCallbackHandler extends CryptographyCallbackHandler impleme
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the key store indicated by system properties. This method tries to load a key store by consulting the
|
||||
* following system properties:<code>javax.net.ssl.keyStore</code>, <code>javax.net.ssl.keyStorePassword</code>, and
|
||||
* <code>javax.net.ssl.keyStoreType</code>.
|
||||
* <p/>
|
||||
* If these properties specify a file with an appropriate password, the factory uses this file for the key store. If
|
||||
* that file does not exist, then a default, empty keystore is created.
|
||||
* <p/>
|
||||
* This behavior corresponds to the standard J2SDK behavior for SSL key stores.
|
||||
*
|
||||
* @see <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html#X509KeyManager">The
|
||||
* standard J2SDK SSL key store mechanism</a>
|
||||
*/
|
||||
/** Loads the key store indicated by system properties. Delegates to {@link KeyStoreUtils#loadDefaultKeyStore()}. */
|
||||
protected void loadDefaultKeyStore() {
|
||||
Resource location = null;
|
||||
String type = null;
|
||||
String password = null;
|
||||
String locationProperty = System.getProperty("javax.net.ssl.keyStore");
|
||||
if (StringUtils.hasLength(locationProperty)) {
|
||||
File f = new File(locationProperty);
|
||||
if (f.exists() && f.isFile() && f.canRead()) {
|
||||
location = new FileSystemResource(f);
|
||||
}
|
||||
String passwordProperty = System.getProperty("javax.net.ssl.keyStorePassword");
|
||||
if (StringUtils.hasLength(passwordProperty)) {
|
||||
password = passwordProperty;
|
||||
}
|
||||
type = System.getProperty("javax.net.ssl.trustStore");
|
||||
}
|
||||
// use the factory bean here, easier to setup
|
||||
KeyStoreFactoryBean factoryBean = new KeyStoreFactoryBean();
|
||||
factoryBean.setLocation(location);
|
||||
factoryBean.setPassword(password);
|
||||
factoryBean.setType(type);
|
||||
try {
|
||||
factoryBean.afterPropertiesSet();
|
||||
keyStore = (KeyStore) factoryBean.getObject();
|
||||
keyStore = KeyStoreUtils.loadDefaultKeyStore();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loaded default key store");
|
||||
}
|
||||
@@ -608,54 +572,10 @@ public class KeyStoreCallbackHandler extends CryptographyCallbackHandler impleme
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a default trust store. This method uses the following algorithm: <ol> <li> If the system property
|
||||
* <code>javax.net.ssl.trustStore</code> is defined, its value is loaded. If the
|
||||
* <code>javax.net.ssl.trustStorePassword</code> system property is also defined, its value is used as a password.
|
||||
* If the <code>javax.net.ssl.trustStoreType</code> system property is defined, its value is used as a key store
|
||||
* type.
|
||||
* <p/>
|
||||
* If <code>javax.net.ssl.trustStore</code> is defined but the specified file does not exist, then a default, empty
|
||||
* trust store is created. </li> <li> If the <code>javax.net.ssl.trustStore</code> system property was not
|
||||
* specified, but if the file <code>$JAVA_HOME/lib/security/jssecacerts</code> exists, that file is used. </li>
|
||||
* Otherwise, <li>If the file <code>$JAVA_HOME/lib/security/cacerts</code> exists, that file is used. </ol>
|
||||
* <p/>
|
||||
* This behavior corresponds to the standard J2SDK behavior for SSL trust stores.
|
||||
*
|
||||
* @see <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager">The
|
||||
* standard J2SDK SSL trust store mechanism</a>
|
||||
*/
|
||||
/** Loads a default trust store. Delegates to {@link KeyStoreUtils#loadDefaultTrustStore()}. */
|
||||
protected void loadDefaultTrustStore() {
|
||||
Resource location = null;
|
||||
String type = null;
|
||||
String password = null;
|
||||
String locationProperty = System.getProperty("javax.net.ssl.trustStore");
|
||||
if (StringUtils.hasLength(locationProperty)) {
|
||||
File f = new File(locationProperty);
|
||||
if (f.exists() && f.isFile() && f.canRead()) {
|
||||
location = new FileSystemResource(f);
|
||||
}
|
||||
String passwordProperty = System.getProperty("javax.net.ssl.trustStorePassword");
|
||||
if (StringUtils.hasLength(passwordProperty)) {
|
||||
password = passwordProperty;
|
||||
}
|
||||
type = System.getProperty("javax.net.ssl.trustStoreType");
|
||||
}
|
||||
else {
|
||||
String javaHome = System.getProperty("java.home");
|
||||
location = new FileSystemResource(javaHome + "/lib/security/jssecacerts");
|
||||
if (!location.exists()) {
|
||||
location = new FileSystemResource(javaHome + "/lib/security/cacerts");
|
||||
}
|
||||
}
|
||||
// use the factory bean here, easier to setup
|
||||
KeyStoreFactoryBean factoryBean = new KeyStoreFactoryBean();
|
||||
factoryBean.setLocation(location);
|
||||
factoryBean.setPassword(password);
|
||||
factoryBean.setType(type);
|
||||
try {
|
||||
factoryBean.afterPropertiesSet();
|
||||
trustStore = (KeyStore) factoryBean.getObject();
|
||||
trustStore = KeyStoreUtils.loadDefaultTrustStore();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loaded default trust store");
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
|
||||
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
|
||||
import com.sun.xml.wss.impl.callback.TimestampValidationCallback;
|
||||
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
import org.springframework.ws.soap.security.callback.CallbackHandlerChain;
|
||||
|
||||
/**
|
||||
* Represents a chain of <code>CallbackHandler</code>s. For each callback, each of the handlers is called in term. If a
|
||||
@@ -35,16 +35,10 @@ import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class CallbackHandlerChain extends AbstractCallbackHandler {
|
||||
public class XwssCallbackHandlerChain extends CallbackHandlerChain {
|
||||
|
||||
private CallbackHandler[] callbackHandlers;
|
||||
|
||||
public CallbackHandlerChain(CallbackHandler[] callbackHandlers) {
|
||||
this.callbackHandlers = callbackHandlers;
|
||||
}
|
||||
|
||||
public void setCallbackHandlers(CallbackHandler[] callbackHandlers) {
|
||||
this.callbackHandlers = callbackHandlers;
|
||||
public XwssCallbackHandlerChain(CallbackHandler[] callbackHandlers) {
|
||||
super(callbackHandlers);
|
||||
}
|
||||
|
||||
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
@@ -58,20 +52,7 @@ public class CallbackHandlerChain extends AbstractCallbackHandler {
|
||||
handleTimestampValidationCallback((TimestampValidationCallback) callback);
|
||||
}
|
||||
else {
|
||||
boolean allUnsupported = true;
|
||||
for (int i = 0; i < callbackHandlers.length; i++) {
|
||||
CallbackHandler callbackHandler = callbackHandlers[i];
|
||||
try {
|
||||
callbackHandler.handle(new Callback[]{callback});
|
||||
allUnsupported = false;
|
||||
}
|
||||
catch (UnsupportedCallbackException ex) {
|
||||
// if an UnsupportedCallbackException occurs, go to the next handler
|
||||
}
|
||||
}
|
||||
if (allUnsupported) {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
super.handleInternal(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,8 +78,8 @@ public class CallbackHandlerChain extends AbstractCallbackHandler {
|
||||
|
||||
public void validate(TimestampValidationCallback.Request request)
|
||||
throws TimestampValidationCallback.TimestampValidationException {
|
||||
for (int i = 0; i < callbackHandlers.length; i++) {
|
||||
CallbackHandler callbackHandler = callbackHandlers[i];
|
||||
for (int i = 0; i < getCallbackHandlers().length; i++) {
|
||||
CallbackHandler callbackHandler = getCallbackHandlers()[i];
|
||||
try {
|
||||
callbackHandler.handle(new Callback[]{callback});
|
||||
callback.getResult();
|
||||
@@ -124,8 +105,8 @@ public class CallbackHandlerChain extends AbstractCallbackHandler {
|
||||
public boolean validate(PasswordValidationCallback.Request request)
|
||||
throws PasswordValidationCallback.PasswordValidationException {
|
||||
boolean allUnsupported = true;
|
||||
for (int i = 0; i < callbackHandlers.length; i++) {
|
||||
CallbackHandler callbackHandler = callbackHandlers[i];
|
||||
for (int i = 0; i < getCallbackHandlers().length; i++) {
|
||||
CallbackHandler callbackHandler = getCallbackHandlers()[i];
|
||||
try {
|
||||
callbackHandler.handle(new Callback[]{callback});
|
||||
allUnsupported = false;
|
||||
@@ -155,8 +136,8 @@ public class CallbackHandlerChain extends AbstractCallbackHandler {
|
||||
public boolean validate(X509Certificate certificate)
|
||||
throws CertificateValidationCallback.CertificateValidationException {
|
||||
boolean allUnsupported = true;
|
||||
for (int i = 0; i < callbackHandlers.length; i++) {
|
||||
CallbackHandler callbackHandler = callbackHandlers[i];
|
||||
for (int i = 0; i < getCallbackHandlers().length; i++) {
|
||||
CallbackHandler callbackHandler = getCallbackHandlers()[i];
|
||||
try {
|
||||
callbackHandler.handle(new Callback[]{callback});
|
||||
allUnsupported = false;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ws.soap.security.xwss.callback;
|
||||
package org.springframework.ws.soap.security.callback;
|
||||
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
@@ -46,7 +46,7 @@ public class CallbackHandlerChainTest extends TestCase {
|
||||
chain.handle(new Callback[]{callback});
|
||||
}
|
||||
|
||||
public void testUnsupportedNormal() throws Exception {
|
||||
public void testUnsupportedSupported() throws Exception {
|
||||
CallbackHandlerChain chain = new CallbackHandlerChain(new CallbackHandler[]{unsupported, supported});
|
||||
chain.handle(new Callback[]{callback});
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.springframework.ws.soap.security.wss4j;
|
||||
|
||||
public class AxiomWss4jMessageInterceptorAcegiCallbackHandlerTest
|
||||
extends Wss4jMessageInterceptorAcegiCallbackHandlerTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.springframework.ws.soap.security.wss4j;
|
||||
|
||||
public class SaajWss4jMessageInterceptorAcegiCallbackHandlerTest
|
||||
extends Wss4jMessageInterceptorAcegiCallbackHandlerTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package org.springframework.ws.soap.security.wss4j;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.acegisecurity.Authentication;
|
||||
import org.acegisecurity.AuthenticationManager;
|
||||
import org.acegisecurity.GrantedAuthority;
|
||||
import org.acegisecurity.context.SecurityContextHolder;
|
||||
import org.acegisecurity.providers.TestingAuthenticationToken;
|
||||
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.acegisecurity.userdetails.memory.InMemoryDaoImpl;
|
||||
import org.apache.ws.security.WSConstants;
|
||||
import org.easymock.MockControl;
|
||||
|
||||
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.acegi.AcegiDigestPasswordValidationCallbackHandler;
|
||||
import org.springframework.ws.soap.security.wss4j.callback.acegi.AcegiPlainTextPasswordValidationCallbackHandler;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorAcegiCallbackHandlerTestCase extends Wss4jTestCase {
|
||||
|
||||
private Properties users = new Properties();
|
||||
|
||||
private MockControl control;
|
||||
|
||||
private AuthenticationManager mock;
|
||||
|
||||
protected void onSetup() throws Exception {
|
||||
control = MockControl.createControl(AuthenticationManager.class);
|
||||
mock = (AuthenticationManager) control.getMock();
|
||||
users.setProperty("Bert", "Ernie,ROLE_TEST");
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
control.verify();
|
||||
}
|
||||
|
||||
public void testValidateUsernameTokenPlainText() throws Exception {
|
||||
EndpointInterceptor interceptor = prepareInterceptor("UsernameToken", true, false);
|
||||
SoapMessage message = loadMessage("usernameTokenPlainText-soap.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getMessageFactory());
|
||||
interceptor.handleRequest(messageContext, null);
|
||||
assertValidateUsernameToken(message);
|
||||
}
|
||||
|
||||
public void testValidateUsernameTokenDigest() throws Exception {
|
||||
EndpointInterceptor interceptor = prepareInterceptor("UsernameToken", true, true);
|
||||
SoapMessage message = loadMessage("usernameTokenDigest-soap.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getMessageFactory());
|
||||
interceptor.handleRequest(messageContext, null);
|
||||
assertValidateUsernameToken(message);
|
||||
}
|
||||
|
||||
protected void assertValidateUsernameToken(SoapMessage message) throws Exception {
|
||||
Object result = getMessage(message);
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security",
|
||||
getDocument(message));
|
||||
Authentication authentication = SecurityContextHolder.getContext()
|
||||
.getAuthentication();
|
||||
assertNotNull("authentication must not be null", authentication);
|
||||
}
|
||||
|
||||
protected EndpointInterceptor prepareInterceptor(String actions, boolean validating, boolean digest)
|
||||
throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
|
||||
if (validating) {
|
||||
interceptor.setValidationActions(actions);
|
||||
}
|
||||
else {
|
||||
interceptor.setSecurementActions(actions);
|
||||
}
|
||||
if (digest) {
|
||||
AcegiDigestPasswordValidationCallbackHandler callbackHandler =
|
||||
new AcegiDigestPasswordValidationCallbackHandler();
|
||||
InMemoryDaoImpl userDetailsService = new InMemoryDaoImpl();
|
||||
userDetailsService.setUserProperties(users);
|
||||
userDetailsService.afterPropertiesSet();
|
||||
callbackHandler.setUserDetailsService(userDetailsService);
|
||||
interceptor.setSecurementPasswordType(WSConstants.PW_DIGEST);
|
||||
interceptor.setValidationCallbackHandler(callbackHandler);
|
||||
interceptor.afterPropertiesSet();
|
||||
}
|
||||
else {
|
||||
AcegiPlainTextPasswordValidationCallbackHandler callbackHandler =
|
||||
new AcegiPlainTextPasswordValidationCallbackHandler();
|
||||
Authentication authResult = new TestingAuthenticationToken("Bert", "Ernie", new GrantedAuthority[0]);
|
||||
control.expectAndReturn(mock.authenticate(new UsernamePasswordAuthenticationToken("Bert", "Ernie")),
|
||||
authResult);
|
||||
callbackHandler.setAuthenticationManager(mock);
|
||||
callbackHandler.afterPropertiesSet();
|
||||
interceptor.setSecurementPasswordType(WSConstants.PW_TEXT);
|
||||
interceptor.setValidationCallbackHandler(callbackHandler);
|
||||
interceptor.afterPropertiesSet();
|
||||
}
|
||||
control.replay();
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.w3c.dom.Document;
|
||||
import org.springframework.ws.context.DefaultMessageContext;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.security.wss4j.callback.SimpleCallbackHandler;
|
||||
import org.springframework.ws.soap.security.wss4j.callback.KeyStoreCallbackHandler;
|
||||
import org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorEncryptionTestCase extends Wss4jTestCase {
|
||||
@@ -20,8 +20,8 @@ public abstract class Wss4jMessageInterceptorEncryptionTestCase extends Wss4jTes
|
||||
interceptor.setValidationActions("Encrypt");
|
||||
interceptor.setSecurementActions("Encrypt");
|
||||
|
||||
SimpleCallbackHandler callbackHandler = new SimpleCallbackHandler();
|
||||
callbackHandler.setKeyPassword("123456");
|
||||
KeyStoreCallbackHandler callbackHandler = new KeyStoreCallbackHandler();
|
||||
callbackHandler.setPrivateKeyPassword("123456");
|
||||
interceptor.setValidationCallbackHandler(callbackHandler);
|
||||
|
||||
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
|
||||
@@ -63,6 +63,5 @@ public abstract class Wss4jMessageInterceptorEncryptionTestCase extends Wss4jTes
|
||||
Document document = getDocument(message);
|
||||
assertXpathExists("Encryption error", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/xenc:EncryptedKey",
|
||||
document);
|
||||
//TODO see why the clear message appears in the unit test
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.springframework.ws.context.DefaultMessageContext;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapHeaderElement;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.security.wss4j.callback.SimpleCallbackHandler;
|
||||
import org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorHeaderTestCase extends Wss4jTestCase {
|
||||
|
||||
@@ -21,7 +21,7 @@ public abstract class Wss4jMessageInterceptorHeaderTestCase extends Wss4jTestCas
|
||||
interceptor.setValidateRequest(true);
|
||||
interceptor.setSecureResponse(true);
|
||||
interceptor.setValidationActions("UsernameToken");
|
||||
SimpleCallbackHandler callbackHandler = new SimpleCallbackHandler();
|
||||
SimplePasswordValidationCallbackHandler callbackHandler = new SimplePasswordValidationCallbackHandler();
|
||||
callbackHandler.setUsers(users);
|
||||
interceptor.setValidationCallbackHandler(callbackHandler);
|
||||
interceptor.afterPropertiesSet();
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.springframework.ws.WebServiceMessage;
|
||||
import org.springframework.ws.context.DefaultMessageContext;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.security.wss4j.callback.SimpleCallbackHandler;
|
||||
import org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorSignTestCase extends Wss4jTestCase {
|
||||
@@ -19,8 +18,6 @@ public abstract class Wss4jMessageInterceptorSignTestCase extends Wss4jTestCase
|
||||
protected void onSetup() throws Exception {
|
||||
interceptor = new Wss4jSecurityInterceptor();
|
||||
interceptor.setValidationActions("Signature");
|
||||
SimpleCallbackHandler callbackHandler = new SimpleCallbackHandler();
|
||||
interceptor.setValidationCallbackHandler(callbackHandler);
|
||||
|
||||
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
|
||||
Properties cryptoFactoryBeanConfig = new Properties();
|
||||
@@ -61,7 +58,6 @@ public abstract class Wss4jMessageInterceptorSignTestCase extends Wss4jTestCase
|
||||
interceptor.secureMessage(message, messageContext);
|
||||
assertNotNull("No result returned", response);
|
||||
Document document = getDocument((SoapMessage) response);
|
||||
message.writeTo(System.out);
|
||||
assertXpathExists("Absent SignatureConfirmation element",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse11:SignatureConfirmation", document);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.w3c.dom.Document;
|
||||
import org.springframework.ws.context.DefaultMessageContext;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.security.wss4j.callback.SimpleCallbackHandler;
|
||||
import org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorUsernameTokenTestCase extends Wss4jTestCase {
|
||||
|
||||
@@ -96,16 +96,16 @@ public abstract class Wss4jMessageInterceptorUsernameTokenTestCase extends Wss4j
|
||||
else {
|
||||
interceptor.setSecurementActions(actions);
|
||||
}
|
||||
SimpleCallbackHandler callbackHandler = new SimpleCallbackHandler();
|
||||
SimplePasswordValidationCallbackHandler callbackHandler = new SimplePasswordValidationCallbackHandler();
|
||||
callbackHandler.setUsers(users);
|
||||
if (digest) {
|
||||
callbackHandler.setPasswordDigestRequired(true);
|
||||
callbackHandler.setPasswordPlainTextRequired(false);
|
||||
// callbackHandler.setPasswordDigestRequired(true);
|
||||
// callbackHandler.setPasswordPlainTextRequired(false);
|
||||
interceptor.setSecurementPasswordType(WSConstants.PW_DIGEST);
|
||||
}
|
||||
else {
|
||||
callbackHandler.setPasswordDigestRequired(false);
|
||||
callbackHandler.setPasswordPlainTextRequired(true);
|
||||
// callbackHandler.setPasswordDigestRequired(false);
|
||||
// callbackHandler.setPasswordPlainTextRequired(true);
|
||||
interceptor.setSecurementPasswordType(WSConstants.PW_TEXT);
|
||||
}
|
||||
interceptor.setValidationCallbackHandler(callbackHandler);
|
||||
|
||||
Reference in New Issue
Block a user