Migrated to Gradle build
This commit migrates from a Maven-based build system to a Gradle-based one. Changes include: - Removed archetype & parent - Renamed core, support, test, security and xml directories to spring-ws-core, spring-ws-test, spring-ws-security, spring-xml respectively. - Moved samples to separate project (https://github.com/spring-projects/spring-ws-samples)
This commit is contained in:
committed by
Arjen Poutsma
parent
a8c1d2ad97
commit
843ca6d2ef
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* Copyright 2005-2011 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;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.client.WebServiceClientException;
|
||||
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.server.EndpointExceptionResolver;
|
||||
import org.springframework.ws.soap.SoapBody;
|
||||
import org.springframework.ws.soap.SoapFault;
|
||||
import org.springframework.ws.soap.SoapHeader;
|
||||
import org.springframework.ws.soap.SoapHeaderElement;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.server.SoapEndpointInterceptor;
|
||||
import org.springframework.ws.soap.soap11.Soap11Body;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Interceptor base class for interceptors that handle WS-Security. Can be used on the server side, registered in a
|
||||
* {@link org.springframework.ws.server.endpoint.mapping.AbstractEndpointMapping#setInterceptors(org.springframework.ws.server.EndpointInterceptor[])
|
||||
* endpoint mapping}; or on the client side, on the {@link org.springframework.ws.client.core.WebServiceTemplate#setInterceptors(ClientInterceptor[])
|
||||
* web service template}.
|
||||
* <p/>
|
||||
* Subclasses of this base class can be configured to secure incoming and secure outgoing messages. By default, both are
|
||||
* on.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInterceptor, ClientInterceptor {
|
||||
|
||||
/** Logger available to subclasses. */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected static final QName WS_SECURITY_NAME =
|
||||
new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security");
|
||||
|
||||
private boolean secureResponse = true;
|
||||
|
||||
private boolean validateRequest = true;
|
||||
|
||||
private boolean secureRequest = true;
|
||||
|
||||
private boolean validateResponse = true;
|
||||
|
||||
private boolean skipValidationIfNoHeaderPresent = false;
|
||||
|
||||
private EndpointExceptionResolver exceptionResolver;
|
||||
|
||||
/** Indicates whether server-side incoming request are to be validated. Defaults to <code>true</code>. */
|
||||
public void setValidateRequest(boolean validateRequest) {
|
||||
this.validateRequest = validateRequest;
|
||||
}
|
||||
|
||||
/** Indicates whether server-side outgoing responses are to be secured. Defaults to <code>true</code>. */
|
||||
public void setSecureResponse(boolean secureResponse) {
|
||||
this.secureResponse = secureResponse;
|
||||
}
|
||||
|
||||
/** Indicates whether client-side outgoing requests are to be secured. Defaults to <code>true</code>. */
|
||||
public void setSecureRequest(boolean secureRequest) {
|
||||
this.secureRequest = secureRequest;
|
||||
}
|
||||
|
||||
/** Indicates whether client-side incoming responses are to be validated. Defaults to <code>true</code>. */
|
||||
public void setValidateResponse(boolean validateResponse) {
|
||||
this.validateResponse = validateResponse;
|
||||
}
|
||||
|
||||
/** Provide an {@link EndpointExceptionResolver} for resolving validation exceptions. */
|
||||
public void setExceptionResolver(EndpointExceptionResolver exceptionResolver) {
|
||||
this.exceptionResolver = exceptionResolver;
|
||||
}
|
||||
|
||||
/** Allows skipping validation if no security header is present. */
|
||||
public void setSkipValidationIfNoHeaderPresent(
|
||||
boolean skipValidationIfNoHeaderPresent) {
|
||||
this.skipValidationIfNoHeaderPresent = skipValidationIfNoHeaderPresent;
|
||||
}
|
||||
|
||||
/*
|
||||
* Server-side
|
||||
*/
|
||||
|
||||
/**
|
||||
* Validates a server-side incoming request. Delegates to {@link #validateMessage(org.springframework.ws.soap.SoapMessage,org.springframework.ws.context.MessageContext)}
|
||||
* if the {@link #setValidateRequest(boolean) validateRequest} property is <code>true</code>.
|
||||
*
|
||||
* @param messageContext the message context, containing the request to be validated
|
||||
* @param endpoint chosen endpoint to invoke
|
||||
* @return <code>true</code> if the request was valid; <code>false</code> otherwise.
|
||||
* @throws Exception in case of errors
|
||||
* @see #validateMessage(org.springframework.ws.soap.SoapMessage,org.springframework.ws.context.MessageContext)
|
||||
*/
|
||||
public final boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
|
||||
if (validateRequest) {
|
||||
Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
|
||||
if(skipValidationIfNoHeaderPresent && !isSecurityHeaderPresent((SoapMessage) messageContext.getRequest())){
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
validateMessage((SoapMessage) messageContext.getRequest(), messageContext);
|
||||
return true;
|
||||
}
|
||||
catch (WsSecurityValidationException ex) {
|
||||
return handleValidationException(ex, messageContext);
|
||||
}
|
||||
catch (WsSecurityFaultException ex) {
|
||||
return handleFaultException(ex, messageContext);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Secures a server-side outgoing response. Delegates to {@link #secureMessage(org.springframework.ws.soap.SoapMessage,org.springframework.ws.context.MessageContext)}
|
||||
* if the {@link #setSecureResponse(boolean) secureResponse} property is <code>true</code>.
|
||||
*
|
||||
* @param messageContext the message context, containing the response to be secured
|
||||
* @param endpoint chosen endpoint to invoke
|
||||
* @return <code>true</code> if the response was secured; <code>false</code> otherwise.
|
||||
* @throws Exception in case of errors
|
||||
* @see #secureMessage(org.springframework.ws.soap.SoapMessage,org.springframework.ws.context.MessageContext)
|
||||
*/
|
||||
public final boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
|
||||
boolean result = true;
|
||||
try {
|
||||
if (secureResponse) {
|
||||
Assert.isTrue(messageContext.hasResponse(), "MessageContext contains no response");
|
||||
Assert.isInstanceOf(SoapMessage.class, messageContext.getResponse());
|
||||
try {
|
||||
secureMessage((SoapMessage) messageContext.getResponse(), messageContext);
|
||||
}
|
||||
catch (WsSecuritySecurementException ex) {
|
||||
result = handleSecurementException(ex, messageContext);
|
||||
}
|
||||
catch (WsSecurityFaultException ex) {
|
||||
result = handleFaultException(ex, messageContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (!result) {
|
||||
messageContext.clearResponse();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns <code>true</code>, i.e. fault responses are not secured. */
|
||||
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) {
|
||||
cleanUp();
|
||||
}
|
||||
|
||||
public boolean understands(SoapHeaderElement headerElement) {
|
||||
return WS_SECURITY_NAME.equals(headerElement.getName());
|
||||
}
|
||||
|
||||
/*
|
||||
* Client-side
|
||||
*/
|
||||
|
||||
/**
|
||||
* Secures a client-side outgoing request. Delegates to {@link #secureMessage(org.springframework.ws.soap.SoapMessage,org.springframework.ws.context.MessageContext)}
|
||||
* if the {@link #setSecureRequest(boolean) secureRequest} property is <code>true</code>.
|
||||
*
|
||||
* @param messageContext the message context, containing the request to be secured
|
||||
* @return <code>true</code> if the response was secured; <code>false</code> otherwise.
|
||||
* @throws Exception in case of errors
|
||||
* @see #secureMessage(org.springframework.ws.soap.SoapMessage,org.springframework.ws.context.MessageContext)
|
||||
*/
|
||||
public final boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
|
||||
if (secureRequest) {
|
||||
Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
|
||||
try {
|
||||
secureMessage((SoapMessage) messageContext.getRequest(), messageContext);
|
||||
return true;
|
||||
}
|
||||
catch (WsSecuritySecurementException ex) {
|
||||
return handleSecurementException(ex, messageContext);
|
||||
}
|
||||
catch (WsSecurityFaultException ex) {
|
||||
return handleFaultException(ex, messageContext);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a client-side incoming response. Delegates to {@link #validateMessage(org.springframework.ws.soap.SoapMessage,org.springframework.ws.context.MessageContext)}
|
||||
* if the {@link #setValidateResponse(boolean) validateResponse} property is <code>true</code>.
|
||||
*
|
||||
* @param messageContext the message context, containing the response to be validated
|
||||
* @return <code>true</code> if the request was valid; <code>false</code> otherwise.
|
||||
* @throws Exception in case of errors
|
||||
* @see #validateMessage(org.springframework.ws.soap.SoapMessage,org.springframework.ws.context.MessageContext)
|
||||
*/
|
||||
public final boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
|
||||
if (validateResponse) {
|
||||
Assert.isTrue(messageContext.hasResponse(), "MessageContext contains no response");
|
||||
Assert.isInstanceOf(SoapMessage.class, messageContext.getResponse());
|
||||
if(skipValidationIfNoHeaderPresent && !isSecurityHeaderPresent((SoapMessage) messageContext.getRequest())){
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
validateMessage((SoapMessage) messageContext.getResponse(), messageContext);
|
||||
return true;
|
||||
}
|
||||
catch (WsSecurityValidationException ex) {
|
||||
return handleValidationException(ex, messageContext);
|
||||
}
|
||||
catch (WsSecurityFaultException ex) {
|
||||
return handleFaultException(ex, messageContext);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns <code>true</code>, i.e. fault responses are not validated. */
|
||||
public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an securement exception. Default implementation logs the given exception, and returns
|
||||
* <code>false</code>.
|
||||
*
|
||||
* @param ex the validation exception
|
||||
* @param messageContext the message context
|
||||
* @return <code>true</code> to continue processing the message, <code>false</code> (the default) otherwise
|
||||
*/
|
||||
protected boolean handleSecurementException(WsSecuritySecurementException ex, MessageContext messageContext) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Could not secure response: " + ex.getMessage(), ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an invalid SOAP message. Default implementation logs the given exception, delegates to the set {@link
|
||||
* #setExceptionResolver(EndpointExceptionResolver) exceptionResolver} if any, or creates a SOAP 1.1 Client or SOAP
|
||||
* 1.2 Sender Fault with the exception message as fault string, and returns <code>false</code>.
|
||||
*
|
||||
* @param ex the validation exception
|
||||
* @param messageContext the message context
|
||||
* @return <code>true</code> to continue processing the message, <code>false</code> (the default) otherwise
|
||||
*/
|
||||
protected boolean handleValidationException(WsSecurityValidationException ex, MessageContext messageContext) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Could not validate request: " + ex.getMessage());
|
||||
}
|
||||
if (exceptionResolver != null) {
|
||||
exceptionResolver.resolveException(messageContext, null, ex);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No exception resolver present, creating basic soap fault");
|
||||
}
|
||||
SoapBody response = ((SoapMessage) messageContext.getResponse()).getSoapBody();
|
||||
response.addClientOrSenderFault(ex.getMessage(), Locale.ENGLISH);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a fault exception.Default implementation logs the given exception, and creates a SOAP Fault with the
|
||||
* properties of the given exception, and returns <code>false</code>.
|
||||
*
|
||||
* @param ex the validation exception
|
||||
* @param messageContext the message context
|
||||
* @return <code>true</code> to continue processing the message, <code>false</code> (the default) otherwise
|
||||
*/
|
||||
protected boolean handleFaultException(WsSecurityFaultException ex, MessageContext messageContext) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Could not handle request: " + ex.getMessage());
|
||||
}
|
||||
SoapBody response = ((SoapMessage) messageContext.getResponse()).getSoapBody();
|
||||
SoapFault fault;
|
||||
if (response instanceof Soap11Body) {
|
||||
fault = ((Soap11Body) response).addFault(ex.getFaultCode(), ex.getFaultString(), Locale.ENGLISH);
|
||||
}
|
||||
else {
|
||||
fault = response.addClientOrSenderFault(ex.getFaultString(), Locale.ENGLISH);
|
||||
}
|
||||
fault.setFaultActorOrRole(ex.getFaultActor());
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract template method. Subclasses are required to validate the request contained in the given {@link
|
||||
* SoapMessage}, and replace the original request with the validated version.
|
||||
*
|
||||
* @param soapMessage the soap message to validate
|
||||
* @throws WsSecurityValidationException in case of validation errors
|
||||
*/
|
||||
protected abstract void validateMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws WsSecurityValidationException;
|
||||
|
||||
/**
|
||||
* Abstract template method. Subclasses are required to secure the response contained in the given {@link
|
||||
* SoapMessage}, and replace the original response with the secured version.
|
||||
*
|
||||
* @param soapMessage the soap message to secure
|
||||
* @throws WsSecuritySecurementException in case of securement errors
|
||||
*/
|
||||
protected abstract void secureMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws WsSecuritySecurementException;
|
||||
|
||||
protected abstract void cleanUp();
|
||||
|
||||
/**
|
||||
* Iterates over header elements and returns true if WS-Security header is found.
|
||||
*/
|
||||
private boolean isSecurityHeaderPresent(SoapMessage message) {
|
||||
SoapHeader soapHeader = message.getSoapHeader();
|
||||
if(soapHeader == null){
|
||||
return false;
|
||||
}
|
||||
Iterator<SoapHeaderElement> elements = soapHeader.examineAllHeaderElements();
|
||||
while(elements.hasNext()){
|
||||
SoapHeaderElement e = elements.next();
|
||||
if(e.getName().equals(WS_SECURITY_NAME)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.springframework.ws.WebServiceException;
|
||||
|
||||
/**
|
||||
* Exception indicating that something went wrong during WS-Security executions. Has specific subclasses for securement
|
||||
* and validation.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class WsSecurityException extends WebServiceException {
|
||||
|
||||
public WsSecurityException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public WsSecurityException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2007 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;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
/**
|
||||
* Exception indicating that a WS-Security executions should result in a SOAP Fault.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public abstract class WsSecurityFaultException extends WsSecurityException {
|
||||
|
||||
private QName faultCode;
|
||||
|
||||
private String faultString;
|
||||
|
||||
private String faultActor;
|
||||
|
||||
/** Construct a new <code>WsSecurityFaultException</code> with the given fault code, string, and actor. */
|
||||
public WsSecurityFaultException(QName faultCode, String faultString, String faultActor) {
|
||||
super(faultString);
|
||||
this.faultCode = faultCode;
|
||||
this.faultString = faultString;
|
||||
this.faultActor = faultActor;
|
||||
}
|
||||
|
||||
/** Returns the fault code for the exception. */
|
||||
public QName getFaultCode() {
|
||||
return faultCode;
|
||||
}
|
||||
|
||||
/** Returns the fault string for the exception. */
|
||||
public String getFaultString() {
|
||||
return faultString;
|
||||
}
|
||||
|
||||
/** Returns the fault actor for the exception. */
|
||||
public String getFaultActor() {
|
||||
return faultActor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Exception indicating that something went wrong during the securement of a message.
|
||||
* <p/>
|
||||
* This is a checked exception since we want it to be caught, logged and handled rather than cause the application to
|
||||
* fail. Failure to secure a message is usually not a fatal problem.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class WsSecuritySecurementException extends WsSecurityException {
|
||||
|
||||
public WsSecuritySecurementException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public WsSecuritySecurementException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Exception indicating that something went wrong during the validation of a message.
|
||||
* <p/>
|
||||
* This is a checked exception since we want it to be caught, logged and handled rather than cause the application to
|
||||
* fail. Failure to validate a message is usually not a fatal problem.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class WsSecurityValidationException extends WsSecurityException {
|
||||
|
||||
public WsSecurityValidationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public WsSecurityValidationException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Abstract implementation of a <code>CallbackHandler</code>.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class AbstractCallbackHandler implements CallbackHandler {
|
||||
|
||||
/** Logger available to subclasses. */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected AbstractCallbackHandler() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the given callbacks, and calls <code>handleInternal</code> for each of them.
|
||||
*
|
||||
* @param callbacks the callbacks
|
||||
* @see #handleInternal(javax.security.auth.callback.Callback)
|
||||
*/
|
||||
public final void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
|
||||
for (Callback callback : callbacks) {
|
||||
handleInternal(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/** Template method that should be implemented by subclasses. */
|
||||
protected abstract void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.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;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
boolean allUnsupported = true;
|
||||
for (CallbackHandler callbackHandler : callbackHandlers) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.Serializable;
|
||||
import javax.security.auth.callback.Callback;
|
||||
|
||||
/**
|
||||
* Underlying security services instantiate and pass a <code>CleanupCallback</code> to the <code>handle</code> method of
|
||||
* a <code>CallbackHandler</code> to clean up security state.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.4
|
||||
*/
|
||||
public class CleanupCallback implements Callback, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 4744181820980888237L;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Contains generic <code>CallbackHandler</code> implementations.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides WS-Security implementation classes. Contains the <code>AbstractWsSecurityInterceptor</code> and exceptions.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.security.KeyStore;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Spring factory bean for an array of {@link KeyManager}s.
|
||||
* <p/>
|
||||
* Uses the {@link KeyManagerFactory} to create the {@code KeyManager}s.
|
||||
*
|
||||
* @author Stephen More
|
||||
* @author Arjen Poutsma
|
||||
* @see KeyManager
|
||||
* @see KeyManagerFactory
|
||||
* @since 2.1.2
|
||||
*/
|
||||
public class KeyManagersFactoryBean implements FactoryBean<KeyManager[]>, InitializingBean {
|
||||
|
||||
private KeyManagerFactory keyManagerFactory;
|
||||
|
||||
private KeyStore keyStore;
|
||||
|
||||
private String algorithm;
|
||||
|
||||
private String provider;
|
||||
|
||||
private char[] password;
|
||||
|
||||
/**
|
||||
* Sets the password to use for integrity checking. If this property is not set, then integrity checking is not
|
||||
* performed.
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
if (password != null) {
|
||||
this.password = password.toCharArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the provider of the key store to use. If this is not set, the default is used.
|
||||
*/
|
||||
public void setProvider(String provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the algorithm of the <code>KeyManager</code> to use. If this is not set, the default is used.
|
||||
*
|
||||
* @see KeyManagerFactory#getDefaultAlgorithm()
|
||||
*/
|
||||
public void setAlgorithm(String algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source of key material.
|
||||
*
|
||||
* @see KeyManagerFactory#init(KeyStore, char[])
|
||||
*/
|
||||
public void setKeyStore(KeyStore keyStore) {
|
||||
this.keyStore = keyStore;
|
||||
}
|
||||
|
||||
public KeyManager[] getObject() throws Exception {
|
||||
return keyManagerFactory.getKeyManagers();
|
||||
}
|
||||
|
||||
public Class<?> getObjectType() {
|
||||
return KeyManager[].class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String algorithm =
|
||||
StringUtils.hasLength(this.algorithm) ? this.algorithm : KeyManagerFactory.getDefaultAlgorithm();
|
||||
|
||||
keyManagerFactory =
|
||||
StringUtils.hasLength(this.provider) ? KeyManagerFactory.getInstance(algorithm, this.provider) :
|
||||
KeyManagerFactory.getInstance(algorithm);
|
||||
|
||||
keyManagerFactory.init(keyStore, password);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyStore;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Spring factory bean for a {@link KeyStore}.
|
||||
* <p/>
|
||||
* To load an existing key store, you must set the <code>location</code> property. If this property is not set, a new,
|
||||
* empty key store is created, which is most likely not what you want.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #setLocation(org.springframework.core.io.Resource)
|
||||
* @see KeyStore
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class KeyStoreFactoryBean implements FactoryBean<KeyStore>, InitializingBean {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(KeyStoreFactoryBean.class);
|
||||
|
||||
private KeyStore keyStore;
|
||||
|
||||
private String type;
|
||||
|
||||
private String provider;
|
||||
|
||||
private Resource location;
|
||||
|
||||
private char[] password;
|
||||
|
||||
/**
|
||||
* Sets the location of the key store to use. If this is not set, a new, empty key store will be used.
|
||||
*
|
||||
* @see KeyStore#load(java.io.InputStream,char[])
|
||||
*/
|
||||
public void setLocation(Resource location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password to use for integrity checking. If this property is not set, then integrity checking is not
|
||||
* performed.
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
if (password != null) {
|
||||
this.password = password.toCharArray();
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the provider of the key store to use. If this is not set, the default is used. */
|
||||
public void setProvider(String provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of the <code>KeyStore</code> to use. If this is not set, the default is used.
|
||||
*
|
||||
* @see KeyStore#getDefaultType()
|
||||
*/
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public KeyStore getObject() {
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
public Class<KeyStore> getObjectType() {
|
||||
return KeyStore.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public final void afterPropertiesSet() throws GeneralSecurityException, IOException {
|
||||
if (StringUtils.hasLength(provider) && StringUtils.hasLength(type)) {
|
||||
keyStore = KeyStore.getInstance(type, provider);
|
||||
}
|
||||
else if (StringUtils.hasLength(type)) {
|
||||
keyStore = KeyStore.getInstance(type);
|
||||
}
|
||||
else {
|
||||
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
}
|
||||
InputStream is = null;
|
||||
try {
|
||||
if (location != null && location.exists()) {
|
||||
is = location.getInputStream();
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Loading key store from " + location);
|
||||
}
|
||||
}
|
||||
else if (logger.isWarnEnabled()) {
|
||||
logger.warn("Creating empty key store");
|
||||
}
|
||||
keyStore.load(is, password);
|
||||
}
|
||||
finally {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.keyStoreType");
|
||||
}
|
||||
// use the factory bean here, easier to setup
|
||||
KeyStoreFactoryBean factoryBean = new KeyStoreFactoryBean();
|
||||
factoryBean.setLocation(location);
|
||||
factoryBean.setPassword(password);
|
||||
factoryBean.setType(type);
|
||||
factoryBean.afterPropertiesSet();
|
||||
return 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 factoryBean.getObject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* 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 org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.authentication.DisabledException;
|
||||
import org.springframework.security.authentication.AccountExpiredException;
|
||||
import org.springframework.security.authentication.CredentialsExpiredException;
|
||||
|
||||
/**
|
||||
* Generic utility methods for Spring Security
|
||||
*
|
||||
* @author Tareq Abedrabbo
|
||||
* @since 1.5.8
|
||||
*/
|
||||
public abstract class SpringSecurityUtils {
|
||||
|
||||
/**
|
||||
* Checks the validity of a user's account and credentials.
|
||||
* @param user the user to check
|
||||
* @throws AccountExpiredException if the account has expired
|
||||
* @throws CredentialsExpiredException if the credentials have expired
|
||||
* @throws DisabledException if the account is disabled
|
||||
* @throws LockedException if the account is locked
|
||||
*/
|
||||
public static void checkUserValidity(UserDetails user)
|
||||
throws AccountExpiredException, CredentialsExpiredException, DisabledException, LockedException {
|
||||
if (!user.isAccountNonLocked()) {
|
||||
throw new LockedException("User account is locked", user);
|
||||
}
|
||||
|
||||
if (!user.isEnabled()) {
|
||||
throw new DisabledException("User is disabled", user);
|
||||
}
|
||||
|
||||
if (!user.isAccountNonExpired()) {
|
||||
throw new AccountExpiredException("User account has expired", user);
|
||||
}
|
||||
|
||||
if (!user.isCredentialsNonExpired()) {
|
||||
throw new CredentialsExpiredException("User credentials have expired", user);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Contains support classes for handling WS-Security messages.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
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.w3c.dom.Document;
|
||||
|
||||
/**
|
||||
* @author Tareq Abed Rabbo
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
class Wss4jHandler extends WSHandler {
|
||||
|
||||
/** Keys are constants from {@link WSHandlerConstants}; values are strings. */
|
||||
private Properties options = new Properties();
|
||||
|
||||
private String securementPassword;
|
||||
|
||||
private Crypto securementEncryptionCrypto;
|
||||
|
||||
private Crypto securementSignatureCrypto;
|
||||
|
||||
Wss4jHandler() {
|
||||
// set up default handler properties
|
||||
options.setProperty(WSHandlerConstants.MUST_UNDERSTAND, Boolean.toString(true));
|
||||
options.setProperty(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, Boolean.toString(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkReceiverResultsAnyOrder(List<WSSecurityEngineResult> wsResult, List<Integer> actions) {
|
||||
return super.checkReceiverResultsAnyOrder(wsResult, actions);
|
||||
}
|
||||
|
||||
void setOption(String key, String value) {
|
||||
options.setProperty(key, value);
|
||||
}
|
||||
|
||||
void setOption(String key, boolean value) {
|
||||
options.setProperty(key, Boolean.toString(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOption(String key) {
|
||||
return options.getProperty(key);
|
||||
}
|
||||
|
||||
void setSecurementPassword(String securementPassword) {
|
||||
this.securementPassword = securementPassword;
|
||||
}
|
||||
|
||||
void setSecurementEncryptionCrypto(Crypto securementEncryptionCrypto) {
|
||||
this.securementEncryptionCrypto = securementEncryptionCrypto;
|
||||
}
|
||||
|
||||
void setSecurementSignatureCrypto(Crypto securementSignatureCrypto) {
|
||||
this.securementSignatureCrypto = securementSignatureCrypto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword(Object msgContext) {
|
||||
return securementPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(Object msgContext, String key) {
|
||||
return ((MessageContext) msgContext).getProperty(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Crypto loadEncryptionCrypto(RequestData reqData) throws WSSecurityException {
|
||||
return securementEncryptionCrypto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Crypto loadSignatureCrypto(RequestData reqData) throws WSSecurityException {
|
||||
return securementSignatureCrypto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPassword(Object msgContext, String password) {
|
||||
securementPassword = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(Object msgContext, String key, Object value) {
|
||||
((MessageContext) msgContext).setProperty(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSenderAction(int doAction,
|
||||
Document doc,
|
||||
RequestData reqData,
|
||||
List<Integer> actions,
|
||||
boolean isRequest) throws WSSecurityException {
|
||||
super.doSenderAction(doAction, doc, reqData, actions, isRequest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.springframework.ws.soap.security.WsSecurityFaultException;
|
||||
|
||||
/**
|
||||
* WSS4J-specific version of the {@link WsSecurityFaultException}.
|
||||
*
|
||||
* @author Tareq Abed Rabbo
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class Wss4jSecurityFaultException extends WsSecurityFaultException {
|
||||
|
||||
public Wss4jSecurityFaultException(QName faultCode, String faultString, String faultActor) {
|
||||
super(faultCode, faultString, faultActor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,713 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.security.cert.X509Certificate;
|
||||
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;
|
||||
|
||||
import org.apache.ws.security.WSConstants;
|
||||
import org.apache.ws.security.WSSConfig;
|
||||
import org.apache.ws.security.WSSecurityEngine;
|
||||
import org.apache.ws.security.WSSecurityEngineResult;
|
||||
import org.apache.ws.security.WSSecurityException;
|
||||
import org.apache.ws.security.WSUsernameTokenPrincipal;
|
||||
import org.apache.ws.security.components.crypto.Crypto;
|
||||
import org.apache.ws.security.handler.RequestData;
|
||||
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;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
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;
|
||||
import org.springframework.ws.soap.security.callback.CleanupCallback;
|
||||
import org.springframework.ws.soap.security.wss4j.callback.UsernameTokenPrincipalCallback;
|
||||
|
||||
/**
|
||||
* A WS-Security endpoint interceptor based on Apache's WSS4J. This interceptor 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.
|
||||
* <p/>
|
||||
* Valid <strong>validation</strong> actions are:
|
||||
* <p/>
|
||||
* <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 secret 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
|
||||
* @see <a href="http://ws.apache.org/wss4j/">Apache WSS4J</a>
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor implements InitializingBean {
|
||||
|
||||
public static final String SECUREMENT_USER_PROPERTY_NAME = "Wss4jSecurityInterceptor.securementUser";
|
||||
|
||||
private int securementAction;
|
||||
|
||||
private String securementActions;
|
||||
|
||||
private List<Integer> securementActionsVector;
|
||||
|
||||
private String securementUsername;
|
||||
|
||||
private CallbackHandler validationCallbackHandler;
|
||||
|
||||
private int validationAction;
|
||||
|
||||
private String validationActions;
|
||||
|
||||
private List<Integer> validationActionsVector;
|
||||
|
||||
private String validationActor;
|
||||
|
||||
private Crypto validationDecryptionCrypto;
|
||||
|
||||
private Crypto validationSignatureCrypto;
|
||||
|
||||
private boolean timestampStrict = true;
|
||||
|
||||
private boolean enableSignatureConfirmation;
|
||||
|
||||
private int validationTimeToLive = 300;
|
||||
|
||||
private int securementTimeToLive = 300;
|
||||
|
||||
private WSSConfig wssConfig;
|
||||
|
||||
private final Wss4jHandler handler = new Wss4jHandler();
|
||||
|
||||
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 ArrayList<Integer>();
|
||||
try {
|
||||
securementAction = WSSecurityUtil.decodeAction(securementActions, securementActionsVector);
|
||||
}
|
||||
catch (WSSecurityException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The actor name of the <code>wsse:Security</code> header.
|
||||
* <p/>
|
||||
* If this parameter is omitted, the actor name is not set.
|
||||
* <p/>
|
||||
* The value of the actor or role has to match the receiver's setting or may contain standard values.
|
||||
*/
|
||||
public void setSecurementActor(String securementActor) {
|
||||
handler.setOption(WSHandlerConstants.ACTOR, securementActor);
|
||||
}
|
||||
|
||||
public void setSecurementEncryptionCrypto(Crypto securementEncryptionCrypto) {
|
||||
handler.setSecurementEncryptionCrypto(securementEncryptionCrypto);
|
||||
}
|
||||
|
||||
/** Sets the key name that needs to be sent for encryption. */
|
||||
public void setSecurementEncryptionEmbeddedKeyName(String securementEncryptionEmbeddedKeyName) {
|
||||
handler.setOption(WSHandlerConstants.ENC_KEY_NAME, securementEncryptionEmbeddedKeyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines which key identifier type to use. The WS-Security specifications recommends to use the identifier type
|
||||
* <code>IssuerSerial</code>. For possible encryption key identifier types refer to {@link
|
||||
* org.apache.ws.security.handler.WSHandlerConstants#keyIdentifier}. For encryption <code>IssuerSerial</code>,
|
||||
* <code>X509KeyIdentifier</code>, <code>DirectReference</code>, <code>Thumbprint</code>,
|
||||
* <code>SKIKeyIdentifier</code>, and <code>EmbeddedKeyName</code> are valid only.
|
||||
*/
|
||||
public void setSecurementEncryptionKeyIdentifier(String securementEncryptionKeyIdentifier) {
|
||||
handler.setOption(WSHandlerConstants.ENC_KEY_ID, securementEncryptionKeyIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines which algorithm to use to encrypt the generated symmetric key. Currently WSS4J supports {@link
|
||||
* WSConstants#KEYTRANSPORT_RSA15} and {@link WSConstants#KEYTRANSPORT_RSAOEP}.
|
||||
*/
|
||||
public void setSecurementEncryptionKeyTransportAlgorithm(String securementEncryptionKeyTransportAlgorithm) {
|
||||
handler.setOption(WSHandlerConstants.ENC_KEY_TRANSPORT, securementEncryptionKeyTransportAlgorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Property to define which parts of the request shall be encrypted.
|
||||
* <p/>
|
||||
* The value of this property is a list of semi-colon separated element names that identify the elements to encrypt.
|
||||
* An encryption mode specifier and a namespace identification, each inside a pair of curly brackets, may precede
|
||||
* each element name.
|
||||
* <p/>
|
||||
* The encryption mode specifier is either <code>{Content}</code> or <code>{Element}</code>. Please refer to the W3C
|
||||
* XML Encryption specification about the differences between Element and Content encryption. The encryption mode
|
||||
* defaults to <code>Content</code> if it is omitted. Example of a list:
|
||||
* <pre>
|
||||
* <property name="securementEncryptionParts"
|
||||
* value="{Content}{http://example.org/paymentv2}CreditCard;
|
||||
* {Element}{}UserName" />
|
||||
* </pre>
|
||||
* The the first entry of the list identifies the element <code>CreditCard</code> in the namespace
|
||||
* <code>http://example.org/paymentv2</code>, and will encrypt its content. Be aware that the element name, the
|
||||
* namespace identifier, and the encryption modifier are case sensitive.
|
||||
* <p/>
|
||||
* The encryption modifier and the namespace identifier can be omitted. In this case the encryption mode defaults to
|
||||
* <code>Content</code> and the namespace is set to the SOAP namespace.
|
||||
* <p/>
|
||||
* An empty encryption mode defaults to <code>Content</code>, an empty namespace identifier defaults to the SOAP
|
||||
* namespace. The second line of the example defines <code>Element</code> as encryption mode for an
|
||||
* <code>UserName</code> element in the SOAP namespace.
|
||||
* <p/>
|
||||
* To specify an element without a namespace use the string <code>Null</code> as the namespace name (this is a case
|
||||
* sensitive string)
|
||||
* <p/>
|
||||
* If no list is specified, the handler encrypts the SOAP Body in <code>Content</code> mode by default.
|
||||
*/
|
||||
public void setSecurementEncryptionParts(String securementEncryptionParts) {
|
||||
handler.setOption(WSHandlerConstants.ENCRYPTION_PARTS, securementEncryptionParts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines which symmetric encryption algorithm to use. WSS4J supports the following alorithms: {@link
|
||||
* WSConstants#TRIPLE_DES}, {@link WSConstants#AES_128}, {@link WSConstants#AES_256}, and {@link
|
||||
* WSConstants#AES_192}. Except for AES 192 all of these algorithms are required by the XML Encryption
|
||||
* specification.
|
||||
*/
|
||||
public void setSecurementEncryptionSymAlgorithm(String securementEncryptionSymAlgorithm) {
|
||||
this.handler.setOption(WSHandlerConstants.ENC_SYM_ALGO, securementEncryptionSymAlgorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* The user's name for encryption.
|
||||
* <p/>
|
||||
* The encryption functions uses the public key of this user's certificate to encrypt the generated symmetric key.
|
||||
* <p/>
|
||||
* If this parameter is not set, then the encryption function falls back to the {@link
|
||||
* org.apache.ws.security.handler.WSHandlerConstants#USER} parameter to get the certificate.
|
||||
* <p/>
|
||||
* If <b>only</b> encryption of the SOAP body data is requested, it is recommended to use this parameter to define
|
||||
* the username. The application can then use the standard user and password functions (see example at {@link
|
||||
* org.apache.ws.security.handler.WSHandlerConstants#USER} to enable HTTP authentication functions.
|
||||
* <p/>
|
||||
* Encryption only does not authenticate a user / sender, therefore it does not need a password.
|
||||
* <p/>
|
||||
* Placing the username of the encryption certificate in the configuration file is not a security risk, because the
|
||||
* public key of that certificate is used only.
|
||||
* <p/>
|
||||
*/
|
||||
public void setSecurementEncryptionUser(String securementEncryptionUser) {
|
||||
handler.setOption(WSHandlerConstants.ENCRYPTION_USER, securementEncryptionUser);
|
||||
}
|
||||
|
||||
public void setSecurementPassword(String securementPassword) {
|
||||
this.handler.setSecurementPassword(securementPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific parameter for UsernameToken action to define the encoding of the passowrd.
|
||||
* <p/>
|
||||
* The parameter can be set to either {@link WSConstants#PW_DIGEST} or to {@link WSConstants#PW_TEXT}.
|
||||
* <p/>
|
||||
* The default setting is PW_DIGEST.
|
||||
*/
|
||||
public void setSecurementPasswordType(String securementUsernameTokenPasswordType) {
|
||||
handler.setOption(WSHandlerConstants.PASSWORD_TYPE, securementUsernameTokenPasswordType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines which signature algorithm to use.
|
||||
* @see WSConstants#RSA
|
||||
* @see WSConstants#DSA
|
||||
*/
|
||||
public void setSecurementSignatureAlgorithm(String securementSignatureAlgorithm) {
|
||||
handler.setOption(WSHandlerConstants.SIG_ALGO, securementSignatureAlgorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines which signature digest algorithm to use.
|
||||
*/
|
||||
public void setSecurementSignatureDigestAlgorithm(String digestAlgorithm) {
|
||||
handler.setOption(WSHandlerConstants.SIG_DIGEST_ALGO, digestAlgorithm);
|
||||
}
|
||||
|
||||
public void setSecurementSignatureCrypto(Crypto securementSignatureCrypto) {
|
||||
handler.setSecurementSignatureCrypto(securementSignatureCrypto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines which key identifier type to use. The WS-Security specifications recommends to use the identifier type
|
||||
* <code>IssuerSerial</code>. For possible signature key identifier types refer to {@link
|
||||
* org.apache.ws.security.handler.WSHandlerConstants#keyIdentifier}. For signature <code>IssuerSerial</code> and
|
||||
* <code>DirectReference</code> are valid only.
|
||||
*/
|
||||
public void setSecurementSignatureKeyIdentifier(String securementSignatureKeyIdentifier) {
|
||||
handler.setOption(WSHandlerConstants.SIG_KEY_ID, securementSignatureKeyIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Property to define which parts of the request shall be signed.
|
||||
* <p/>
|
||||
* Refer to {@link #setSecurementEncryptionParts(String)} for a detailed description of the format of the value
|
||||
* string.
|
||||
* <p/>
|
||||
* If this property is not specified the handler signs the SOAP Body by default.
|
||||
* <p/>
|
||||
* The WS Security specifications define several formats to transfer the signature tokens (certificates) or
|
||||
* references to these tokens. Thus, the plain element name <code>Token</code> signs the token and takes care of the
|
||||
* different formats.
|
||||
* <p/>
|
||||
* To sign the SOAP body <b>and</b> the signature token the value of this parameter must contain:
|
||||
* <pre>
|
||||
* <property name="securementSignatureParts"
|
||||
* value="{}{http://schemas.xmlsoap.org/soap/envelope/}Body; Token" />
|
||||
* </pre>
|
||||
* To specify an element without a namespace use the string <code>Null</code> as the namespace name (this is a case
|
||||
* sensitive string)
|
||||
* <p/>
|
||||
* If there is no other element in the request with a local name of <code>Body</code> then the SOAP namespace
|
||||
* identifier can be empty (<code>{}</code>).
|
||||
*/
|
||||
public void setSecurementSignatureParts(String securementSignatureParts) {
|
||||
handler.setOption(WSHandlerConstants.SIGNATURE_PARTS, securementSignatureParts);
|
||||
}
|
||||
|
||||
/**
|
||||
* The user's name for signature.
|
||||
* <p/>
|
||||
* This name is used as the alias name in the keystore to get user's
|
||||
* certificate and private key to perform signing.
|
||||
* <p/>
|
||||
* If this parameter is not set, then the signature
|
||||
* function falls back to the alias specified by {@link #setSecurementUsername(String)}.
|
||||
* <p/>
|
||||
*/
|
||||
public void setSecurementSignatureUser(String securementSignatureUser) {
|
||||
handler.setOption(WSHandlerConstants.SIGNATURE_USER, securementSignatureUser);
|
||||
}
|
||||
|
||||
/** Sets the username for securement username token or/and the alias of the private key for securement signature */
|
||||
public void setSecurementUsername(String securementUsername) {
|
||||
this.securementUsername = securementUsername;
|
||||
}
|
||||
|
||||
/** Sets the time to live on the outgoing message */
|
||||
public void setSecurementTimeToLive(int securementTimeToLive) {
|
||||
if (securementTimeToLive <= 0) {
|
||||
throw new IllegalArgumentException("timeToLive must be positive");
|
||||
}
|
||||
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) {
|
||||
throw new IllegalArgumentException("timeToLive must be positive");
|
||||
}
|
||||
this.validationTimeToLive = validationTimeToLive;
|
||||
}
|
||||
|
||||
/** Sets the validation actions to be executed by the interceptor. */
|
||||
public void setValidationActions(String actions) {
|
||||
this.validationActions = actions;
|
||||
try {
|
||||
validationActionsVector = new ArrayList<Integer>();
|
||||
validationAction = WSSecurityUtil.decodeAction(actions, validationActionsVector);
|
||||
}
|
||||
catch (WSSecurityException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void setValidationActor(String validationActor) {
|
||||
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;
|
||||
}
|
||||
|
||||
/** Sets the Crypto to use to verify the signature of incoming messages */
|
||||
public void setValidationSignatureCrypto(Crypto signatureCrypto) {
|
||||
this.validationSignatureCrypto = signatureCrypto;
|
||||
}
|
||||
|
||||
/** Whether to enable signatureConfirmation or not. By default signatureConfirmation is enabled */
|
||||
public void setEnableSignatureConfirmation(boolean enableSignatureConfirmation) {
|
||||
handler.setOption(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, enableSignatureConfirmation);
|
||||
this.enableSignatureConfirmation = enableSignatureConfirmation;
|
||||
}
|
||||
|
||||
/** Sets if the generated timestamp header's precision is in milliseconds. */
|
||||
public void setTimestampPrecisionInMilliseconds(boolean timestampPrecisionInMilliseconds) {
|
||||
handler.setOption(WSHandlerConstants.TIMESTAMP_PRECISION, timestampPrecisionInMilliseconds);
|
||||
}
|
||||
|
||||
/** Sets whether or not timestamp verification is done with the server-side time to live */
|
||||
public void setTimestampStrict(boolean timestampStrict) {
|
||||
this.timestampStrict = timestampStrict;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the <code>mustUnderstand</code> attribute on WS-Security headers on outgoing messages. Default is
|
||||
* <code>true</code>.
|
||||
*/
|
||||
public void setSecurementMustUnderstand(boolean securementMustUnderstand) {
|
||||
handler.setOption(WSHandlerConstants.MUST_UNDERSTAND, securementMustUnderstand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the additional elements in <code>UsernameToken</code>s.
|
||||
* <p/>
|
||||
* The value of this parameter is a list of element names that are added to the UsernameToken. The names of the list
|
||||
* a separated by spaces.
|
||||
* <p/>
|
||||
* The list may contain the names <code>Nonce</code> and <code>Created</code> only (case sensitive). Use this option
|
||||
* if the password type is <code>passwordText</code> and the handler shall add the <code>Nonce</code> and/or
|
||||
* <code>Created</code> elements.
|
||||
*/
|
||||
public void setSecurementUsernameTokenElements(String securementUsernameTokenElements) {
|
||||
handler.setOption(WSHandlerConstants.ADD_UT_ELEMENTS, securementUsernameTokenElements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the web service specification settings.
|
||||
* <p>
|
||||
* The default settings follow the latest OASIS and changing anything might violate the OASIS specs.
|
||||
*
|
||||
* @param config web service security configuration or {@code null} to use default settings
|
||||
*/
|
||||
public void setWssConfig(WSSConfig config) {
|
||||
securityEngine.setWssConfig(config);
|
||||
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.handler.setOption(WSHandlerConstants.IS_BSP_COMPLIANT, bspCompliant);
|
||||
this.bspCompliant = bspCompliant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location of the SAML properties file. The file should be available on the classpath.
|
||||
*/
|
||||
public void setSamlProperties(String location) {
|
||||
handler.setOption(WSHandlerConstants.SAML_PROP_FILE, location);
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.isTrue(validationActions != null || securementActions != null,
|
||||
"validationActions or securementActions are required");
|
||||
if (validationActions != null) {
|
||||
if ((validationAction & WSConstants.UT) != 0) {
|
||||
Assert.notNull(validationCallbackHandler, "validationCallbackHandler is required");
|
||||
}
|
||||
|
||||
if ((validationAction & WSConstants.SIGN) != 0) {
|
||||
Assert.notNull(validationSignatureCrypto, "validationSignatureCrypto is required");
|
||||
}
|
||||
}
|
||||
// securement actions are not to be validated at start up as they could
|
||||
// be configured dynamically via the message context
|
||||
|
||||
// allow for qualified password types for .Net interoperability
|
||||
securityEngine.getWssConfig().setAllowNamespaceQualifiedPasswordTypes(true);
|
||||
securityEngine.getWssConfig().setWsiBSPCompliant(bspCompliant);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void secureMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws WsSecuritySecurementException {
|
||||
if (securementAction == WSConstants.NO_SECURITY && !enableSignatureConfirmation) {
|
||||
return;
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Securing message [" + soapMessage + "] with actions [" + securementActions + "]");
|
||||
}
|
||||
RequestData requestData = initializeRequestData(messageContext);
|
||||
|
||||
Document envelopeAsDocument = soapMessage.getDocument();
|
||||
try {
|
||||
// In case on signature confirmation with no other securement
|
||||
// action, we need to pass an empty securementActionsVector to avoid
|
||||
// NPE
|
||||
if (securementAction == WSConstants.NO_SECURITY) {
|
||||
securementActionsVector = new ArrayList<Integer>(0);
|
||||
}
|
||||
|
||||
handler.doSenderAction(securementAction, envelopeAsDocument, requestData, securementActionsVector, false);
|
||||
}
|
||||
catch (WSSecurityException ex) {
|
||||
throw new Wss4jSecuritySecurementException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
soapMessage.setDocument(envelopeAsDocument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a request data for the given message context.
|
||||
*
|
||||
* @param messageContext the message context
|
||||
* @return the request data
|
||||
*/
|
||||
protected RequestData initializeRequestData(MessageContext messageContext) {
|
||||
RequestData requestData = new RequestData();
|
||||
requestData.setMsgContext(messageContext);
|
||||
|
||||
// reads securementUsername first from the context then from the property
|
||||
String contextUsername = (String) messageContext.getProperty(SECUREMENT_USER_PROPERTY_NAME);
|
||||
if (StringUtils.hasLength(contextUsername)) {
|
||||
requestData.setUsername(contextUsername);
|
||||
}
|
||||
else {
|
||||
requestData.setUsername(securementUsername);
|
||||
}
|
||||
|
||||
requestData.setTimeToLive(securementTimeToLive);
|
||||
|
||||
requestData.setUseDerivedKey(securementUseDerivedKey);
|
||||
|
||||
requestData.setWssConfig(wssConfig);
|
||||
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void validateMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws WsSecurityValidationException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Validating message [" + soapMessage + "] with actions [" + validationActions + "]");
|
||||
}
|
||||
|
||||
if (validationAction == WSConstants.NO_SECURITY) {
|
||||
return;
|
||||
}
|
||||
|
||||
Document envelopeAsDocument = soapMessage.getDocument();
|
||||
|
||||
// Header processing
|
||||
|
||||
try {
|
||||
List<WSSecurityEngineResult> results = securityEngine
|
||||
.processSecurityHeader(envelopeAsDocument, validationActor, validationCallbackHandler,
|
||||
validationSignatureCrypto, validationDecryptionCrypto);
|
||||
|
||||
// Results verification
|
||||
if (CollectionUtils.isEmpty(results)) {
|
||||
throw new Wss4jSecurityValidationException("No WS-Security header found");
|
||||
}
|
||||
|
||||
checkResults(results, validationActionsVector);
|
||||
|
||||
// puts the results in the context
|
||||
// useful for Signature Confirmation
|
||||
updateContextWithResults(messageContext, results);
|
||||
|
||||
verifyCertificateTrust(results);
|
||||
|
||||
verifyTimestamp(results);
|
||||
|
||||
processPrincipal(results);
|
||||
}
|
||||
catch (WSSecurityException ex) {
|
||||
throw new Wss4jSecurityValidationException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
soapMessage.setDocument(envelopeAsDocument);
|
||||
|
||||
soapMessage.getEnvelope().getHeader().removeHeaderElement(WS_SECURITY_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 validationActions the decoded validation actions
|
||||
* @throws Wss4jSecurityValidationException if the results are deemed invalid
|
||||
*/
|
||||
protected void checkResults(List<WSSecurityEngineResult> results, List<Integer> validationActions)
|
||||
throws Wss4jSecurityValidationException {
|
||||
if (!handler.checkReceiverResultsAnyOrder(results, validationActions)) {
|
||||
throw new Wss4jSecurityValidationException("Security processing failed (actions mismatch)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the results of WS-Security headers processing in the message context. Some actions like Signature
|
||||
* Confirmation require this.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
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);
|
||||
handlerResults.add(0, rResult);
|
||||
messageContext.setProperty(WSHandlerConstants.RECV_RESULTS, handlerResults);
|
||||
}
|
||||
|
||||
/** Verifies the trust of a certificate. */
|
||||
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);
|
||||
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(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) {
|
||||
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(List<WSSecurityEngineResult> results) {
|
||||
WSSecurityEngineResult actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.UT);
|
||||
|
||||
if (actionResult != null) {
|
||||
Principal principal = (Principal) actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
|
||||
if (principal != null && principal instanceof WSUsernameTokenPrincipal) {
|
||||
WSUsernameTokenPrincipal usernameTokenPrincipal = (WSUsernameTokenPrincipal) principal;
|
||||
UsernameTokenPrincipalCallback callback = new UsernameTokenPrincipalCallback(usernameTokenPrincipal);
|
||||
try {
|
||||
validationCallbackHandler.handle(new Callback[]{callback});
|
||||
}
|
||||
catch (IOException ex) {
|
||||
logger.warn("Principal callback resulted in IOException", ex);
|
||||
}
|
||||
catch (UnsupportedCallbackException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanUp() {
|
||||
if (validationCallbackHandler != null) {
|
||||
try {
|
||||
CleanupCallback cleanupCallback = new CleanupCallback();
|
||||
validationCallbackHandler.handle(new Callback[]{cleanupCallback});
|
||||
}
|
||||
catch (IOException ex) {
|
||||
logger.warn("Cleanup callback resulted in IOException", ex);
|
||||
}
|
||||
catch (UnsupportedCallbackException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.springframework.ws.soap.security.WsSecuritySecurementException;
|
||||
|
||||
/**
|
||||
* WSS4J-specific version of the {@link WsSecuritySecurementException}.
|
||||
*
|
||||
* @author Tareq Abed Rabbo
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class Wss4jSecuritySecurementException extends WsSecuritySecurementException {
|
||||
|
||||
public Wss4jSecuritySecurementException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public Wss4jSecuritySecurementException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.springframework.ws.soap.security.WsSecurityValidationException;
|
||||
|
||||
/**
|
||||
* WSS4J-specific version of the {@link WsSecurityValidationException}.
|
||||
*
|
||||
* @author Tareq Abed Rabbo
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class Wss4jSecurityValidationException extends WsSecurityValidationException {
|
||||
|
||||
public Wss4jSecurityValidationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public Wss4jSecurityValidationException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.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.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
@Override
|
||||
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.SECURITY_CONTEXT_TOKEN:
|
||||
handleSecurityContextToken(passwordCallback);
|
||||
break;
|
||||
case WSPasswordCallback.CUSTOM_TOKEN:
|
||||
handleCustomToken(passwordCallback);
|
||||
break;
|
||||
case WSPasswordCallback.SECRET_KEY:
|
||||
handleSecretKey(passwordCallback);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedCallbackException(callback,
|
||||
"Unknown usage [" + passwordCallback.getUsage() + "]");
|
||||
}
|
||||
}
|
||||
else if (callback instanceof CleanupCallback) {
|
||||
handleCleanup((CleanupCallback) callback);
|
||||
}
|
||||
else if (callback instanceof UsernameTokenPrincipalCallback) {
|
||||
handleUsernameTokenPrincipal((UsernameTokenPrincipalCallback) callback);
|
||||
}
|
||||
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#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/>
|
||||
* 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#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}.
|
||||
*/
|
||||
protected void handleSignature(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#SECRET_KEY} usage.
|
||||
* <p/>
|
||||
* Default implementation throws an {@link UnsupportedCallbackException}.
|
||||
*/
|
||||
protected void handleSecretKey(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when a {@link CleanupCallback} is passed to {@link #handle(Callback[])}.
|
||||
* <p/>
|
||||
* Default implementation throws an {@link UnsupportedCallbackException}.
|
||||
*/
|
||||
protected void handleCleanup(CleanupCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when a {@link UsernameTokenPrincipalCallback} is passed to {@link #handle(Callback[])}.
|
||||
* <p/>
|
||||
* Default implementation throws an {@link UnsupportedCallbackException}.
|
||||
*/
|
||||
protected void handleUsernameTokenPrincipal(UsernameTokenPrincipalCallback callback)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.Key;
|
||||
import java.security.KeyStore;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
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.
|
||||
*
|
||||
* @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 decryption 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 defaults 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();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleDecrypt(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
callback.setPassword(privateKeyPassword);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void handleSecretKey(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
try {
|
||||
String identifier = callback.getIdentifier();
|
||||
Key key = keyStore.getKey(identifier, symmetricKeyPassword);
|
||||
if (key instanceof SecretKey) {
|
||||
callback.setKey(key.getEncoded());
|
||||
}
|
||||
else {
|
||||
logger.error("Key [" + key + "] is not a javax.crypto.SecretKey");
|
||||
}
|
||||
}
|
||||
catch (GeneralSecurityException ex) {
|
||||
logger.error("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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.apache.ws.security.WSPasswordCallback;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @author Arjen Poutsma
|
||||
* @see #setUsers(java.util.Properties)
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class SimplePasswordValidationCallbackHandler extends AbstractWsPasswordCallbackHandler
|
||||
implements InitializingBean {
|
||||
|
||||
private Map<String, String > users = new HashMap<String, String>();
|
||||
|
||||
/** Sets the users to validate against. Property names are usernames, property values are passwords. */
|
||||
public void setUsers(Properties users) {
|
||||
for (Map.Entry<Object, Object> entry : users.entrySet()) {
|
||||
if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
|
||||
this.users.put((String) entry.getKey(), (String) entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setUsersMap(Map<String, String> users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(users, "users is required");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleUsernameToken(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
String identifier = callback.getIdentifier();
|
||||
callback.setPassword(users.get(identifier));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.UnsupportedCallbackException;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
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.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 plain text or digest password using an Spring Security {@code UserDetailsService}.
|
||||
* <p/>
|
||||
* 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
|
||||
* @since 2.1
|
||||
*/
|
||||
public class SpringSecurityPasswordValidationCallbackHandler extends AbstractWsPasswordCallbackHandler
|
||||
implements InitializingBean {
|
||||
|
||||
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 Spring Security user details service. Required. */
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(userDetailsService, "userDetailsService is required");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleUsernameToken(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
String identifier = callback.getIdentifier();
|
||||
UserDetails user = loadUserDetails(identifier);
|
||||
if (user != null) {
|
||||
SpringSecurityUtils.checkUserValidity(user);
|
||||
callback.setPassword(user.getPassword());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleUsernameTokenPrincipal(UsernameTokenPrincipalCallback callback)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
UserDetails user = loadUserDetails(callback.getPrincipal().getName());
|
||||
WSUsernameTokenPrincipal principal = callback.getPrincipal();
|
||||
UsernamePasswordAuthenticationToken authRequest =
|
||||
new UsernamePasswordAuthenticationToken(principal, principal.getPassword(), user.getAuthorities());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication success: " + authRequest.toString());
|
||||
}
|
||||
SecurityContextHolder.getContext().setAuthentication(authRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleCleanup(CleanupCallback callback) throws IOException, UnsupportedCallbackException {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
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,48 @@
|
||||
/*
|
||||
* 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.Serializable;
|
||||
import javax.security.auth.callback.Callback;
|
||||
|
||||
import org.apache.ws.security.WSUsernameTokenPrincipal;
|
||||
|
||||
/**
|
||||
* Underlying security services instantiate and pass a <code>UsernameTokenPrincipalCallback</code> to the
|
||||
* <code>handle</code> method of a <code>CallbackHandler</code> to pass a security
|
||||
* <code>WSUsernameTokenPrincipal</code>.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see WSUsernameTokenPrincipal
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class UsernameTokenPrincipalCallback implements Callback, Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3022202225157082715L;
|
||||
|
||||
private final WSUsernameTokenPrincipal principal;
|
||||
|
||||
/** Construct a <code>UsernameTokenPrincipalCallback</code>. */
|
||||
public UsernameTokenPrincipalCallback(WSUsernameTokenPrincipal principal) {
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
/** Get the retrieved <code>Principal</code>. */
|
||||
public WSUsernameTokenPrincipal getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Contains <code>CallbackHandler</code> implementations for WSS4J.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
Contains classes for using the <a href="http://ws.apache.org/wss4j/">Apache WSS4J</a> WS-Security implementation within
|
||||
Spring-WS.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright 2005-2011 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.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.apache.ws.security.components.crypto.Crypto;
|
||||
import org.apache.ws.security.components.crypto.CryptoFactory;
|
||||
import org.apache.ws.security.components.crypto.Merlin;
|
||||
|
||||
/**
|
||||
* Spring factory bean for a WSS4J {@link Crypto}. Allows for strong-typed property configuration, or configuration
|
||||
* through {@link Properties}.
|
||||
* <p/>
|
||||
* Requires either individual properties, or the {@link #setConfiguration(java.util.Properties) configuration} property
|
||||
* to be set.
|
||||
*
|
||||
* @author Tareq Abed Rabbo
|
||||
* @author Arjen Poutsma
|
||||
* @see org.apache.ws.security.components.crypto.Crypto
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class CryptoFactoryBean implements FactoryBean<Crypto>, BeanClassLoaderAware, InitializingBean {
|
||||
|
||||
private Properties configuration = new Properties();
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
private Crypto crypto;
|
||||
|
||||
private static final String CRYPTO_PROVIDER_PROPERTY = "org.apache.ws.security.crypto.provider";
|
||||
|
||||
/**
|
||||
* Sets the configuration of the Crypto. Setting this property overrides all previously set configuration, through
|
||||
* the type-safe properties
|
||||
*
|
||||
* @see org.apache.ws.security.components.crypto.CryptoFactory#getInstance(java.util.Properties)
|
||||
*/
|
||||
public void setConfiguration(Properties properties) {
|
||||
Assert.notNull(properties, "'properties' must not be null");
|
||||
this.configuration.putAll(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link org.apache.ws.security.components.crypto.Crypto} provider name. Defaults to {@link
|
||||
* org.apache.ws.security.components.crypto.Merlin}.
|
||||
* <p/>
|
||||
* This property maps to the WSS4J {@code org.apache.ws.security.crypto.provider} property.
|
||||
*
|
||||
* @param cryptoProviderClass the crypto provider class
|
||||
*/
|
||||
public void setCryptoProvider(Class<? extends Crypto> cryptoProviderClass) {
|
||||
this.configuration.setProperty(CRYPTO_PROVIDER_PROPERTY, cryptoProviderClass.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location of the key store to be loaded in the {@link org.apache.ws.security.components.crypto.Crypto}
|
||||
* instance.
|
||||
* <p/>
|
||||
* This property maps to the WSS4J {@code org.apache.ws.security.crypto.merlin.file} property.
|
||||
*
|
||||
* @param location the key store location
|
||||
* @throws java.io.IOException when the resource cannot be opened
|
||||
*/
|
||||
public void setKeyStoreLocation(Resource location) throws IOException {
|
||||
String resourcePath = getResourcePath(location);
|
||||
this.configuration.setProperty("org.apache.ws.security.crypto.merlin.file", resourcePath);
|
||||
}
|
||||
|
||||
private String getResourcePath(Resource resource) throws IOException {
|
||||
try {
|
||||
return resource.getFile().getAbsolutePath();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
if (resource instanceof ClassPathResource) {
|
||||
ClassPathResource classPathResource = (ClassPathResource) resource;
|
||||
return classPathResource.getPath();
|
||||
}
|
||||
else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key store provider.
|
||||
* <p/>
|
||||
* This property maps to the WSS4J {@code org.apache.ws.security.crypto.merlin.keystore.provider} property.
|
||||
*
|
||||
* @param provider the key store provider
|
||||
*/
|
||||
public void setKeyStoreProvider(String provider) {
|
||||
this.configuration.setProperty("org.apache.ws.security.crypto.merlin.keystore.provider", provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key store password. Defaults to {@code security}.
|
||||
* <p/>
|
||||
* This property maps to the WSS4J {@code org.apache.ws.security.crypto.merlin.keystore.password} property.
|
||||
*
|
||||
* @param password the key store password
|
||||
*/
|
||||
public void setKeyStorePassword(String password) {
|
||||
this.configuration.setProperty("org.apache.ws.security.crypto.merlin.keystore.password", password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key store type. Defaults to {@link java.security.KeyStore#getDefaultType()}.
|
||||
* <p/>
|
||||
* This property maps to the WSS4J {@code org.apache.ws.security.crypto.merlin.keystore.type} property.
|
||||
*
|
||||
* @param type the key store type
|
||||
*/
|
||||
public void setKeyStoreType(String type) {
|
||||
this.configuration.setProperty("org.apache.ws.security.crypto.merlin.keystore.type", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the trust store password. Defaults to {@code changeit}.
|
||||
* <p/>
|
||||
* WSS4J crypto uses the standard J2SE trust store, i.e. {@code $JAVA_HOME/lib/security/cacerts}.
|
||||
* <p/>
|
||||
* <p/>
|
||||
* This property maps to the WSS4J {@code org.apache.ws.security.crypto.merlin.cacerts.password} property.
|
||||
*
|
||||
* @param password the trust store password
|
||||
*/
|
||||
public void setTrustStorePassword(String password) {
|
||||
this.configuration.setProperty("org.apache.ws.security.crypto.merlin.cacerts.password", password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alias name of the default certificate which has been specified as a property. This should be the
|
||||
* certificate that is used for signature and encryption. This alias corresponds to the certificate that should be
|
||||
* used whenever KeyInfo is not present in a signed or an encrypted message.
|
||||
* <p/>
|
||||
* This property maps to the WSS4J {@code org.apache.ws.security.crypto.merlin.keystore.alias} property.
|
||||
*
|
||||
* @param defaultX509Alias alias name of the default X509 certificate
|
||||
*/
|
||||
public void setDefaultX509Alias(String defaultX509Alias) {
|
||||
this.configuration.setProperty("org.apache.ws.security.crypto.merlin.keystore.alias", defaultX509Alias);
|
||||
}
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (!configuration.containsKey(CRYPTO_PROVIDER_PROPERTY)) {
|
||||
configuration.setProperty(CRYPTO_PROVIDER_PROPERTY, Merlin.class.getName());
|
||||
}
|
||||
this.crypto = CryptoFactory.getInstance(configuration, classLoader);
|
||||
}
|
||||
|
||||
public Class<Crypto> getObjectType() {
|
||||
return Crypto.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Crypto getObject() throws Exception {
|
||||
return crypto;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Contains support classes for working with WSS4J.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.x509;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.soap.security.x509.cache.NullX509UserCache;
|
||||
import org.springframework.ws.soap.security.x509.cache.X509UserCache;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Processes an X.509 authentication request.
|
||||
* <p>Migrated from Spring Security 2 since it has been removed in Spring Security 3.</p>
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id: X509AuthenticationProvider.java 3256 2008-08-18 18:20:48Z luke_t $
|
||||
*/
|
||||
public class X509AuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(X509AuthenticationProvider.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
private X509AuthoritiesPopulator x509AuthoritiesPopulator;
|
||||
private X509UserCache userCache = new NullX509UserCache();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(userCache, "An x509UserCache must be set");
|
||||
Assert.notNull(x509AuthoritiesPopulator, "An X509AuthoritiesPopulator must be set");
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
}
|
||||
|
||||
/**
|
||||
* If the supplied authentication token contains a certificate then this will be passed to the configured
|
||||
* {@link X509AuthoritiesPopulator} to obtain the user details and authorities for the user identified by the
|
||||
* certificate.<p>If no certificate is present (for example, if the filter is applied to an HttpRequest for
|
||||
* which client authentication hasn't been configured in the container) then a BadCredentialsException will be
|
||||
* raised.</p>
|
||||
*
|
||||
* @param authentication the authentication request.
|
||||
*
|
||||
* @return an X509AuthenticationToken containing the authorities of the principal represented by the certificate.
|
||||
*
|
||||
* @throws AuthenticationException if the {@link X509AuthoritiesPopulator} rejects the certficate.
|
||||
* @throws BadCredentialsException if no certificate was presented in the authentication request.
|
||||
*/
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
if (!supports(authentication.getClass())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("X509 authentication request: " + authentication);
|
||||
}
|
||||
|
||||
X509Certificate clientCertificate = (X509Certificate) authentication.getCredentials();
|
||||
|
||||
if (clientCertificate == null) {
|
||||
throw new BadCredentialsException(messages.getMessage("X509AuthenticationProvider.certificateNull",
|
||||
"Certificate is null"));
|
||||
}
|
||||
|
||||
UserDetails user = userCache.getUserFromCache(clientCertificate);
|
||||
|
||||
if (user == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authenticating with certificate " + clientCertificate);
|
||||
}
|
||||
user = x509AuthoritiesPopulator.getUserDetails(clientCertificate);
|
||||
userCache.putUserInCache(clientCertificate, user);
|
||||
}
|
||||
|
||||
X509AuthenticationToken result = new X509AuthenticationToken(user, clientCertificate, user.getAuthorities());
|
||||
|
||||
result.setDetails(authentication.getDetails());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
|
||||
public void setX509AuthoritiesPopulator(X509AuthoritiesPopulator x509AuthoritiesPopulator) {
|
||||
this.x509AuthoritiesPopulator = x509AuthoritiesPopulator;
|
||||
}
|
||||
|
||||
public void setX509UserCache(X509UserCache cache) {
|
||||
this.userCache = cache;
|
||||
}
|
||||
|
||||
public boolean supports(Class authentication) {
|
||||
return X509AuthenticationToken.class.isAssignableFrom(authentication);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.x509;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
|
||||
/**
|
||||
* <code>Authentication</code> implementation for X.509 client-certificate authentication.
|
||||
* <p>Migrated from Spring Security 2 since it has been removed in Spring Security 3.</p>
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class X509AuthenticationToken extends AbstractAuthenticationToken {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private Object principal;
|
||||
private X509Certificate credentials;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Used for an authentication request. The {@link org.springframework.security.core.Authentication#isAuthenticated()} will return
|
||||
* <code>false</code>.
|
||||
*
|
||||
* @param credentials the certificate
|
||||
*/
|
||||
public X509AuthenticationToken(X509Certificate credentials) {
|
||||
super(null);
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for an authentication response object. The {@link org.springframework.security.core.Authentication#isAuthenticated()}
|
||||
* will return <code>true</code>.
|
||||
*
|
||||
* @param principal the principal, which is generally a
|
||||
* <code>UserDetails</code>
|
||||
* @param credentials the certificate
|
||||
* @param authorities the authorities
|
||||
*/
|
||||
public X509AuthenticationToken(Object principal, X509Certificate credentials, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(authorities);
|
||||
this.principal = principal;
|
||||
this.credentials = credentials;
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Object getCredentials() {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
public Object getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.x509;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
|
||||
/**
|
||||
* Populates the <code>UserDetails</code> associated with the X.509
|
||||
* certificate presented by a client.
|
||||
* <p>
|
||||
* Although the certificate will already have been validated by the web container,
|
||||
* implementations may choose to perform additional application-specific checks on
|
||||
* the certificate content here. If an implementation chooses to reject the certificate,
|
||||
* it should throw a {@link org.springframework.security.authentication.BadCredentialsException}.
|
||||
* </p>
|
||||
* <p>Migrated from Spring Security 2 since it has been removed in Spring Security 3.</p>
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public interface X509AuthoritiesPopulator {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Obtains the granted authorities for the specified user.<p>May throw any
|
||||
* <code>AuthenticationException</code> or return <code>null</code> if the authorities are unavailable.</p>
|
||||
*
|
||||
* @param userCertificate the X.509 certificate supplied
|
||||
*
|
||||
* @return the details of the indicated user (at minimum the granted authorities and the username)
|
||||
*
|
||||
* @throws AuthenticationException if the user details are not available or the certificate isn't valid for the
|
||||
* application's purpose.
|
||||
*/
|
||||
UserDetails getUserDetails(X509Certificate userCertificate)
|
||||
throws AuthenticationException;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.x509.cache;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import net.sf.ehcache.CacheException;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Element;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Caches <code>User</code> objects using a Spring IoC defined <a
|
||||
* href="http://ehcache.sourceforge.net">EHCACHE</a>.
|
||||
* <p>Migrated from Spring Security 2 since it has been removed in Spring Security 3.</p>
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class EhCacheBasedX509UserCache implements X509UserCache, InitializingBean {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(EhCacheBasedX509UserCache.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private Ehcache cache;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(cache, "cache is mandatory");
|
||||
}
|
||||
|
||||
public UserDetails getUserFromCache(X509Certificate userCert) {
|
||||
Element element = null;
|
||||
|
||||
try {
|
||||
element = cache.get(userCert);
|
||||
} catch (CacheException cacheException) {
|
||||
throw new DataRetrievalFailureException("Cache failure: " + cacheException.getMessage());
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
String subjectDN = "unknown";
|
||||
|
||||
if ((userCert != null) && (userCert.getSubjectDN() != null)) {
|
||||
subjectDN = userCert.getSubjectDN().toString();
|
||||
}
|
||||
|
||||
logger.debug("X.509 Cache hit. SubjectDN: " + subjectDN);
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
return null;
|
||||
} else {
|
||||
return (UserDetails) element.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
public void putUserInCache(X509Certificate userCert, UserDetails user) {
|
||||
Element element = new Element(userCert, user);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cache put: " + userCert.getSubjectDN());
|
||||
}
|
||||
|
||||
cache.put(element);
|
||||
}
|
||||
|
||||
public void removeUserFromCache(X509Certificate userCert) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cache remove: " + userCert.getSubjectDN());
|
||||
}
|
||||
|
||||
cache.remove(userCert);
|
||||
}
|
||||
|
||||
public void setCache(Ehcache cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.x509.cache;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
|
||||
/**
|
||||
* "Cache" that doesn't do any caching.
|
||||
* <p>Migrated from Spring Security 2 since it has been removed in Spring Security 3.</p>
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class NullX509UserCache implements X509UserCache {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public UserDetails getUserFromCache(X509Certificate certificate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void putUserInCache(X509Certificate certificate, UserDetails user) {}
|
||||
|
||||
public void removeUserFromCache(X509Certificate certificate) {}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.x509.cache;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
|
||||
/**
|
||||
* Provides a cache of {@link UserDetails} objects for the
|
||||
* {@link org.springframework.ws.soap.security.x509.X509AuthenticationProvider}.
|
||||
* <p>
|
||||
* Similar in function to the {@link org.springframework.security.core.userdetails.UserCache}
|
||||
* used by the Dao provider, but the cache is keyed with the user's certificate
|
||||
* rather than the user name.
|
||||
* </p>
|
||||
* <p>Migrated from Spring Security 2 since it has been removed in Spring Security 3.</p>
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public interface X509UserCache {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
UserDetails getUserFromCache(X509Certificate userCertificate);
|
||||
|
||||
void putUserInCache(X509Certificate key, UserDetails user);
|
||||
|
||||
void removeUserFromCache(X509Certificate key);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* 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.x509.populator;
|
||||
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
|
||||
import org.springframework.ws.soap.security.x509.X509AuthoritiesPopulator;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
/**
|
||||
* Populates the X509 authorities via an {@link org.springframework.security.core.userdetails.UserDetailsService}.
|
||||
* <p>Migrated from Spring Security 2 since it has been removed in Spring Security 3.</p>
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id: DaoX509AuthoritiesPopulator.java 2544 2008-01-29 11:50:33Z luke_t $
|
||||
*/
|
||||
public class DaoX509AuthoritiesPopulator implements X509AuthoritiesPopulator, InitializingBean, MessageSourceAware {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DaoX509AuthoritiesPopulator.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
private Pattern subjectDNPattern;
|
||||
private String subjectDNRegex = "CN=(.*?),";
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(userDetailsService, "An authenticationDao must be set");
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
|
||||
subjectDNPattern = Pattern.compile(subjectDNRegex, Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
|
||||
public UserDetails getUserDetails(X509Certificate clientCert) throws AuthenticationException {
|
||||
String subjectDN = clientCert.getSubjectDN().getName();
|
||||
|
||||
Matcher matcher = subjectDNPattern.matcher(subjectDN);
|
||||
|
||||
if (!matcher.find()) {
|
||||
throw new BadCredentialsException(messages.getMessage("DaoX509AuthoritiesPopulator.noMatching",
|
||||
new Object[] {subjectDN}, "No matching pattern was found in subjectDN: {0}"));
|
||||
}
|
||||
|
||||
if (matcher.groupCount() != 1) {
|
||||
throw new IllegalArgumentException("Regular expression must contain a single group ");
|
||||
}
|
||||
|
||||
String userName = matcher.group(1);
|
||||
|
||||
UserDetails user = this.userDetailsService.loadUserByUsername(userName);
|
||||
|
||||
if (user == null) {
|
||||
throw new AuthenticationServiceException(
|
||||
"UserDetailsService returned null, which is an interface contract violation");
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the regular expression which will by used to extract the user name from the certificate's Subject
|
||||
* DN.
|
||||
* <p>It should contain a single group; for example the default expression "CN=(.?)," matches the common
|
||||
* name field. So "CN=Jimi Hendrix, OU=..." will give a user name of "Jimi Hendrix".</p>
|
||||
* <p>The matches are case insensitive. So "emailAddress=(.?)," will match "EMAILADDRESS=jimi@hendrix.org,
|
||||
* CN=..." giving a user name "jimi@hendrix.org"</p>
|
||||
*
|
||||
* @param subjectDNRegex the regular expression to find in the subject
|
||||
*/
|
||||
public void setSubjectDNRegex(String subjectDNRegex) {
|
||||
this.subjectDNRegex = subjectDNRegex;
|
||||
}
|
||||
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.springframework.ws.soap.security.xwss;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.springframework.ws.soap.security.WsSecurityFaultException;
|
||||
|
||||
/**
|
||||
* XWSS-specific version of the {@link WsSecurityFaultException}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public class XwsSecurityFaultException extends WsSecurityFaultException {
|
||||
|
||||
public XwsSecurityFaultException(QName faultCode, String faultString, String faultActor) {
|
||||
super(faultCode, faultString, faultActor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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.xwss;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Hashtable;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.xml.soap.SOAPMessage;
|
||||
|
||||
import com.sun.xml.wss.ProcessingContext;
|
||||
import com.sun.xml.wss.XWSSProcessor;
|
||||
import com.sun.xml.wss.XWSSProcessorFactory;
|
||||
import com.sun.xml.wss.XWSSecurityException;
|
||||
import com.sun.xml.wss.impl.WssSoapFaultException;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
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.callback.CleanupCallback;
|
||||
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
|
||||
* WS-Security implementation is part of the Java Web Services Developer Pack (Java WSDP).
|
||||
* <p/>
|
||||
* This interceptor needs a <code>CallbackHandler</code> to operate. This handler is used to retrieve certificates,
|
||||
* private keys, validate user credentials, etc. Refer to the XWSS Javadoc to learn more about the specific
|
||||
* <code>Callback</code>s fired by XWSS. You can also set multiple handlers, each of which will be used in turn.
|
||||
* <p/>
|
||||
* Additionally, you must define a XWSS policy file by setting <code>policyConfiguration</code> property. The format of
|
||||
* the policy file is documented in the <a href="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp529900">Java
|
||||
* Web Services Tutorial</a>.
|
||||
* <p/>
|
||||
* <b>Note</b> that this interceptor depends on SAAJ, and thus requires <code>SaajSoapMessage</code>s to operate. This
|
||||
* means that you must use a <code>SaajSoapMessageFactory</code> to create the SOAP messages.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #setCallbackHandler(javax.security.auth.callback.CallbackHandler)
|
||||
* @see #setPolicyConfiguration(org.springframework.core.io.Resource)
|
||||
* @see com.sun.xml.wss.impl.callback.XWSSCallback
|
||||
* @see org.springframework.ws.soap.saaj.SaajSoapMessageFactory
|
||||
* @see <a href="https://xwss.dev.java.net/">XWSS</a>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class XwsSecurityInterceptor extends AbstractWsSecurityInterceptor implements InitializingBean {
|
||||
|
||||
private XWSSProcessor processor;
|
||||
|
||||
private CallbackHandler callbackHandler;
|
||||
|
||||
private Resource policyConfiguration;
|
||||
|
||||
/**
|
||||
* Sets the handler to resolve XWSS callbacks. Setting either this propery, or <code>callbackHandlers</code>, is
|
||||
* required.
|
||||
*
|
||||
* @see com.sun.xml.wss.impl.callback.XWSSCallback
|
||||
* @see #setCallbackHandlers(javax.security.auth.callback.CallbackHandler[])
|
||||
*/
|
||||
public void setCallbackHandler(CallbackHandler callbackHandler) {
|
||||
this.callbackHandler = callbackHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the handlers to resolve XWSS callbacks. Setting either this propery, or <code>callbackHandlers</code>, is
|
||||
* required.
|
||||
*
|
||||
* @see com.sun.xml.wss.impl.callback.XWSSCallback
|
||||
* @see #setCallbackHandler(javax.security.auth.callback.CallbackHandler)
|
||||
*/
|
||||
public void setCallbackHandlers(CallbackHandler[] callbackHandler) {
|
||||
this.callbackHandler = new XwssCallbackHandlerChain(callbackHandler);
|
||||
}
|
||||
|
||||
/** Sets the policy configuration to use for XWSS. Required. */
|
||||
public void setPolicyConfiguration(Resource policyConfiguration) {
|
||||
this.policyConfiguration = policyConfiguration;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(policyConfiguration, "policyConfiguration is required");
|
||||
Assert.isTrue(policyConfiguration.exists(), "policyConfiguration [" + policyConfiguration + "] does not exist");
|
||||
Assert.notNull(callbackHandler, "callbackHandler is required");
|
||||
XWSSProcessorFactory processorFactory = XWSSProcessorFactory.newInstance();
|
||||
InputStream is = null;
|
||||
try {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Loading policy configuration from from '" + policyConfiguration + "'");
|
||||
}
|
||||
is = policyConfiguration.getInputStream();
|
||||
processor = processorFactory.createProcessorForSecurityConfiguration(is, callbackHandler);
|
||||
}
|
||||
finally {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Secures the given SoapMessage message in accordance with the defined security policy.
|
||||
*
|
||||
* @param soapMessage the message to be secured
|
||||
* @throws XwsSecuritySecurementException in case of errors
|
||||
* @throws IllegalArgumentException when soapMessage is not a <code>SaajSoapMessage</code>
|
||||
*/
|
||||
@Override
|
||||
protected void secureMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws XwsSecuritySecurementException {
|
||||
Assert.isTrue(soapMessage instanceof SaajSoapMessage, "XwsSecurityInterceptor requires a SaajSoapMessage. " +
|
||||
"Use a SaajSoapMessageFactory to create the SOAP messages.");
|
||||
SaajSoapMessage saajSoapMessage = (SaajSoapMessage) soapMessage;
|
||||
try {
|
||||
ProcessingContext context = processor.createProcessingContext(saajSoapMessage.getSaajMessage());
|
||||
SOAPMessage result = processor.secureOutboundMessage(context);
|
||||
saajSoapMessage.setSaajMessage(result);
|
||||
}
|
||||
catch (XWSSecurityException ex) {
|
||||
throw new XwsSecuritySecurementException(ex.getMessage(), ex);
|
||||
}
|
||||
catch (WssSoapFaultException ex) {
|
||||
throw new XwsSecurityFaultException(ex.getFaultCode(), ex.getFaultString(), ex.getFaultActor());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the given SoapMessage message in accordance with the defined security policy.
|
||||
*
|
||||
* @param soapMessage the message to be validated
|
||||
* @throws XwsSecurityValidationException in case of errors
|
||||
* @throws IllegalArgumentException when soapMessage is not a <code>SaajSoapMessage</code>
|
||||
*/
|
||||
@Override
|
||||
protected void validateMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws WsSecurityValidationException {
|
||||
Assert.isTrue(soapMessage instanceof SaajSoapMessage, "XwsSecurityInterceptor requires a SaajSoapMessage. " +
|
||||
"Use a SaajSoapMessageFactory to create the SOAP messages.");
|
||||
SaajSoapMessage saajSoapMessage = (SaajSoapMessage) soapMessage;
|
||||
try {
|
||||
ProcessingContext context = processor.createProcessingContext(saajSoapMessage.getSaajMessage());
|
||||
SOAPMessage result = processor.verifyInboundMessage(context);
|
||||
saajSoapMessage.setSaajMessage(result);
|
||||
}
|
||||
catch (XWSSecurityException ex) {
|
||||
throw new XwsSecurityValidationException(ex.getMessage(), ex);
|
||||
}
|
||||
catch (WssSoapFaultException ex) {
|
||||
throw new XwsSecurityFaultException(ex.getFaultCode(), ex.getFaultString(), ex.getFaultActor());
|
||||
}
|
||||
}
|
||||
|
||||
private SOAPMessage verifyInboundMessage(ProcessingContext context)
|
||||
throws XWSSecurityException {
|
||||
try {
|
||||
return processor.verifyInboundMessage(context);
|
||||
}
|
||||
catch (XWSSecurityException ex) {
|
||||
Throwable cause = ex.getCause();
|
||||
if (cause instanceof NullPointerException) {
|
||||
StackTraceElement[] stackTrace = cause.getStackTrace();
|
||||
if (stackTrace.length >= 1 &&
|
||||
Hashtable.class.getName().equals(stackTrace[0].getClassName())) {
|
||||
return verifyInboundMessage(context);
|
||||
}
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanUp() {
|
||||
if (callbackHandler != null) {
|
||||
try {
|
||||
CleanupCallback cleanupCallback = new CleanupCallback();
|
||||
callbackHandler.handle(new Callback[]{cleanupCallback});
|
||||
}
|
||||
catch (IOException ex) {
|
||||
logger.warn("Cleanup callback resulted in IOException", ex);
|
||||
}
|
||||
catch (UnsupportedCallbackException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.xwss;
|
||||
|
||||
import org.springframework.ws.soap.security.WsSecuritySecurementException;
|
||||
|
||||
/**
|
||||
* XWSS-specific version of the {@link WsSecuritySecurementException}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class XwsSecuritySecurementException extends WsSecuritySecurementException {
|
||||
|
||||
public XwsSecuritySecurementException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public XwsSecuritySecurementException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.xwss;
|
||||
|
||||
import org.springframework.ws.soap.security.WsSecurityValidationException;
|
||||
|
||||
/**
|
||||
* XWSS-specific version of the {@link WsSecurityValidationException}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class XwsSecurityValidationException extends WsSecurityValidationException {
|
||||
|
||||
public XwsSecurityValidationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public XwsSecurityValidationException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* 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.xwss.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
|
||||
import com.sun.xml.wss.impl.callback.DecryptionKeyCallback;
|
||||
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.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
|
||||
/**
|
||||
* Default callback handler that handles cryptographic callback. This handler determines the exact callback passed, and
|
||||
* calls a template method for it. By default, all template methods throw an <code>UnsupportedCallbackException</code>,
|
||||
* so you only need to override those you need.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class CryptographyCallbackHandler extends AbstractCallbackHandler {
|
||||
|
||||
@Override
|
||||
protected final void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
if (callback instanceof CertificateValidationCallback) {
|
||||
handleCertificateValidationCallback((CertificateValidationCallback) callback);
|
||||
}
|
||||
else if (callback instanceof DecryptionKeyCallback) {
|
||||
handleDecryptionKeyCallback((DecryptionKeyCallback) callback);
|
||||
}
|
||||
else if (callback instanceof EncryptionKeyCallback) {
|
||||
handleEncryptionKeyCallback((EncryptionKeyCallback) callback);
|
||||
}
|
||||
else if (callback instanceof SignatureKeyCallback) {
|
||||
handleSignatureKeyCallback((SignatureKeyCallback) callback);
|
||||
}
|
||||
else if (callback instanceof SignatureVerificationKeyCallback) {
|
||||
handleSignatureVerificationKeyCallback((SignatureVerificationKeyCallback) callback);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Certificate validation
|
||||
//
|
||||
|
||||
/**
|
||||
* Template method that handles <code>CertificateValidationCallback</code>s. Called from
|
||||
* <code>handleInternal()</code>. Default implementation throws an <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handleCertificateValidationCallback(CertificateValidationCallback callback)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
//
|
||||
// Decryption
|
||||
//
|
||||
|
||||
/**
|
||||
* Method that handles <code>DecryptionKeyCallback</code>s. Called from <code>handleInternal()</code>. Default
|
||||
* implementation delegates to specific handling methods.
|
||||
*
|
||||
* @see #handlePrivateKeyRequest(com.sun.xml.wss.impl.callback.DecryptionKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.DecryptionKeyCallback.PrivateKeyRequest)
|
||||
* @see #handleSymmetricKeyRequest(com.sun.xml.wss.impl.callback.DecryptionKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.DecryptionKeyCallback.SymmetricKeyRequest)
|
||||
*/
|
||||
protected final void handleDecryptionKeyCallback(DecryptionKeyCallback callback)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
if (callback.getRequest() instanceof DecryptionKeyCallback.PrivateKeyRequest) {
|
||||
handlePrivateKeyRequest(callback, (DecryptionKeyCallback.PrivateKeyRequest) callback.getRequest());
|
||||
}
|
||||
else if (callback.getRequest() instanceof DecryptionKeyCallback.SymmetricKeyRequest) {
|
||||
handleSymmetricKeyRequest(callback, (DecryptionKeyCallback.SymmetricKeyRequest) callback.getRequest());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that handles <code>DecryptionKeyCallback</code>s with <code>PrivateKeyRequest</code> . Called from
|
||||
* <code>handleDecryptionKeyCallback()</code>. Default implementation delegates to specific handling methods.
|
||||
*
|
||||
* @see #handlePublicKeyBasedPrivKeyCertRequest(com.sun.xml.wss.impl.callback.SignatureKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.SignatureKeyCallback.PublicKeyBasedPrivKeyCertRequest)
|
||||
* @see #handleX509CertificateBasedRequest(com.sun.xml.wss.impl.callback.DecryptionKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.DecryptionKeyCallback.X509CertificateBasedRequest)
|
||||
* @see #handleX509IssuerSerialBasedRequest(com.sun.xml.wss.impl.callback.DecryptionKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.DecryptionKeyCallback.X509IssuerSerialBasedRequest)
|
||||
* @see #handleX509SubjectKeyIdentifierBasedRequest(com.sun.xml.wss.impl.callback.DecryptionKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest)
|
||||
*/
|
||||
protected final void handlePrivateKeyRequest(DecryptionKeyCallback callback,
|
||||
DecryptionKeyCallback.PrivateKeyRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
if (request instanceof DecryptionKeyCallback.PublicKeyBasedPrivKeyRequest) {
|
||||
handlePublicKeyBasedPrivKeyRequest(callback, (DecryptionKeyCallback.PublicKeyBasedPrivKeyRequest) request);
|
||||
}
|
||||
else if (request instanceof DecryptionKeyCallback.X509CertificateBasedRequest) {
|
||||
handleX509CertificateBasedRequest(callback, (DecryptionKeyCallback.X509CertificateBasedRequest) request);
|
||||
}
|
||||
else if (request instanceof DecryptionKeyCallback.X509IssuerSerialBasedRequest) {
|
||||
handleX509IssuerSerialBasedRequest(callback, (DecryptionKeyCallback.X509IssuerSerialBasedRequest) request);
|
||||
}
|
||||
else if (request instanceof DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest) {
|
||||
handleX509SubjectKeyIdentifierBasedRequest(callback,
|
||||
(DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest) request);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>DecryptionKeyCallback</code>s with <code>PublicKeyBasedPrivKeyRequest</code>s.
|
||||
* Called from <code>handlePrivateKeyRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handlePublicKeyBasedPrivKeyRequest(DecryptionKeyCallback callback,
|
||||
DecryptionKeyCallback.PublicKeyBasedPrivKeyRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>DecryptionKeyCallback</code>s with <code>X509CertificateBasedRequest</code>s.
|
||||
* Called from <code>handlePrivateKeyRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handleX509CertificateBasedRequest(DecryptionKeyCallback callback,
|
||||
DecryptionKeyCallback.X509CertificateBasedRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>DecryptionKeyCallback</code>s with <code>X509IssuerSerialBasedRequest</code>s.
|
||||
* Called from <code>handlePrivateKeyRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handleX509IssuerSerialBasedRequest(DecryptionKeyCallback callback,
|
||||
DecryptionKeyCallback.X509IssuerSerialBasedRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>DecryptionKeyCallback</code>s with <code>X509SubjectKeyIdentifierBasedRequest</code>s.
|
||||
* Called from <code>handlePrivateKeyRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handleX509SubjectKeyIdentifierBasedRequest(DecryptionKeyCallback callback,
|
||||
DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that handles <code>DecryptionKeyCallback</code>s with <code>SymmetricKeyRequest</code> . Called from
|
||||
* <code>handleDecryptionKeyCallback()</code>. Default implementation delegates to specific handling methods.
|
||||
*
|
||||
* @see #handleAliasSymmetricKeyRequest(com.sun.xml.wss.impl.callback.DecryptionKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.DecryptionKeyCallback.AliasSymmetricKeyRequest)
|
||||
*/
|
||||
protected final void handleSymmetricKeyRequest(DecryptionKeyCallback callback,
|
||||
DecryptionKeyCallback.SymmetricKeyRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
if (request instanceof DecryptionKeyCallback.AliasSymmetricKeyRequest) {
|
||||
DecryptionKeyCallback.AliasSymmetricKeyRequest aliasSymmetricKeyRequest =
|
||||
(DecryptionKeyCallback.AliasSymmetricKeyRequest) request;
|
||||
handleAliasSymmetricKeyRequest(callback, aliasSymmetricKeyRequest);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>DecryptionKeyCallback</code>s with <code>AliasSymmetricKeyRequest</code>s.
|
||||
* Called from <code>handleSymmetricKeyRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handleAliasSymmetricKeyRequest(DecryptionKeyCallback callback,
|
||||
DecryptionKeyCallback.AliasSymmetricKeyRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
//
|
||||
// Encryption
|
||||
//
|
||||
|
||||
/**
|
||||
* Method that handles <code>EncryptionKeyCallback</code>s. Called from <code>handleInternal()</code>. Default
|
||||
* implementation delegates to specific handling methods.
|
||||
*
|
||||
* @see #handleSymmetricKeyRequest(com.sun.xml.wss.impl.callback.EncryptionKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.EncryptionKeyCallback.SymmetricKeyRequest)
|
||||
* @see #handleX509CertificateRequest(com.sun.xml.wss.impl.callback.EncryptionKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.EncryptionKeyCallback.X509CertificateRequest)
|
||||
*/
|
||||
protected final void handleEncryptionKeyCallback(EncryptionKeyCallback callback)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
if (callback.getRequest() instanceof EncryptionKeyCallback.SymmetricKeyRequest) {
|
||||
handleSymmetricKeyRequest(callback, (EncryptionKeyCallback.SymmetricKeyRequest) callback.getRequest());
|
||||
}
|
||||
else if (callback.getRequest() instanceof EncryptionKeyCallback.X509CertificateRequest) {
|
||||
handleX509CertificateRequest(callback,
|
||||
(EncryptionKeyCallback.X509CertificateRequest) callback.getRequest());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that handles <code>EncryptionKeyCallback</code>s with <code>SymmetricKeyRequest</code> . Called from
|
||||
* <code>handleEncryptionKeyCallback()</code>. Default implementation delegates to specific handling methods.
|
||||
*
|
||||
* @see #handleAliasSymmetricKeyRequest(com.sun.xml.wss.impl.callback.EncryptionKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.EncryptionKeyCallback.AliasSymmetricKeyRequest)
|
||||
*/
|
||||
protected final void handleSymmetricKeyRequest(EncryptionKeyCallback callback,
|
||||
EncryptionKeyCallback.SymmetricKeyRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
if (request instanceof EncryptionKeyCallback.AliasSymmetricKeyRequest) {
|
||||
handleAliasSymmetricKeyRequest(callback, (EncryptionKeyCallback.AliasSymmetricKeyRequest) request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>EncryptionKeyCallback</code>s with <code>AliasSymmetricKeyRequest</code>s.
|
||||
* Called from <code>handleSymmetricKeyRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handleAliasSymmetricKeyRequest(EncryptionKeyCallback callback,
|
||||
EncryptionKeyCallback.AliasSymmetricKeyRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that handles <code>EncryptionKeyCallback</code>s with <code>X509CertificateRequest</code> . Called from
|
||||
* <code>handleEncryptionKeyCallback()</code>. Default implementation delegates to specific handling methods.
|
||||
*
|
||||
* @see #handleAliasX509CertificateRequest(com.sun.xml.wss.impl.callback.EncryptionKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.EncryptionKeyCallback.AliasX509CertificateRequest)
|
||||
* @see #handleDefaultX509CertificateRequest(com.sun.xml.wss.impl.callback.EncryptionKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.EncryptionKeyCallback.DefaultX509CertificateRequest)
|
||||
* @see #handlePublicKeyBasedRequest(com.sun.xml.wss.impl.callback.EncryptionKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.EncryptionKeyCallback.PublicKeyBasedRequest)
|
||||
*/
|
||||
protected final void handleX509CertificateRequest(EncryptionKeyCallback callback,
|
||||
EncryptionKeyCallback.X509CertificateRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
if (request instanceof EncryptionKeyCallback.AliasX509CertificateRequest) {
|
||||
handleAliasX509CertificateRequest(callback, (EncryptionKeyCallback.AliasX509CertificateRequest) request);
|
||||
}
|
||||
else if (request instanceof EncryptionKeyCallback.DefaultX509CertificateRequest) {
|
||||
handleDefaultX509CertificateRequest(callback,
|
||||
(EncryptionKeyCallback.DefaultX509CertificateRequest) request);
|
||||
}
|
||||
else if (request instanceof EncryptionKeyCallback.PublicKeyBasedRequest) {
|
||||
handlePublicKeyBasedRequest(callback, (EncryptionKeyCallback.PublicKeyBasedRequest) request);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>EncryptionKeyCallback</code>s with <code>AliasX509CertificateRequest</code>s.
|
||||
* Called from <code>handleX509CertificateRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handleAliasX509CertificateRequest(EncryptionKeyCallback callback,
|
||||
EncryptionKeyCallback.AliasX509CertificateRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>EncryptionKeyCallback</code>s with <code>DefaultX509CertificateRequest</code>s.
|
||||
* Called from <code>handleX509CertificateRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handleDefaultX509CertificateRequest(EncryptionKeyCallback callback,
|
||||
EncryptionKeyCallback.DefaultX509CertificateRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>EncryptionKeyCallback</code>s with <code>PublicKeyBasedRequest</code>s. Called
|
||||
* from <code>handleX509CertificateRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handlePublicKeyBasedRequest(EncryptionKeyCallback callback,
|
||||
EncryptionKeyCallback.PublicKeyBasedRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
//
|
||||
// Signing
|
||||
//
|
||||
|
||||
/**
|
||||
* Method that handles <code>SignatureKeyCallback</code>s. Called from <code>handleInternal()</code>. Default
|
||||
* implementation delegates to specific handling methods.
|
||||
*
|
||||
* @see #handlePrivKeyCertRequest(com.sun.xml.wss.impl.callback.SignatureKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.SignatureKeyCallback.PrivKeyCertRequest)
|
||||
*/
|
||||
protected final void handleSignatureKeyCallback(SignatureKeyCallback callback)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
if (callback.getRequest() instanceof SignatureKeyCallback.PrivKeyCertRequest) {
|
||||
handlePrivKeyCertRequest(callback, (SignatureKeyCallback.PrivKeyCertRequest) callback.getRequest());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that handles <code>SignatureKeyCallback</code>s with <code>PrivKeyCertRequest</code>s. Called from
|
||||
* <code>handleSignatureKeyCallback()</code>. Default implementation delegates to specific handling methods.
|
||||
*
|
||||
* @see #handleDefaultPrivKeyCertRequest(com.sun.xml.wss.impl.callback.SignatureKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.SignatureKeyCallback.DefaultPrivKeyCertRequest)
|
||||
* @see #handleAliasPrivKeyCertRequest(com.sun.xml.wss.impl.callback.SignatureKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.SignatureKeyCallback.AliasPrivKeyCertRequest)
|
||||
* @see #handlePublicKeyBasedPrivKeyCertRequest(com.sun.xml.wss.impl.callback.SignatureKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.SignatureKeyCallback.PublicKeyBasedPrivKeyCertRequest)
|
||||
*/
|
||||
protected final void handlePrivKeyCertRequest(SignatureKeyCallback cb,
|
||||
SignatureKeyCallback.PrivKeyCertRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
if (request instanceof SignatureKeyCallback.DefaultPrivKeyCertRequest) {
|
||||
handleDefaultPrivKeyCertRequest(cb, (SignatureKeyCallback.DefaultPrivKeyCertRequest) request);
|
||||
}
|
||||
else if (cb.getRequest() instanceof SignatureKeyCallback.AliasPrivKeyCertRequest) {
|
||||
handleAliasPrivKeyCertRequest(cb, (SignatureKeyCallback.AliasPrivKeyCertRequest) request);
|
||||
}
|
||||
else if (cb.getRequest() instanceof SignatureKeyCallback.PublicKeyBasedPrivKeyCertRequest) {
|
||||
handlePublicKeyBasedPrivKeyCertRequest(cb, (SignatureKeyCallback.PublicKeyBasedPrivKeyCertRequest) request);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(cb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>SignatureKeyCallback</code>s with <code>DefaultPrivKeyCertRequest</code>s.
|
||||
* Called from <code>handlePrivKeyCertRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handleDefaultPrivKeyCertRequest(SignatureKeyCallback callback,
|
||||
SignatureKeyCallback.DefaultPrivKeyCertRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>SignatureKeyCallback</code>s with <code>AliasPrivKeyCertRequest</code>s.
|
||||
* Called from <code>handlePrivKeyCertRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handleAliasPrivKeyCertRequest(SignatureKeyCallback callback,
|
||||
SignatureKeyCallback.AliasPrivKeyCertRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>SignatureKeyCallback</code>s with <code>PublicKeyBasedPrivKeyCertRequest</code>s.
|
||||
* Called from <code>handlePrivKeyCertRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handlePublicKeyBasedPrivKeyCertRequest(SignatureKeyCallback callback,
|
||||
SignatureKeyCallback.PublicKeyBasedPrivKeyCertRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
//
|
||||
// Signature verification
|
||||
//
|
||||
|
||||
/**
|
||||
* Method that handles <code>SignatureVerificationKeyCallback</code>s. Called from <code>handleInternal()</code>.
|
||||
* Default implementation delegates to specific handling methods.
|
||||
*
|
||||
* @see #handleX509CertificateRequest(com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback.X509CertificateRequest)
|
||||
*/
|
||||
protected final void handleSignatureVerificationKeyCallback(SignatureVerificationKeyCallback callback)
|
||||
throws UnsupportedCallbackException, IOException {
|
||||
if (callback.getRequest() instanceof SignatureVerificationKeyCallback.X509CertificateRequest) {
|
||||
handleX509CertificateRequest(callback,
|
||||
(SignatureVerificationKeyCallback.X509CertificateRequest) callback.getRequest());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that handles <code>SignatureVerificationKeyCallback</code>s with <code>X509CertificateRequest</code>s.
|
||||
* Called from <code>handleSignatureVerificationKeyCallback()</code>. Default implementation delegates to specific
|
||||
* handling methods.
|
||||
*
|
||||
* @see #handlePublicKeyBasedRequest(com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback.PublicKeyBasedRequest)
|
||||
* @see #handleX509IssuerSerialBasedRequest(com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest)
|
||||
* @see #handleX509SubjectKeyIdentifierBasedRequest(com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback,
|
||||
* com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest)
|
||||
*/
|
||||
protected final void handleX509CertificateRequest(SignatureVerificationKeyCallback callback,
|
||||
SignatureVerificationKeyCallback.X509CertificateRequest request)
|
||||
throws UnsupportedCallbackException, IOException {
|
||||
if (request instanceof SignatureVerificationKeyCallback.PublicKeyBasedRequest) {
|
||||
handlePublicKeyBasedRequest(callback, (SignatureVerificationKeyCallback.PublicKeyBasedRequest) request);
|
||||
}
|
||||
else if (request instanceof SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest) {
|
||||
handleX509IssuerSerialBasedRequest(callback,
|
||||
(SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest) request);
|
||||
}
|
||||
else if (request instanceof SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest) {
|
||||
handleX509SubjectKeyIdentifierBasedRequest(callback,
|
||||
(SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest) request);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>SignatureKeyCallback</code>s with <code>PublicKeyBasedPrivKeyCertRequest</code>s.
|
||||
* Called from <code>handlePrivKeyCertRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handleX509SubjectKeyIdentifierBasedRequest(SignatureVerificationKeyCallback callback,
|
||||
SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>SignatureKeyCallback</code>s with <code>X509IssuerSerialBasedRequest</code>s.
|
||||
* Called from <code>handlePrivKeyCertRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handleX509IssuerSerialBasedRequest(SignatureVerificationKeyCallback callback,
|
||||
SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that handles <code>SignatureKeyCallback</code>s with <code>PublicKeyBasedRequest</code>s. Called
|
||||
* from <code>handlePrivKeyCertRequest()</code>. Default implementation throws an
|
||||
* <code>UnsupportedCallbackException</code>.
|
||||
*/
|
||||
protected void handlePublicKeyBasedRequest(SignatureVerificationKeyCallback callback,
|
||||
SignatureVerificationKeyCallback.PublicKeyBasedRequest request)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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.xwss.callback;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.TimestampValidationCallback;
|
||||
|
||||
/**
|
||||
* A default implementation of a <code>TimestampValidationCallback.TimestampValidator</code>. Based on a version found
|
||||
* in the JWSDP samples.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class DefaultTimestampValidator implements TimestampValidationCallback.TimestampValidator {
|
||||
|
||||
public void validate(TimestampValidationCallback.Request request)
|
||||
throws TimestampValidationCallback.TimestampValidationException {
|
||||
if (request instanceof TimestampValidationCallback.UTCTimestampRequest) {
|
||||
TimestampValidationCallback.UTCTimestampRequest utcRequest =
|
||||
(TimestampValidationCallback.UTCTimestampRequest) request;
|
||||
Date created = parseDate(utcRequest.getCreated());
|
||||
|
||||
validateCreationTime(created, utcRequest.getMaxClockSkew(), utcRequest.getTimestampFreshnessLimit());
|
||||
|
||||
if (utcRequest.getExpired() != null) {
|
||||
Date expired = parseDate(utcRequest.getExpired());
|
||||
validateExpirationTime(expired, utcRequest.getMaxClockSkew());
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new TimestampValidationCallback.TimestampValidationException("Unsupport request: [" + request + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private Date getFreshnessAndSkewAdjustedDate(long maxClockSkew, long timestampFreshnessLimit) {
|
||||
Calendar c = new GregorianCalendar();
|
||||
long offset = c.get(Calendar.ZONE_OFFSET);
|
||||
if (c.getTimeZone().inDaylightTime(c.getTime())) {
|
||||
offset += c.getTimeZone().getDSTSavings();
|
||||
}
|
||||
long beforeTime = c.getTimeInMillis();
|
||||
long currentTime = beforeTime - offset;
|
||||
|
||||
long adjustedTime = currentTime - maxClockSkew - timestampFreshnessLimit;
|
||||
c.setTimeInMillis(adjustedTime);
|
||||
|
||||
return c.getTime();
|
||||
}
|
||||
|
||||
private Date getGMTDateWithSkewAdjusted(Calendar calendar, long maxClockSkew, boolean addSkew) {
|
||||
long offset = calendar.get(Calendar.ZONE_OFFSET);
|
||||
if (calendar.getTimeZone().inDaylightTime(calendar.getTime())) {
|
||||
offset += calendar.getTimeZone().getDSTSavings();
|
||||
}
|
||||
long beforeTime = calendar.getTimeInMillis();
|
||||
long currentTime = beforeTime - offset;
|
||||
|
||||
if (addSkew) {
|
||||
currentTime = currentTime + maxClockSkew;
|
||||
}
|
||||
else {
|
||||
currentTime = currentTime - maxClockSkew;
|
||||
}
|
||||
|
||||
calendar.setTimeInMillis(currentTime);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
private Date parseDate(String date) throws TimestampValidationCallback.TimestampValidationException {
|
||||
SimpleDateFormat calendarFormatter1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
SimpleDateFormat calendarFormatter2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'SSS'Z'");
|
||||
|
||||
try {
|
||||
try {
|
||||
return calendarFormatter1.parse(date);
|
||||
}
|
||||
catch (ParseException ignored) {
|
||||
return calendarFormatter2.parse(date);
|
||||
}
|
||||
}
|
||||
catch (ParseException ex) {
|
||||
throw new TimestampValidationCallback.TimestampValidationException("Could not parse request date: " + date,
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateCreationTime(Date created, long maxClockSkew, long timestampFreshnessLimit)
|
||||
throws TimestampValidationCallback.TimestampValidationException {
|
||||
Date current = getFreshnessAndSkewAdjustedDate(maxClockSkew, timestampFreshnessLimit);
|
||||
|
||||
if (created.before(current)) {
|
||||
throw new TimestampValidationCallback.TimestampValidationException(
|
||||
"The creation time is older than currenttime - timestamp-freshness-limit - max-clock-skew");
|
||||
}
|
||||
|
||||
Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(), maxClockSkew, true);
|
||||
if (currentTime.before(created)) {
|
||||
throw new TimestampValidationCallback.TimestampValidationException(
|
||||
"The creation time is ahead of the current time.");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateExpirationTime(Date expires, long maxClockSkew)
|
||||
throws TimestampValidationCallback.TimestampValidationException {
|
||||
Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(), maxClockSkew, false);
|
||||
if (expires.before(currentTime)) {
|
||||
throw new TimestampValidationCallback.TimestampValidationException(
|
||||
"The current time is ahead of the expiration time in Timestamp");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,705 @@
|
||||
/*
|
||||
* 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.xwss.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.CertPathBuilder;
|
||||
import java.security.cert.CertPathBuilderException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateExpiredException;
|
||||
import java.security.cert.CertificateNotYetValidException;
|
||||
import java.security.cert.PKIXBuilderParameters;
|
||||
import java.security.cert.X509CertSelector;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.ws.soap.security.support.KeyStoreUtils;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
|
||||
import com.sun.xml.wss.impl.callback.DecryptionKeyCallback;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p/>
|
||||
* This handler requires one or more key stores to be set. You can configure them in your application context by using a
|
||||
* <code>KeyStoreFactoryBean</code>. The exact stores to be set depends on the cryptographic operations that are to be
|
||||
* performed by this handler. The table underneath show the key store to be used for each operation: <table border="1">
|
||||
* <tr> <td><strong>Cryptographic operation</strong></td> <td><strong>Key store used</strong></td> </tr> <tr>
|
||||
* <td>Certificate validation</td> <td>first <code>keyStore</code>, then <code>trustStore</code></td> </tr> <tr>
|
||||
* <td>Decryption based on private key</td> <td><code>keyStore</code></td> </tr> <tr> <td>Decryption based on symmetric
|
||||
* key</td> <td><code>symmetricStore</code></td> </tr> <tr> <td>Encryption based on certificate</td>
|
||||
* <td><code>trustStore</code></td> </tr> <tr> <td>Encryption based on symmetric key</td>
|
||||
* <td><code>symmetricStore</code></td> </tr> <tr> <td>Signing</td> <td><code>keyStore</code></td> </tr> <tr>
|
||||
* <td>Signature verification</td> <td><code>trustStore</code></td> </tr> </table>
|
||||
* <p/>
|
||||
* <h3>Default key stores</h3> If the <code>symmetricStore</code> is not set, it will default to the
|
||||
* <code>keyStore</code>. If the key or trust store is not set, this handler will use the standard Java mechanism to
|
||||
* load or create it. See {@link #loadDefaultKeyStore()} and {@link #loadDefaultTrustStore()}.
|
||||
* <p/>
|
||||
* <h3>Examples</h3> For instance, if you want to use the <code>KeyStoreCallbackHandler</code> to validate incoming
|
||||
* certificates or signatures, you would use a trust store, like so:
|
||||
* <pre>
|
||||
* <bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
|
||||
* <property name="trustStore" ref="trustStore"/>
|
||||
* </bean>
|
||||
* <p/>
|
||||
* <bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
|
||||
* <property name="location" value="classpath:truststore.jks"/>
|
||||
* <property name="password" value="changeit"/>
|
||||
* </bean>
|
||||
* </pre>
|
||||
* If you want to use it to decrypt incoming certificates or sign outgoing messages, you would use a key store, like
|
||||
* so:
|
||||
* <pre>
|
||||
* <bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
|
||||
* <property name="keyStore" ref="keyStore"/>
|
||||
* <property name="privateKeyPassword" value="changeit"/>
|
||||
* </bean>
|
||||
* <p/>
|
||||
* <bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
|
||||
* <property name="location" value="classpath:keystore.jks"/>
|
||||
* <property name="password" value="changeit"/>
|
||||
* </bean>
|
||||
* </pre>
|
||||
* <p/>
|
||||
* <h3>Handled callbacks</h3> This class handles <code>CertificateValidationCallback</code>s,
|
||||
* <code>DecryptionKeyCallback</code>s, <code>EncryptionKeyCallback</code>s, <code>SignatureKeyCallback</code>s, and
|
||||
* <code>SignatureVerificationKeyCallback</code>s. It throws an <code>UnsupportedCallbackException</code> for others.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see KeyStore
|
||||
* @see org.springframework.ws.soap.security.support.KeyStoreFactoryBean
|
||||
* @see CertificateValidationCallback
|
||||
* @see DecryptionKeyCallback
|
||||
* @see EncryptionKeyCallback
|
||||
* @see SignatureKeyCallback
|
||||
* @see SignatureVerificationKeyCallback
|
||||
* @see <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager">The
|
||||
* standard Java trust store mechanism</a>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class KeyStoreCallbackHandler extends CryptographyCallbackHandler implements InitializingBean {
|
||||
|
||||
private static final String X_509_CERTIFICATE_TYPE = "X.509";
|
||||
|
||||
private static final String SUBJECT_KEY_IDENTIFIER_OID = "2.5.29.14";
|
||||
|
||||
private KeyStore keyStore;
|
||||
|
||||
private KeyStore symmetricStore;
|
||||
|
||||
private KeyStore trustStore;
|
||||
|
||||
private String defaultAlias;
|
||||
|
||||
private char[] privateKeyPassword;
|
||||
|
||||
private char[] symmetricKeyPassword;
|
||||
|
||||
private static X509Certificate getCertificate(String alias, KeyStore store) throws IOException {
|
||||
try {
|
||||
return (X509Certificate) store.getCertificate(alias);
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static X509Certificate getCertificate(PublicKey pk, KeyStore store) throws IOException {
|
||||
try {
|
||||
Enumeration<String> aliases = store.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
Certificate cert = store.getCertificate(alias);
|
||||
if (cert == null || !X_509_CERTIFICATE_TYPE.equals(cert.getType())) {
|
||||
continue;
|
||||
}
|
||||
X509Certificate x509Cert = (X509Certificate) cert;
|
||||
if (x509Cert.getPublicKey().equals(pk)) {
|
||||
return x509Cert;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Sets the key store alias for the default certificate and private key. */
|
||||
public void setDefaultAlias(String defaultAlias) {
|
||||
this.defaultAlias = defaultAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default key store. This property is required for decription based on private keys, and signing. If this
|
||||
* property is not set, a default key store is loaded.
|
||||
*
|
||||
* @see org.springframework.ws.soap.security.support.KeyStoreFactoryBean
|
||||
* @see #loadDefaultTrustStore()
|
||||
*/
|
||||
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.toCharArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key store used for encryption and decryption using symmetric keys. If this property is not set, it
|
||||
* defaults to the <code>keyStore</code> property.
|
||||
*
|
||||
* @see org.springframework.ws.soap.security.support.KeyStoreFactoryBean
|
||||
* @see #setKeyStore(java.security.KeyStore)
|
||||
*/
|
||||
public void setSymmetricStore(KeyStore symmetricStore) {
|
||||
this.symmetricStore = symmetricStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key store used for signature verifications and encryptions. If this property is not set, a default key
|
||||
* store will be loaded.
|
||||
*
|
||||
* @see org.springframework.ws.soap.security.support.KeyStoreFactoryBean
|
||||
* @see #loadDefaultTrustStore()
|
||||
*/
|
||||
public void setTrustStore(KeyStore trustStore) {
|
||||
this.trustStore = trustStore;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (keyStore == null) {
|
||||
loadDefaultKeyStore();
|
||||
}
|
||||
if (trustStore == null) {
|
||||
loadDefaultTrustStore();
|
||||
}
|
||||
if (symmetricStore == null) {
|
||||
symmetricStore = keyStore;
|
||||
}
|
||||
if (symmetricKeyPassword == null) {
|
||||
symmetricKeyPassword = privateKeyPassword;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handleAliasPrivKeyCertRequest(SignatureKeyCallback callback,
|
||||
SignatureKeyCallback.AliasPrivKeyCertRequest request)
|
||||
throws IOException {
|
||||
PrivateKey privateKey = getPrivateKey(request.getAlias());
|
||||
X509Certificate certificate = getCertificate(request.getAlias());
|
||||
request.setPrivateKey(privateKey);
|
||||
request.setX509Certificate(certificate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handleAliasSymmetricKeyRequest(DecryptionKeyCallback callback,
|
||||
DecryptionKeyCallback.AliasSymmetricKeyRequest request)
|
||||
throws IOException {
|
||||
SecretKey secretKey = getSymmetricKey(request.getAlias());
|
||||
request.setSymmetricKey(secretKey);
|
||||
}
|
||||
|
||||
//
|
||||
// Encryption
|
||||
//
|
||||
|
||||
@Override
|
||||
protected final void handleAliasSymmetricKeyRequest(EncryptionKeyCallback callback,
|
||||
EncryptionKeyCallback.AliasSymmetricKeyRequest request)
|
||||
throws IOException {
|
||||
SecretKey secretKey = getSymmetricKey(request.getAlias());
|
||||
request.setSymmetricKey(secretKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handleAliasX509CertificateRequest(EncryptionKeyCallback callback,
|
||||
EncryptionKeyCallback.AliasX509CertificateRequest request)
|
||||
throws IOException {
|
||||
X509Certificate certificate = getCertificateFromTrustStore(request.getAlias());
|
||||
request.setX509Certificate(certificate);
|
||||
}
|
||||
|
||||
//
|
||||
// Certificate validation
|
||||
//
|
||||
|
||||
@Override
|
||||
protected final void handleCertificateValidationCallback(CertificateValidationCallback callback) {
|
||||
callback.setValidator(new KeyStoreCertificateValidator());
|
||||
}
|
||||
|
||||
//
|
||||
// Signing
|
||||
//
|
||||
|
||||
@Override
|
||||
protected final void handleDefaultPrivKeyCertRequest(SignatureKeyCallback callback,
|
||||
SignatureKeyCallback.DefaultPrivKeyCertRequest request)
|
||||
throws IOException {
|
||||
PrivateKey privateKey = getPrivateKey(defaultAlias);
|
||||
X509Certificate certificate = getCertificate(defaultAlias);
|
||||
request.setPrivateKey(privateKey);
|
||||
request.setX509Certificate(certificate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handleDefaultX509CertificateRequest(EncryptionKeyCallback callback,
|
||||
EncryptionKeyCallback.DefaultX509CertificateRequest request)
|
||||
throws IOException {
|
||||
X509Certificate certificate = getCertificateFromTrustStore(defaultAlias);
|
||||
request.setX509Certificate(certificate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handlePublicKeyBasedPrivKeyCertRequest(SignatureKeyCallback callback,
|
||||
SignatureKeyCallback.PublicKeyBasedPrivKeyCertRequest request)
|
||||
throws IOException {
|
||||
PrivateKey privateKey = getPrivateKey(request.getPublicKey());
|
||||
X509Certificate certificate = getCertificate(request.getPublicKey());
|
||||
request.setPrivateKey(privateKey);
|
||||
request.setX509Certificate(certificate);
|
||||
}
|
||||
|
||||
//
|
||||
// Decryption
|
||||
//
|
||||
@Override
|
||||
protected final void handlePublicKeyBasedPrivKeyRequest(DecryptionKeyCallback callback,
|
||||
DecryptionKeyCallback.PublicKeyBasedPrivKeyRequest request)
|
||||
throws IOException {
|
||||
PrivateKey key = getPrivateKey(request.getPublicKey());
|
||||
request.setPrivateKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handlePublicKeyBasedRequest(EncryptionKeyCallback callback,
|
||||
EncryptionKeyCallback.PublicKeyBasedRequest request)
|
||||
throws IOException {
|
||||
X509Certificate certificate = getCertificateFromTrustStore(request.getPublicKey());
|
||||
request.setX509Certificate(certificate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handlePublicKeyBasedRequest(SignatureVerificationKeyCallback callback,
|
||||
SignatureVerificationKeyCallback.PublicKeyBasedRequest request)
|
||||
throws IOException {
|
||||
X509Certificate certificate = getCertificateFromTrustStore(request.getPublicKey());
|
||||
request.setX509Certificate(certificate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handleX509CertificateBasedRequest(DecryptionKeyCallback callback,
|
||||
DecryptionKeyCallback.X509CertificateBasedRequest request)
|
||||
throws IOException {
|
||||
PrivateKey privKey = getPrivateKey(request.getX509Certificate());
|
||||
request.setPrivateKey(privKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handleX509IssuerSerialBasedRequest(DecryptionKeyCallback callback,
|
||||
DecryptionKeyCallback.X509IssuerSerialBasedRequest request)
|
||||
throws IOException {
|
||||
PrivateKey key = getPrivateKey(request.getIssuerName(), request.getSerialNumber());
|
||||
request.setPrivateKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handleX509IssuerSerialBasedRequest(SignatureVerificationKeyCallback callback,
|
||||
SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest request)
|
||||
throws IOException {
|
||||
X509Certificate certificate = getCertificateFromTrustStore(request.getIssuerName(), request.getSerialNumber());
|
||||
request.setX509Certificate(certificate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handleX509SubjectKeyIdentifierBasedRequest(DecryptionKeyCallback callback,
|
||||
DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest request)
|
||||
throws IOException {
|
||||
PrivateKey key = getPrivateKey(request.getSubjectKeyIdentifier());
|
||||
request.setPrivateKey(key);
|
||||
}
|
||||
|
||||
//
|
||||
// Signature verification
|
||||
//
|
||||
|
||||
@Override
|
||||
protected final void handleX509SubjectKeyIdentifierBasedRequest(SignatureVerificationKeyCallback callback,
|
||||
SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest request)
|
||||
throws IOException {
|
||||
X509Certificate certificate = getCertificateFromTrustStore(request.getSubjectKeyIdentifier());
|
||||
request.setX509Certificate(certificate);
|
||||
}
|
||||
|
||||
// Certificate methods
|
||||
|
||||
protected X509Certificate getCertificate(String alias) throws IOException {
|
||||
return getCertificate(alias, keyStore);
|
||||
}
|
||||
|
||||
protected X509Certificate getCertificate(PublicKey pk) throws IOException {
|
||||
return getCertificate(pk, keyStore);
|
||||
}
|
||||
|
||||
protected X509Certificate getCertificateFromTrustStore(String alias) throws IOException {
|
||||
return getCertificate(alias, trustStore);
|
||||
}
|
||||
|
||||
protected X509Certificate getCertificateFromTrustStore(byte[] subjectKeyIdentifier) throws IOException {
|
||||
try {
|
||||
Enumeration<String> aliases = trustStore.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
Certificate cert = trustStore.getCertificate(alias);
|
||||
if (cert == null || !X_509_CERTIFICATE_TYPE.equals(cert.getType())) {
|
||||
continue;
|
||||
}
|
||||
X509Certificate x509Cert = (X509Certificate) cert;
|
||||
byte[] keyId = getSubjectKeyIdentifier(x509Cert);
|
||||
if (keyId == null) {
|
||||
// Cert does not contain a key identifier
|
||||
continue;
|
||||
}
|
||||
if (Arrays.equals(subjectKeyIdentifier, keyId)) {
|
||||
return x509Cert;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected X509Certificate getCertificateFromTrustStore(PublicKey pk) throws IOException {
|
||||
return getCertificate(pk, trustStore);
|
||||
}
|
||||
|
||||
protected X509Certificate getCertificateFromTrustStore(String issuerName, BigInteger serialNumber)
|
||||
throws IOException {
|
||||
try {
|
||||
Enumeration<String> aliases = trustStore.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
Certificate cert = trustStore.getCertificate(alias);
|
||||
if (cert == null || !X_509_CERTIFICATE_TYPE.equals(cert.getType())) {
|
||||
continue;
|
||||
}
|
||||
X509Certificate x509Cert = (X509Certificate) cert;
|
||||
String thisIssuerName = RFC2253Parser.normalize(x509Cert.getIssuerDN().getName());
|
||||
BigInteger thisSerialNumber = x509Cert.getSerialNumber();
|
||||
if (thisIssuerName.equals(issuerName) && thisSerialNumber.equals(serialNumber)) {
|
||||
return x509Cert;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Private Key methods
|
||||
|
||||
protected PrivateKey getPrivateKey(String alias) throws IOException {
|
||||
try {
|
||||
return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected PrivateKey getPrivateKey(PublicKey publicKey) throws IOException {
|
||||
try {
|
||||
Enumeration<String> aliases = keyStore.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
if (keyStore.isKeyEntry(alias)) {
|
||||
// Just returning the first one here
|
||||
return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected PrivateKey getPrivateKey(X509Certificate certificate) throws IOException {
|
||||
try {
|
||||
Enumeration<String> aliases = keyStore.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
if (!keyStore.isKeyEntry(alias)) {
|
||||
continue;
|
||||
}
|
||||
Certificate cert = keyStore.getCertificate(alias);
|
||||
if (cert != null && cert.equals(certificate)) {
|
||||
return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected PrivateKey getPrivateKey(byte[] keyIdentifier) throws IOException {
|
||||
try {
|
||||
Enumeration<String> aliases = keyStore.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
if (!keyStore.isKeyEntry(alias)) {
|
||||
continue;
|
||||
}
|
||||
Certificate cert = keyStore.getCertificate(alias);
|
||||
if (cert == null || !"X.509".equals(cert.getType())) {
|
||||
continue;
|
||||
}
|
||||
X509Certificate x509Cert = (X509Certificate) cert;
|
||||
byte[] keyId = getSubjectKeyIdentifier(x509Cert);
|
||||
if (keyId == null) {
|
||||
// Cert does not contain a key identifier
|
||||
continue;
|
||||
}
|
||||
if (Arrays.equals(keyIdentifier, keyId)) {
|
||||
return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected PrivateKey getPrivateKey(String issuerName, BigInteger serialNumber) throws IOException {
|
||||
try {
|
||||
Enumeration<String> aliases = keyStore.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
if (!keyStore.isKeyEntry(alias)) {
|
||||
continue;
|
||||
}
|
||||
Certificate cert = keyStore.getCertificate(alias);
|
||||
if (cert == null || !"X.509".equals(cert.getType())) {
|
||||
continue;
|
||||
}
|
||||
X509Certificate x509Cert = (X509Certificate) cert;
|
||||
String thisIssuerName = RFC2253Parser.normalize(x509Cert.getIssuerDN().getName());
|
||||
BigInteger thisSerialNumber = x509Cert.getSerialNumber();
|
||||
if (thisIssuerName.equals(issuerName) && thisSerialNumber.equals(serialNumber)) {
|
||||
return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Utility methods
|
||||
|
||||
protected final byte[] getSubjectKeyIdentifier(X509Certificate cert) {
|
||||
byte[] subjectKeyIdentifier = cert.getExtensionValue(SUBJECT_KEY_IDENTIFIER_OID);
|
||||
if (subjectKeyIdentifier == null) {
|
||||
return null;
|
||||
}
|
||||
byte[] dest = new byte[subjectKeyIdentifier.length - 4];
|
||||
System.arraycopy(subjectKeyIdentifier, 4, dest, 0, subjectKeyIdentifier.length - 4);
|
||||
return dest;
|
||||
}
|
||||
|
||||
//
|
||||
// Symmetric key methods
|
||||
//
|
||||
|
||||
protected SecretKey getSymmetricKey(String alias) throws IOException {
|
||||
try {
|
||||
return (SecretKey) symmetricStore.getKey(alias, symmetricKeyPassword);
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/** 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);
|
||||
}
|
||||
}
|
||||
|
||||
/** Loads a default trust store. Delegates to {@link KeyStoreUtils#loadDefaultTrustStore()}. */
|
||||
protected void loadDefaultTrustStore() {
|
||||
try {
|
||||
trustStore = KeyStoreUtils.loadDefaultTrustStore();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loaded default trust store");
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn("Could not open default trust store", ex);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Inner classes
|
||||
//
|
||||
|
||||
private class KeyStoreCertificateValidator implements CertificateValidationCallback.CertificateValidator {
|
||||
|
||||
public boolean validate(X509Certificate certificate)
|
||||
throws CertificateValidationCallback.CertificateValidationException {
|
||||
if (isOwnedCert(certificate)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Certificate with DN [" + certificate.getSubjectX500Principal().getName() +
|
||||
"] is in private keystore");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (trustStore == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
certificate.checkValidity();
|
||||
}
|
||||
catch (CertificateExpiredException e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Certificate with DN [" + certificate.getSubjectX500Principal().getName() +
|
||||
"] has expired");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (CertificateNotYetValidException e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Certificate with DN [" + certificate.getSubjectX500Principal().getName() +
|
||||
"] is not yet valid");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
X509CertSelector certSelector = new X509CertSelector();
|
||||
certSelector.setCertificate(certificate);
|
||||
|
||||
PKIXBuilderParameters parameters;
|
||||
CertPathBuilder builder;
|
||||
try {
|
||||
parameters = new PKIXBuilderParameters(trustStore, certSelector);
|
||||
parameters.setRevocationEnabled(false);
|
||||
builder = CertPathBuilder.getInstance("PKIX");
|
||||
}
|
||||
catch (GeneralSecurityException ex) {
|
||||
throw new CertificateValidationCallback.CertificateValidationException(
|
||||
"Could not create PKIX CertPathBuilder", ex);
|
||||
}
|
||||
|
||||
try {
|
||||
builder.build(parameters);
|
||||
}
|
||||
catch (CertPathBuilderException e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Certification path of certificate with DN [" +
|
||||
certificate.getSubjectX500Principal().getName() + "] could not be validated");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (InvalidAlgorithmParameterException e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Algorithm of certificate with DN [" +
|
||||
certificate.getSubjectX500Principal().getName() + "] could not be validated");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Certificate with DN [" + certificate.getSubjectX500Principal().getName() + "] validated");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isOwnedCert(X509Certificate cert)
|
||||
throws CertificateValidationCallback.CertificateValidationException {
|
||||
if (keyStore == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Enumeration<String> aliases = keyStore.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
if (keyStore.isKeyEntry(alias)) {
|
||||
X509Certificate x509Cert = (X509Certificate) keyStore.getCertificate(alias);
|
||||
if (x509Cert != null) {
|
||||
if (x509Cert.equals(cert)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw new CertificateValidationCallback.CertificateValidationException(
|
||||
"Could not determine whether certificate is contained in main key store", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.xwss.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
|
||||
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
|
||||
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
|
||||
/**
|
||||
* Mock implementation of of callback handler that accepts all password and certificate validation callbacks.
|
||||
* <p/>
|
||||
* If the <code>valid</code> property is set to <code>true</code> (the default), this handler simply accepts and
|
||||
* validates every password or certificate validation callback that is passed to it.
|
||||
* <p/>
|
||||
* This class handles <code>CertificateValidationCallback</code>s and <code>PasswordValidationCallback</code>s, and
|
||||
* throws an <code>UnsupportedCallbackException</code> for others
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class MockValidationCallbackHandler extends AbstractCallbackHandler {
|
||||
|
||||
private boolean isValid = true;
|
||||
|
||||
public MockValidationCallbackHandler() {
|
||||
}
|
||||
|
||||
public MockValidationCallbackHandler(boolean valid) {
|
||||
isValid = valid;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
if (callback instanceof CertificateValidationCallback) {
|
||||
CertificateValidationCallback validationCallback = (CertificateValidationCallback) callback;
|
||||
validationCallback.setValidator(new MockCertificateValidator());
|
||||
}
|
||||
else if (callback instanceof PasswordValidationCallback) {
|
||||
PasswordValidationCallback validationCallback = (PasswordValidationCallback) callback;
|
||||
validationCallback.setValidator(new MockPasswordValidator());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
public void setValid(boolean valid) {
|
||||
isValid = valid;
|
||||
}
|
||||
|
||||
private class MockCertificateValidator implements CertificateValidationCallback.CertificateValidator {
|
||||
|
||||
public boolean validate(X509Certificate certificate)
|
||||
throws CertificateValidationCallback.CertificateValidationException {
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
|
||||
private class MockPasswordValidator implements PasswordValidationCallback.PasswordValidator {
|
||||
|
||||
public boolean validate(PasswordValidationCallback.Request request)
|
||||
throws PasswordValidationCallback.PasswordValidationException {
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.xwss.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
|
||||
import com.sun.xml.wss.impl.callback.TimestampValidationCallback;
|
||||
|
||||
/**
|
||||
* Simple callback handler that validates passwords agains a in-memory <code>Properties</code> object. Password
|
||||
* validation is done on a case-sensitive basis.
|
||||
* <p/>
|
||||
* This class only handles <code>PasswordValidationCallback</code>s, and throws an
|
||||
* <code>UnsupportedCallbackException</code> for others
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #setUsers(java.util.Properties)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SimplePasswordValidationCallbackHandler extends AbstractCallbackHandler implements InitializingBean {
|
||||
|
||||
private Map<String, String> users = new HashMap<String, String>();
|
||||
|
||||
/** Sets the users to validate against. Property names are usernames, property values are passwords. */
|
||||
public void setUsers(Properties users) {
|
||||
for (Map.Entry<Object, Object> entry : users.entrySet()) {
|
||||
if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
|
||||
this.users.put((String) entry.getKey(), (String) entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setUsersMap(Map<String, String> users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(users, "users is required");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
if (callback instanceof PasswordValidationCallback) {
|
||||
PasswordValidationCallback passwordCallback = (PasswordValidationCallback) callback;
|
||||
if (passwordCallback.getRequest() instanceof PasswordValidationCallback.PlainTextPasswordRequest) {
|
||||
passwordCallback.setValidator(new SimplePlainTextPasswordValidator());
|
||||
}
|
||||
else if (passwordCallback.getRequest() instanceof PasswordValidationCallback.DigestPasswordRequest) {
|
||||
PasswordValidationCallback.DigestPasswordRequest digestPasswordRequest =
|
||||
(PasswordValidationCallback.DigestPasswordRequest) passwordCallback.getRequest();
|
||||
String password = users.get(digestPasswordRequest.getUsername());
|
||||
digestPasswordRequest.setPassword(password);
|
||||
passwordCallback.setValidator(new PasswordValidationCallback.DigestPasswordValidator());
|
||||
}
|
||||
}
|
||||
else if (callback instanceof TimestampValidationCallback) {
|
||||
TimestampValidationCallback timestampCallback = (TimestampValidationCallback) callback;
|
||||
timestampCallback.setValidator(new DefaultTimestampValidator());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private class SimplePlainTextPasswordValidator implements PasswordValidationCallback.PasswordValidator {
|
||||
|
||||
public boolean validate(PasswordValidationCallback.Request request)
|
||||
throws PasswordValidationCallback.PasswordValidationException {
|
||||
PasswordValidationCallback.PlainTextPasswordRequest plainTextPasswordRequest =
|
||||
(PasswordValidationCallback.PlainTextPasswordRequest) request;
|
||||
String password = users.get(plainTextPasswordRequest.getUsername());
|
||||
return password != null && password.equals(plainTextPasswordRequest.getPassword());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2002-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
|
||||
*
|
||||
* 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.xwss.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.PasswordCallback;
|
||||
import com.sun.xml.wss.impl.callback.UsernameCallback;
|
||||
|
||||
/**
|
||||
* Simple callback handler that supplies a username and password to a username token at runtime.
|
||||
* <p/>
|
||||
* This class handles <code>UsernameCallback</code>s and <code>PasswordCallback</code>s, and throws an
|
||||
* <code>UnsupportedCallbackException</code> for others
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #setUsername(String)
|
||||
* @see #setPassword(String)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SimpleUsernamePasswordCallbackHandler extends AbstractCallbackHandler implements InitializingBean {
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an empty instance of the {@code SimpleUsernamePasswordCallbackHandler}.
|
||||
*/
|
||||
public SimpleUsernamePasswordCallbackHandler() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@code SimpleUsernamePasswordCallbackHandler} with the given name and password.
|
||||
*/
|
||||
public SimpleUsernamePasswordCallbackHandler(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(username, "username must be set");
|
||||
Assert.hasLength(password, "password must be set");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
if (callback instanceof UsernameCallback) {
|
||||
UsernameCallback usernameCallback = (UsernameCallback) callback;
|
||||
usernameCallback.setUsername(username);
|
||||
}
|
||||
else if (callback instanceof PasswordCallback) {
|
||||
PasswordCallback passwordCallback = (PasswordCallback) callback;
|
||||
passwordCallback.setPassword(password);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.xwss.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.ws.soap.security.x509.X509AuthenticationToken;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
import org.springframework.ws.soap.security.callback.CleanupCallback;
|
||||
|
||||
/**
|
||||
* Callback handler that validates a certificate using an Spring Security <code>AuthenticationManager</code>. Logic
|
||||
* based on Spring Security's <code>X509ProcessingFilter</code>. <p/> Spring Security
|
||||
* <code>X509AuthenticationToken</code> is created with the certificate as the credentials. <p/> The configured
|
||||
* authentication manager is expected to supply a provider which can handle this token (usually an instance of
|
||||
* <code>X509AuthenticationProvider</code>).</p>
|
||||
* <p/>
|
||||
* This class only handles <code>CertificateValidationCallback</code>s, and throws an
|
||||
* <code>UnsupportedCallbackException</code> for others.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see org.springframework.ws.soap.security.x509.X509AuthenticationToken
|
||||
* @see org.springframework.ws.soap.security.x509.X509AuthenticationProvider
|
||||
* @see com.sun.xml.wss.impl.callback.CertificateValidationCallback
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class SpringCertificateValidationCallbackHandler extends AbstractCallbackHandler 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");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles <code>CertificateValidationCallback</code>s, and throws an <code>UnsupportedCallbackException</code> for
|
||||
* others
|
||||
*
|
||||
* @throws javax.security.auth.callback.UnsupportedCallbackException
|
||||
* when the callback is not supported
|
||||
*/
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
if (callback instanceof CertificateValidationCallback) {
|
||||
((CertificateValidationCallback) callback).setValidator(new SpringSecurityCertificateValidator());
|
||||
}
|
||||
else if (callback instanceof CleanupCallback) {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private class SpringSecurityCertificateValidator implements CertificateValidationCallback.CertificateValidator {
|
||||
|
||||
public boolean validate(X509Certificate certificate)
|
||||
throws CertificateValidationCallback.CertificateValidationException {
|
||||
boolean result;
|
||||
try {
|
||||
Authentication authResult =
|
||||
authenticationManager.authenticate(new X509AuthenticationToken(certificate));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for certificate with DN [" +
|
||||
certificate.getSubjectX500Principal().getName() + "] successful");
|
||||
}
|
||||
SecurityContextHolder.getContext().setAuthentication(authResult);
|
||||
return true;
|
||||
}
|
||||
catch (AuthenticationException failed) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for certificate with DN [" +
|
||||
certificate.getSubjectX500Principal().getName() + "] failed: " + failed.toString());
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
result = ignoreFailure;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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.xwss.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
|
||||
import com.sun.xml.wss.impl.callback.TimestampValidationCallback;
|
||||
|
||||
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.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.util.Assert;
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
import org.springframework.ws.soap.security.callback.CleanupCallback;
|
||||
import org.springframework.ws.soap.security.support.SpringSecurityUtils;
|
||||
|
||||
/**
|
||||
* Callback handler that validates a password digest using an Spring Security <code>UserDetailsService</code>. Logic
|
||||
* based on Spring Security's <code>DigestProcessingFilter</code>.
|
||||
* <p/>
|
||||
* An Spring Security <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.
|
||||
* <p/>
|
||||
* This class only handles <code>PasswordValidationCallback</code>s that contain a <code>DigestPasswordRequest</code>,
|
||||
* and throws an <code>UnsupportedCallbackException</code> for others.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see org.springframework.security.core.userdetails.UserDetailsService
|
||||
* @see com.sun.xml.wss.impl.callback.PasswordValidationCallback
|
||||
* @see com.sun.xml.wss.impl.callback.PasswordValidationCallback.DigestPasswordRequest
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class SpringDigestPasswordValidationCallbackHandler extends AbstractCallbackHandler implements InitializingBean {
|
||||
|
||||
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 Spring Security user details service. Required. */
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(userDetailsService, "userDetailsService is required");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles <code>PasswordValidationCallback</code>s that contain a <code>DigestPasswordRequest</code>, and throws an
|
||||
* <code>UnsupportedCallbackException</code> for others
|
||||
*
|
||||
* @throws javax.security.auth.callback.UnsupportedCallbackException
|
||||
* when the callback is not supported
|
||||
*/
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
if (callback instanceof PasswordValidationCallback) {
|
||||
PasswordValidationCallback passwordCallback = (PasswordValidationCallback) callback;
|
||||
if (passwordCallback.getRequest() instanceof PasswordValidationCallback.DigestPasswordRequest) {
|
||||
PasswordValidationCallback.DigestPasswordRequest request =
|
||||
(PasswordValidationCallback.DigestPasswordRequest) passwordCallback.getRequest();
|
||||
String username = request.getUsername();
|
||||
UserDetails user = loadUserDetails(username);
|
||||
if (user != null) {
|
||||
SpringSecurityUtils.checkUserValidity(user);
|
||||
request.setPassword(user.getPassword());
|
||||
}
|
||||
SpringSecurityDigestPasswordValidator validator = new SpringSecurityDigestPasswordValidator(user);
|
||||
passwordCallback.setValidator(validator);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (callback instanceof TimestampValidationCallback) {
|
||||
TimestampValidationCallback timestampCallback = (TimestampValidationCallback) callback;
|
||||
timestampCallback.setValidator(new DefaultTimestampValidator());
|
||||
|
||||
}
|
||||
else if (callback instanceof CleanupCallback) {
|
||||
SecurityContextHolder.clearContext();
|
||||
return;
|
||||
}
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private class SpringSecurityDigestPasswordValidator extends PasswordValidationCallback.DigestPasswordValidator {
|
||||
|
||||
private UserDetails user;
|
||||
|
||||
private SpringSecurityDigestPasswordValidator(UserDetails user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(PasswordValidationCallback.Request request)
|
||||
throws PasswordValidationCallback.PasswordValidationException {
|
||||
if (super.validate(request)) {
|
||||
UsernamePasswordAuthenticationToken authRequest =
|
||||
new UsernamePasswordAuthenticationToken(user, user.getPassword());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication success: " + authRequest.toString());
|
||||
}
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(authRequest);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.xwss.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
import org.springframework.ws.soap.security.callback.CleanupCallback;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p/>
|
||||
* This class only handles <code>PasswordValidationCallback</code>s that contain a
|
||||
* <code>PlainTextPasswordRequest</code>, and throws an <code>UnsupportedCallbackException</code> for others.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
* @see com.sun.xml.wss.impl.callback.PasswordValidationCallback
|
||||
* @see com.sun.xml.wss.impl.callback.PasswordValidationCallback.PlainTextPasswordRequest
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class SpringPlainTextPasswordValidationCallbackHandler extends AbstractCallbackHandler
|
||||
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");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles <code>PasswordValidationCallback</code>s that contain a <code>PlainTextPasswordRequest</code>, and throws
|
||||
* an <code>UnsupportedCallbackException</code> for others.
|
||||
*
|
||||
* @throws javax.security.auth.callback.UnsupportedCallbackException
|
||||
* when the callback is not supported
|
||||
*/
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
if (callback instanceof PasswordValidationCallback) {
|
||||
PasswordValidationCallback validationCallback = (PasswordValidationCallback) callback;
|
||||
if (validationCallback.getRequest() instanceof PasswordValidationCallback.PlainTextPasswordRequest) {
|
||||
validationCallback.setValidator(new SpringSecurityPlainTextPasswordValidator());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (callback instanceof CleanupCallback) {
|
||||
SecurityContextHolder.clearContext();
|
||||
return;
|
||||
}
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
private class SpringSecurityPlainTextPasswordValidator implements PasswordValidationCallback.PasswordValidator {
|
||||
|
||||
public boolean validate(PasswordValidationCallback.Request request)
|
||||
throws PasswordValidationCallback.PasswordValidationException {
|
||||
PasswordValidationCallback.PlainTextPasswordRequest plainTextRequest =
|
||||
(PasswordValidationCallback.PlainTextPasswordRequest) request;
|
||||
try {
|
||||
Authentication authResult = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
|
||||
plainTextRequest.getUsername(), plainTextRequest.getPassword()));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication success: " + authResult.toString());
|
||||
}
|
||||
SecurityContextHolder.getContext().setAuthentication(authResult);
|
||||
return true;
|
||||
}
|
||||
catch (AuthenticationException failed) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for user '" + plainTextRequest.getUsername() + "' failed: " +
|
||||
failed.toString());
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
return ignoreFailure;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.xwss.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.PasswordCallback;
|
||||
import com.sun.xml.wss.impl.callback.UsernameCallback;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
|
||||
/**
|
||||
* Callback handler that adds username/password information to a mesage using an Spring Security {@link
|
||||
* org.springframework.security.core.context.SecurityContext}.
|
||||
* <p/>
|
||||
* This class handles <code>UsernameCallback</code>s and <code>PasswordCallback</code>s, and throws an
|
||||
* <code>UnsupportedCallbackException</code> for others
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class SpringUsernamePasswordCallbackHandler extends AbstractCallbackHandler {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
if (callback instanceof UsernameCallback) {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication != null && authentication.getName() != null) {
|
||||
UsernameCallback usernameCallback = (UsernameCallback) callback;
|
||||
usernameCallback.setUsername(authentication.getName());
|
||||
return;
|
||||
}
|
||||
else {
|
||||
logger.warn(
|
||||
"Cannot handle UsernameCallback: Spring Security SecurityContext contains no Authentication");
|
||||
}
|
||||
}
|
||||
else if (callback instanceof PasswordCallback) {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication != null && authentication.getName() != null) {
|
||||
PasswordCallback passwordCallback = (PasswordCallback) callback;
|
||||
passwordCallback.setPassword(authentication.getCredentials().toString());
|
||||
return;
|
||||
}
|
||||
else {
|
||||
logger.warn(
|
||||
"Canot handle PasswordCallback: Spring Security SecurityContext contains no Authentication");
|
||||
}
|
||||
}
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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.xwss.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
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.CallbackHandlerChain;
|
||||
|
||||
/**
|
||||
* 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.0.0
|
||||
*/
|
||||
public class XwssCallbackHandlerChain extends CallbackHandlerChain {
|
||||
|
||||
public XwssCallbackHandlerChain(CallbackHandler[] callbackHandlers) {
|
||||
super(callbackHandlers);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
|
||||
if (callback instanceof CertificateValidationCallback) {
|
||||
handleCertificateValidationCallback((CertificateValidationCallback) callback);
|
||||
}
|
||||
else if (callback instanceof PasswordValidationCallback) {
|
||||
handlePasswordValidationCallback((PasswordValidationCallback) callback);
|
||||
}
|
||||
else if (callback instanceof TimestampValidationCallback) {
|
||||
handleTimestampValidationCallback((TimestampValidationCallback) callback);
|
||||
}
|
||||
else {
|
||||
super.handleInternal(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCertificateValidationCallback(CertificateValidationCallback callback) {
|
||||
callback.setValidator(new CertificateValidatorChain(callback));
|
||||
}
|
||||
|
||||
private void handlePasswordValidationCallback(PasswordValidationCallback callback) {
|
||||
callback.setValidator(new PasswordValidatorChain(callback));
|
||||
}
|
||||
|
||||
private void handleTimestampValidationCallback(TimestampValidationCallback callback) {
|
||||
callback.setValidator(new TimestampValidatorChain(callback));
|
||||
}
|
||||
|
||||
private class TimestampValidatorChain implements TimestampValidationCallback.TimestampValidator {
|
||||
|
||||
private TimestampValidationCallback callback;
|
||||
|
||||
private TimestampValidatorChain(TimestampValidationCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void validate(TimestampValidationCallback.Request request)
|
||||
throws TimestampValidationCallback.TimestampValidationException {
|
||||
for (int i = 0; i < getCallbackHandlers().length; i++) {
|
||||
CallbackHandler callbackHandler = getCallbackHandlers()[i];
|
||||
try {
|
||||
callbackHandler.handle(new Callback[]{callback});
|
||||
callback.getResult();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new TimestampValidationCallback.TimestampValidationException(e);
|
||||
}
|
||||
catch (UnsupportedCallbackException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PasswordValidatorChain implements PasswordValidationCallback.PasswordValidator {
|
||||
|
||||
private PasswordValidationCallback callback;
|
||||
|
||||
private PasswordValidatorChain(PasswordValidationCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public boolean validate(PasswordValidationCallback.Request request)
|
||||
throws PasswordValidationCallback.PasswordValidationException {
|
||||
boolean allUnsupported = true;
|
||||
for (int i = 0; i < getCallbackHandlers().length; i++) {
|
||||
CallbackHandler callbackHandler = getCallbackHandlers()[i];
|
||||
try {
|
||||
callbackHandler.handle(new Callback[]{callback});
|
||||
allUnsupported = false;
|
||||
if (!callback.getResult()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new PasswordValidationCallback.PasswordValidationException(e);
|
||||
}
|
||||
catch (UnsupportedCallbackException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return !allUnsupported;
|
||||
}
|
||||
}
|
||||
|
||||
private class CertificateValidatorChain implements CertificateValidationCallback.CertificateValidator {
|
||||
|
||||
private CertificateValidationCallback callback;
|
||||
|
||||
private CertificateValidatorChain(CertificateValidationCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public boolean validate(X509Certificate certificate)
|
||||
throws CertificateValidationCallback.CertificateValidationException {
|
||||
boolean allUnsupported = true;
|
||||
for (int i = 0; i < getCallbackHandlers().length; i++) {
|
||||
CallbackHandler callbackHandler = getCallbackHandlers()[i];
|
||||
try {
|
||||
callbackHandler.handle(new Callback[]{callback});
|
||||
allUnsupported = false;
|
||||
if (!callback.getResult()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new CertificateValidationCallback.CertificateValidationException(e);
|
||||
}
|
||||
catch (UnsupportedCallbackException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return !allUnsupported;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.xwss.callback.jaas;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
|
||||
/**
|
||||
* Abstract base class for integrating with JAAS. Provides a login context name property.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class AbstractJaasValidationCallbackHandler extends AbstractCallbackHandler
|
||||
implements InitializingBean {
|
||||
|
||||
private String loginContextName;
|
||||
|
||||
protected AbstractJaasValidationCallbackHandler() {
|
||||
}
|
||||
|
||||
/** Returns the login context name. */
|
||||
public String getLoginContextName() {
|
||||
return loginContextName;
|
||||
}
|
||||
|
||||
/** Sets the login context name. */
|
||||
public void setLoginContextName(String loginContextName) {
|
||||
this.loginContextName = loginContextName;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(loginContextName, "loginContextName is required");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.xwss.callback.jaas;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
import javax.security.auth.login.LoginException;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
|
||||
|
||||
/**
|
||||
* Provides basic support for integrating with JAAS and certificates. Requires the <code>loginContextName</code> to be
|
||||
* set.Requires a <code>LoginContext</code> which handles <code>X500Principal</code>s.
|
||||
* <p/>
|
||||
* This class only handles <code>CertificateValidationCallback</code>s, and throws an
|
||||
* <code>UnsupportedCallbackException</code> for others.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see javax.security.auth.x500.X500Principal
|
||||
* @see #setLoginContextName(String)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class JaasCertificateValidationCallbackHandler extends AbstractJaasValidationCallbackHandler {
|
||||
|
||||
/**
|
||||
* Handles <code>CertificateValidationCallback</code>s, and throws an <code>UnsupportedCallbackException</code> for
|
||||
* others
|
||||
*
|
||||
* @throws UnsupportedCallbackException when the callback is not supported
|
||||
*/
|
||||
@Override
|
||||
protected final void handleInternal(Callback callback) throws UnsupportedCallbackException {
|
||||
if (callback instanceof CertificateValidationCallback) {
|
||||
((CertificateValidationCallback) callback).setValidator(new JaasCertificateValidator());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private class JaasCertificateValidator implements CertificateValidationCallback.CertificateValidator {
|
||||
|
||||
public boolean validate(X509Certificate certificate)
|
||||
throws CertificateValidationCallback.CertificateValidationException {
|
||||
Subject subject = new Subject();
|
||||
subject.getPrincipals().add(certificate.getSubjectX500Principal());
|
||||
LoginContext loginContext;
|
||||
try {
|
||||
loginContext = new LoginContext(getLoginContextName(), subject);
|
||||
}
|
||||
catch (LoginException ex) {
|
||||
throw new CertificateValidationCallback.CertificateValidationException(ex);
|
||||
}
|
||||
catch (SecurityException ex) {
|
||||
throw new CertificateValidationCallback.CertificateValidationException(ex);
|
||||
}
|
||||
|
||||
try {
|
||||
loginContext.login();
|
||||
Subject subj = loginContext.getSubject();
|
||||
if (!subj.getPrincipals().isEmpty()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for certificate with DN [" +
|
||||
certificate.getSubjectX500Principal().getName() + "] successful");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for certificate with DN [" +
|
||||
certificate.getSubjectX500Principal().getName() + "] failed");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (LoginException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for certificate with DN [" +
|
||||
certificate.getSubjectX500Principal().getName() + "] failed");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.xwss.callback.jaas;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.NameCallback;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
import javax.security.auth.login.LoginException;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
|
||||
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
|
||||
/**
|
||||
* Provides basic support for integrating with JAAS and plain text passwords.
|
||||
* <p/>
|
||||
* This class only handles <code>PasswordValidationCallback</code>s that contain a
|
||||
* <code>PlainTextPasswordRequest</code>, and throws an <code>UnsupportedCallbackException</code> for others.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #getLoginContextName()
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class JaasPlainTextPasswordValidationCallbackHandler extends AbstractJaasValidationCallbackHandler {
|
||||
|
||||
/**
|
||||
* Handles <code>PasswordValidationCallback</code>s that contain a <code>PlainTextPasswordRequest</code>, and throws
|
||||
* an <code>UnsupportedCallbackException</code> for others.
|
||||
*
|
||||
* @throws UnsupportedCallbackException when the callback is not supported
|
||||
*/
|
||||
@Override
|
||||
protected final void handleInternal(Callback callback) throws UnsupportedCallbackException {
|
||||
if (callback instanceof PasswordValidationCallback) {
|
||||
PasswordValidationCallback validationCallback = (PasswordValidationCallback) callback;
|
||||
if (validationCallback.getRequest() instanceof PasswordValidationCallback.PlainTextPasswordRequest) {
|
||||
validationCallback.setValidator(new JaasPlainTextPasswordValidator());
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
|
||||
private class JaasPlainTextPasswordValidator implements PasswordValidationCallback.PasswordValidator {
|
||||
|
||||
public boolean validate(PasswordValidationCallback.Request request)
|
||||
throws PasswordValidationCallback.PasswordValidationException {
|
||||
PasswordValidationCallback.PlainTextPasswordRequest plainTextRequest =
|
||||
(PasswordValidationCallback.PlainTextPasswordRequest) request;
|
||||
|
||||
final String username = plainTextRequest.getUsername();
|
||||
final String password = plainTextRequest.getPassword();
|
||||
|
||||
LoginContext loginContext;
|
||||
try {
|
||||
loginContext = new LoginContext(getLoginContextName(), new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) throws UnsupportedCallbackException {
|
||||
if (callback instanceof NameCallback) {
|
||||
((NameCallback) callback).setName(username);
|
||||
}
|
||||
else if (callback instanceof PasswordCallback) {
|
||||
((PasswordCallback) callback).setPassword(password.toCharArray());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedCallbackException(callback);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (LoginException ex) {
|
||||
throw new PasswordValidationCallback.PasswordValidationException(ex);
|
||||
}
|
||||
catch (SecurityException ex) {
|
||||
throw new PasswordValidationCallback.PasswordValidationException(ex);
|
||||
}
|
||||
|
||||
try {
|
||||
loginContext.login();
|
||||
Subject subject = loginContext.getSubject();
|
||||
if (!subject.getPrincipals().isEmpty()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for user '" + username + "' successful");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for user '" + username + "' failed");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (LoginException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for user '" + username + "' failed");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
Contains <code>CallbackHandler</code> implementations for XWSS that use the <a
|
||||
href="http://java.sun.com/products/jaas/">Java Authentication and Authorization Service (JAAS)</a>.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Contains <code>CallbackHandler</code> implementations for XWSS.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
Contains classes for using the <a href="http://xwss.java.net/">XML and WebServices Security</a> WS-Security
|
||||
implementation within Spring-WS.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,96 @@
|
||||
package org.springframework.ws.soap.security;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.xml.soap.MessageFactory;
|
||||
import javax.xml.soap.MimeHeaders;
|
||||
import javax.xml.soap.SOAPException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.ws.context.DefaultMessageContext;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessage;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
|
||||
|
||||
public class SkipValidationWsSecurityInterceptorTest {
|
||||
|
||||
private MessageFactory messageFactory;
|
||||
private AbstractWsSecurityInterceptor interceptor;
|
||||
private SaajSoapMessageFactory soapMessageFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
messageFactory = MessageFactory.newInstance();
|
||||
soapMessageFactory = new SaajSoapMessageFactory(messageFactory);
|
||||
interceptor = new AbstractWsSecurityInterceptor() {
|
||||
|
||||
@Override
|
||||
protected void validateMessage(SoapMessage soapMessage,
|
||||
MessageContext messageContext)
|
||||
throws WsSecurityValidationException {
|
||||
fail("validation must be skipped.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void secureMessage(SoapMessage soapMessage,
|
||||
MessageContext messageContext)
|
||||
throws WsSecuritySecurementException {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanUp() {
|
||||
}
|
||||
};
|
||||
interceptor.setSkipValidationIfNoHeaderPresent(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipValidationOnNoHeader() throws Exception {
|
||||
doTestSkipValidation("noHeader-soap.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipValidationOnEmptyHeader() throws Exception {
|
||||
doTestSkipValidation("emptyHeader-soap.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipValidationOnNoSecurityHeader() throws Exception {
|
||||
doTestSkipValidation("noSecurityHeader-soap.xml");
|
||||
}
|
||||
|
||||
|
||||
private void doTestSkipValidation(String fileName) throws Exception {
|
||||
SoapMessage message = loadSaajMessage(fileName);
|
||||
MessageContext messageContext = new DefaultMessageContext(message,
|
||||
soapMessageFactory);
|
||||
assertTrue("handeRequest result must be true", interceptor
|
||||
.handleRequest(messageContext, null));
|
||||
|
||||
}
|
||||
|
||||
private SaajSoapMessage loadSaajMessage(String fileName)
|
||||
throws SOAPException, IOException {
|
||||
MimeHeaders mimeHeaders = new MimeHeaders();
|
||||
mimeHeaders.addHeader("Content-Type", "text/xml");
|
||||
Resource resource = new ClassPathResource(fileName, getClass());
|
||||
InputStream is = resource.getInputStream();
|
||||
try {
|
||||
assertTrue("Could not load SAAJ message [" + resource + "]",
|
||||
resource.exists());
|
||||
is = resource.getInputStream();
|
||||
return new SaajSoapMessage(messageFactory.createMessage(
|
||||
mimeHeaders, is));
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.callback;
|
||||
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class CallbackHandlerChainTest {
|
||||
|
||||
private CallbackHandler supported = new CallbackHandler() {
|
||||
public void handle(Callback[] callbacks) {
|
||||
}
|
||||
};
|
||||
|
||||
private CallbackHandler unsupported = new CallbackHandler() {
|
||||
public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
|
||||
throw new UnsupportedCallbackException(callbacks[0]);
|
||||
}
|
||||
};
|
||||
|
||||
private Callback callback = new Callback() {
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testSupported() throws Exception {
|
||||
CallbackHandlerChain chain = new CallbackHandlerChain(new CallbackHandler[]{supported});
|
||||
chain.handle(new Callback[]{callback});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsupportedSupported() throws Exception {
|
||||
CallbackHandlerChain chain = new CallbackHandlerChain(new CallbackHandler[]{unsupported, supported});
|
||||
chain.handle(new Callback[]{callback});
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedCallbackException.class)
|
||||
public void testUnsupported() throws Exception {
|
||||
CallbackHandlerChain chain = new CallbackHandlerChain(new CallbackHandler[]{unsupported});
|
||||
chain.handle(new Callback[]{callback});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class AxiomWss4jInterceptorTest extends Wss4jInterceptorTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class AxiomWss4jMessageInterceptorEncryptionTest extends Wss4jMessageInterceptorEncryptionTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class AxiomWss4jMessageInterceptorHeaderTest extends Wss4jMessageInterceptorHeaderTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class AxiomWss4jMessageInterceptorSignTest extends Wss4jMessageInterceptorSignTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class AxiomWss4jMessageInterceptorSoapActionTest extends Wss4jMessageInterceptorSoapActionTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class AxiomWss4jMessageInterceptorSpringSecurityCallbackHandlerTest
|
||||
extends Wss4jMessageInterceptorSpringSecurityCallbackHandlerTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class AxiomWss4jMessageInterceptorTimestampTest extends Wss4jMessageInterceptorTimestampTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class AxiomWss4jMessageInterceptorUsernameTokenSignatureTest
|
||||
extends Wss4jMessageInterceptorUsernameTokenSignatureTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class AxiomWss4jMessageInterceptorUsernameTokenTest extends Wss4jMessageInterceptorUsernameTokenTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/** @author tareq */
|
||||
public class AxiomWss4jMessageInterceptorX509Test extends Wss4jMessageInterceptorX509TestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class SaajWss4jInterceptorTest extends Wss4jInterceptorTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class SaajWss4jMessageInterceptorEncryptionTest extends Wss4jMessageInterceptorEncryptionTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class SaajWss4jMessageInterceptorHeaderTest extends Wss4jMessageInterceptorHeaderTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Iterator;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.soap.MimeHeaders;
|
||||
import javax.xml.soap.SOAPHeader;
|
||||
import javax.xml.soap.SOAPHeaderElement;
|
||||
import javax.xml.soap.SOAPMessage;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMResult;
|
||||
|
||||
import org.springframework.ws.context.DefaultMessageContext;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessage;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
|
||||
import org.springframework.xml.transform.StringSource;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SaajWss4jMessageInterceptorSignTest extends Wss4jMessageInterceptorSignTestCase {
|
||||
|
||||
private static final String PAYLOAD =
|
||||
"<tru:StockSymbol xmlns:tru=\"http://fabrikam123.com/payloads\">QQQ</tru:StockSymbol>";
|
||||
|
||||
@Test
|
||||
public void testSignAndValidate() throws Exception {
|
||||
Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||
interceptor.setSecurementActions("Signature");
|
||||
interceptor.setEnableSignatureConfirmation(false);
|
||||
interceptor.setSecurementPassword("123456");
|
||||
interceptor.setSecurementUsername("rsaKey");
|
||||
SOAPMessage saajMessage = saajSoap11MessageFactory.createMessage();
|
||||
transformer.transform(new StringSource(PAYLOAD), new DOMResult(saajMessage.getSOAPBody()));
|
||||
SoapMessage message = new SaajSoapMessage(saajMessage, saajSoap11MessageFactory);
|
||||
MessageContext messageContext = new DefaultMessageContext(message, new SaajSoapMessageFactory(saajSoap11MessageFactory));
|
||||
|
||||
interceptor.secureMessage(message, messageContext);
|
||||
|
||||
SOAPHeader header = ((SaajSoapMessage) message).getSaajMessage().getSOAPHeader();
|
||||
Iterator<?> iterator = header.getChildElements(new QName(
|
||||
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security"));
|
||||
assertTrue("No security header", iterator.hasNext());
|
||||
SOAPHeaderElement securityHeader = (SOAPHeaderElement) iterator.next();
|
||||
iterator = securityHeader.getChildElements(new QName("http://www.w3.org/2000/09/xmldsig#", "Signature"));
|
||||
assertTrue("No signature header", iterator.hasNext());
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
message.writeTo(bos);
|
||||
|
||||
MimeHeaders mimeHeaders = new MimeHeaders();
|
||||
mimeHeaders.addHeader("Content-Type", "text/xml");
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
|
||||
|
||||
SOAPMessage signed = saajSoap11MessageFactory.createMessage(mimeHeaders, bis);
|
||||
message = new SaajSoapMessage(signed, saajSoap11MessageFactory);
|
||||
messageContext = new DefaultMessageContext(message, new SaajSoapMessageFactory(saajSoap11MessageFactory));
|
||||
|
||||
interceptor.validateMessage(message, messageContext);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class SaajWss4jMessageInterceptorSoapActionTest extends Wss4jMessageInterceptorSoapActionTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class SaajWss4jMessageInterceptorSpringSecurityCallbackHandlerTest
|
||||
extends Wss4jMessageInterceptorSpringSecurityCallbackHandlerTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class SaajWss4jMessageInterceptorTimestampTest extends Wss4jMessageInterceptorTimestampTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class SaajWss4jMessageInterceptorUsernameTokenSignatureTest
|
||||
extends Wss4jMessageInterceptorUsernameTokenSignatureTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class SaajWss4jMessageInterceptorUsernameTokenTest extends Wss4jMessageInterceptorUsernameTokenTestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/** @author tareq */
|
||||
public class SaajWss4jMessageInterceptorX509Test extends Wss4jMessageInterceptorX509TestCase {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.springframework.ws.context.DefaultMessageContext;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.security.WsSecuritySecurementException;
|
||||
import org.springframework.ws.soap.security.WsSecurityValidationException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public abstract class Wss4jInterceptorTestCase extends Wss4jTestCase {
|
||||
|
||||
@Test
|
||||
public void testHandleRequest() throws Exception {
|
||||
SoapMessage request = loadSoap11Message("empty-soap.xml");
|
||||
final Object requestMessage = getMessage(request);
|
||||
SoapMessage validatedRequest = loadSoap11Message("empty-soap.xml");
|
||||
final Object validatedRequestMessage = getMessage(validatedRequest);
|
||||
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor() {
|
||||
@Override
|
||||
protected void secureMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws WsSecuritySecurementException {
|
||||
fail("secure not expected");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws WsSecurityValidationException {
|
||||
assertEquals("Invalid message", requestMessage, getMessage(soapMessage));
|
||||
setMessage(soapMessage, validatedRequestMessage);
|
||||
}
|
||||
};
|
||||
MessageContext context = new DefaultMessageContext(request, getSoap11MessageFactory());
|
||||
interceptor.handleRequest(context, null);
|
||||
assertEquals("Invalid request", validatedRequestMessage, getMessage((SoapMessage) context.getRequest()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleResponse() throws Exception {
|
||||
SoapMessage securedResponse = loadSoap11Message("empty-soap.xml");
|
||||
final Object securedResponseMessage = getMessage(securedResponse);
|
||||
|
||||
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor() {
|
||||
|
||||
@Override
|
||||
protected void secureMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws WsSecuritySecurementException {
|
||||
setMessage(soapMessage, securedResponseMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws WsSecurityValidationException {
|
||||
fail("validate not expected");
|
||||
}
|
||||
|
||||
};
|
||||
SoapMessage request = loadSoap11Message("empty-soap.xml");
|
||||
MessageContext context = new DefaultMessageContext(request, getSoap11MessageFactory());
|
||||
context.getResponse();
|
||||
interceptor.handleResponse(context, null);
|
||||
assertEquals("Invalid response", securedResponseMessage, getMessage((SoapMessage) context.getResponse()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
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.KeyStoreCallbackHandler;
|
||||
import org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean;
|
||||
|
||||
import org.apache.ws.security.components.crypto.Crypto;
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorEncryptionTestCase extends Wss4jTestCase {
|
||||
|
||||
protected Wss4jSecurityInterceptor interceptor;
|
||||
|
||||
@Override
|
||||
protected void onSetup() throws Exception {
|
||||
interceptor = new Wss4jSecurityInterceptor();
|
||||
interceptor.setValidationActions("Encrypt");
|
||||
interceptor.setSecurementActions("Encrypt");
|
||||
|
||||
KeyStoreCallbackHandler callbackHandler = new KeyStoreCallbackHandler();
|
||||
callbackHandler.setPrivateKeyPassword("123456");
|
||||
interceptor.setValidationCallbackHandler(callbackHandler);
|
||||
|
||||
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
|
||||
|
||||
Properties cryptoFactoryBeanConfig = new Properties();
|
||||
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.provider",
|
||||
"org.apache.ws.security.components.crypto.Merlin");
|
||||
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.merlin.keystore.type", "jceks");
|
||||
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.merlin.keystore.password", "123456");
|
||||
|
||||
// from the class path
|
||||
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.merlin.file", "private.jks");
|
||||
cryptoFactoryBean.setConfiguration(cryptoFactoryBeanConfig);
|
||||
cryptoFactoryBean.afterPropertiesSet();
|
||||
interceptor.setValidationDecryptionCrypto((Crypto) cryptoFactoryBean
|
||||
.getObject());
|
||||
interceptor.setSecurementEncryptionCrypto((Crypto) cryptoFactoryBean
|
||||
.getObject());
|
||||
|
||||
interceptor.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecryptRequest() throws Exception {
|
||||
SoapMessage message = loadSoap11Message("encrypted-soap.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.validateMessage(message, messageContext);
|
||||
Document document = getDocument((SoapMessage) messageContext.getRequest());
|
||||
assertXpathEvaluatesTo("Decryption error", "Hello", "/SOAP-ENV:Envelope/SOAP-ENV:Body/echo:echoRequest/text()",
|
||||
document);
|
||||
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security",
|
||||
getDocument(message));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncryptResponse() throws Exception {
|
||||
SoapMessage message = loadSoap11Message("empty-soap.xml");
|
||||
MessageContext messageContext = getSoap11MessageContext(message);
|
||||
interceptor.setSecurementEncryptionUser("rsakey");
|
||||
interceptor.secureMessage(message, messageContext);
|
||||
Document document = getDocument(message);
|
||||
assertXpathExists("Encryption error", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/xenc:EncryptedKey",
|
||||
document);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.junit.Test;
|
||||
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.WsSecurityValidationException;
|
||||
import org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorHeaderTestCase extends Wss4jTestCase {
|
||||
|
||||
private Wss4jSecurityInterceptor interceptor;
|
||||
|
||||
@Override
|
||||
protected void onSetup() throws Exception {
|
||||
Properties users = new Properties();
|
||||
users.setProperty("Bert", "Ernie");
|
||||
interceptor = new Wss4jSecurityInterceptor();
|
||||
interceptor.setValidateRequest(true);
|
||||
interceptor.setSecureResponse(true);
|
||||
interceptor.setValidationActions("UsernameToken");
|
||||
SimplePasswordValidationCallbackHandler callbackHandler = new SimplePasswordValidationCallbackHandler();
|
||||
callbackHandler.setUsers(users);
|
||||
interceptor.setValidationCallbackHandler(callbackHandler);
|
||||
interceptor.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateUsernameTokenPlainText() throws Exception {
|
||||
SoapMessage message = loadSoap11Message("usernameTokenPlainTextWithHeaders-soap.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.validateMessage(message, messageContext);
|
||||
Object result = getMessage(message);
|
||||
assertNotNull("No result returned", result);
|
||||
|
||||
for (Iterator<SoapHeaderElement> i = message.getEnvelope().getHeader().examineAllHeaderElements(); i.hasNext();) {
|
||||
SoapHeaderElement element = i.next();
|
||||
QName name = element.getName();
|
||||
if (name.getNamespaceURI()
|
||||
.equals("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")) {
|
||||
fail("Security Header not removed");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security",
|
||||
getDocument(message));
|
||||
assertXpathExists("header1 not found", "/SOAP-ENV:Envelope/SOAP-ENV:Header/header1", getDocument(message));
|
||||
assertXpathExists("header2 not found", "/SOAP-ENV:Envelope/SOAP-ENV:Header/header2", getDocument(message));
|
||||
|
||||
}
|
||||
|
||||
@Test(expected=WsSecurityValidationException.class)
|
||||
public void testEmptySecurityHeader() throws Exception {
|
||||
SoapMessage message = loadSoap11Message("emptySecurityHeader-soap.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.validateMessage(message, messageContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreserveCustomHeaders() throws Exception {
|
||||
interceptor.setSecurementActions("UsernameToken");
|
||||
interceptor.setSecurementUsername("Bert");
|
||||
interceptor.setSecurementPassword("Ernie");
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
SoapMessage message = loadSoap11Message("customHeader-soap.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
message.writeTo(os);
|
||||
String document = os.toString("UTF-8");
|
||||
assertXpathEvaluatesTo("Header 1 does not exist", "test1", "/SOAP-ENV:Envelope/SOAP-ENV:Header/test:header1",
|
||||
document);
|
||||
assertXpathNotExists("Header 2 exist", "/SOAP-ENV:Envelope/SOAP-ENV:Header/test:header2", document);
|
||||
|
||||
interceptor.secureMessage(message, messageContext);
|
||||
|
||||
SoapHeaderElement element = message.getSoapHeader().addHeaderElement(new QName("http://test", "header2"));
|
||||
element.setText("test2");
|
||||
|
||||
os = new ByteArrayOutputStream();
|
||||
message.writeTo(os);
|
||||
document = os.toString("UTF-8");
|
||||
assertXpathEvaluatesTo("Header 1 does not exist", "test1", "/SOAP-ENV:Envelope/SOAP-ENV:Header/test:header1",
|
||||
document);
|
||||
assertXpathEvaluatesTo("Header 2 does not exist", "test2", "/SOAP-ENV:Envelope/SOAP-ENV:Header/test:header2",
|
||||
document);
|
||||
|
||||
os = new ByteArrayOutputStream();
|
||||
message.writeTo(os);
|
||||
document = os.toString("UTF-8");
|
||||
assertXpathEvaluatesTo("Header 1 does not exist", "test1", "/SOAP-ENV:Envelope/SOAP-ENV:Header/test:header1",
|
||||
document);
|
||||
assertXpathEvaluatesTo("Header 2 does not exist", "test2", "/SOAP-ENV:Envelope/SOAP-ENV:Header/test:header2",
|
||||
document);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
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.support.CryptoFactoryBean;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorSignTestCase extends Wss4jTestCase {
|
||||
|
||||
protected Wss4jSecurityInterceptor interceptor;
|
||||
|
||||
@Override
|
||||
protected void onSetup() throws Exception {
|
||||
interceptor = new Wss4jSecurityInterceptor();
|
||||
interceptor.setValidationActions("Signature");
|
||||
|
||||
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
|
||||
Properties cryptoFactoryBeanConfig = new Properties();
|
||||
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.provider",
|
||||
"org.apache.ws.security.components.crypto.Merlin");
|
||||
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.merlin.keystore.type", "jceks");
|
||||
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.merlin.keystore.password", "123456");
|
||||
|
||||
// from the class path
|
||||
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.merlin.file", "private.jks");
|
||||
cryptoFactoryBean.setConfiguration(cryptoFactoryBeanConfig);
|
||||
cryptoFactoryBean.afterPropertiesSet();
|
||||
interceptor.setValidationSignatureCrypto(cryptoFactoryBean
|
||||
.getObject());
|
||||
interceptor.setSecurementSignatureCrypto(cryptoFactoryBean
|
||||
.getObject());
|
||||
interceptor.afterPropertiesSet();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCertificate() throws Exception {
|
||||
SoapMessage message = loadSoap11Message("signed-soap.xml");
|
||||
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.validateMessage(message, messageContext);
|
||||
Object result = getMessage(message);
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security",
|
||||
getDocument(message));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCertificateWithSignatureConfirmation() throws Exception {
|
||||
SoapMessage message = loadSoap11Message("signed-soap.xml");
|
||||
MessageContext messageContext = getSoap11MessageContext(message);
|
||||
interceptor.setEnableSignatureConfirmation(true);
|
||||
interceptor.validateMessage(message, messageContext);
|
||||
WebServiceMessage response = messageContext.getResponse();
|
||||
interceptor.secureMessage(message, messageContext);
|
||||
assertNotNull("No result returned", response);
|
||||
Document document = getDocument((SoapMessage) response);
|
||||
assertXpathExists("Absent SignatureConfirmation element",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse11:SignatureConfirmation", document);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSignResponse() throws Exception {
|
||||
interceptor.setSecurementActions("Signature");
|
||||
interceptor.setEnableSignatureConfirmation(false);
|
||||
interceptor.setSecurementPassword("123456");
|
||||
interceptor.setSecurementUsername("rsaKey");
|
||||
SoapMessage message = loadSoap11Message("empty-soap.xml");
|
||||
MessageContext messageContext = getSoap11MessageContext(message);
|
||||
|
||||
// interceptor.setSecurementSignatureKeyIdentifier("IssuerSerial");
|
||||
|
||||
interceptor.secureMessage(message, messageContext);
|
||||
|
||||
Document document = getDocument(message);
|
||||
assertXpathExists("Absent SignatureConfirmation element",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/ds:Signature", document);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSignResponseWithSignatureUser() throws Exception {
|
||||
interceptor.setSecurementActions("Signature");
|
||||
interceptor.setEnableSignatureConfirmation(false);
|
||||
interceptor.setSecurementPassword("123456");
|
||||
interceptor.setSecurementSignatureUser("rsaKey");
|
||||
SoapMessage message = loadSoap11Message("empty-soap.xml");
|
||||
MessageContext messageContext = getSoap11MessageContext(message);
|
||||
|
||||
interceptor.secureMessage(message, messageContext);
|
||||
|
||||
Document document = getDocument(message);
|
||||
assertXpathExists("Absent SignatureConfirmation element",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/ds:Signature", document);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.ws.WebServiceMessageFactory;
|
||||
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.SimplePasswordValidationCallbackHandler;
|
||||
|
||||
import org.apache.ws.security.WSConstants;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorSoapActionTestCase extends Wss4jTestCase {
|
||||
|
||||
private static final String SOAP_ACTION = "\"http://test\"";
|
||||
|
||||
private Properties users;
|
||||
|
||||
private Wss4jSecurityInterceptor interceptor;
|
||||
|
||||
@Override
|
||||
protected void onSetup() throws Exception {
|
||||
users = new Properties();
|
||||
users.setProperty("Bert", "Ernie");
|
||||
interceptor = new Wss4jSecurityInterceptor();
|
||||
interceptor.setValidationActions("UsernameToken");
|
||||
interceptor.setSecurementActions("UsernameToken");
|
||||
interceptor.setSecurementPasswordType(WSConstants.PW_TEXT);
|
||||
SimplePasswordValidationCallbackHandler callbackHandler = new SimplePasswordValidationCallbackHandler();
|
||||
callbackHandler.setUsers(users);
|
||||
interceptor.setValidationCallbackHandler(callbackHandler);
|
||||
|
||||
interceptor.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreserveSoapActionOnValidation() throws Exception {
|
||||
SoapMessage message = loadSoap11Message("usernameTokenPlainText-soap.xml");
|
||||
message.setSoapAction(SOAP_ACTION);
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.validateMessage(message, messageContext);
|
||||
|
||||
assertNotNull("Soap Action must not be null", message.getSoapAction());
|
||||
assertEquals("Soap Action is different from expected", SOAP_ACTION, message.getSoapAction());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreserveSoap12ActionOnValidation() throws Exception {
|
||||
SoapMessage message = loadSoap12Message("usernameTokenPlainText-soap12.xml");
|
||||
message.setSoapAction(SOAP_ACTION);
|
||||
WebServiceMessageFactory messageFactory = getSoap12MessageFactory();
|
||||
MessageContext messageContext = new DefaultMessageContext(message, messageFactory);
|
||||
interceptor.validateMessage(message, messageContext);
|
||||
|
||||
assertNotNull("Soap Action must not be null", message.getSoapAction());
|
||||
assertEquals("Soap Action is different from expected", SOAP_ACTION, message.getSoapAction());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreserveSoapActionOnSecurement() throws Exception {
|
||||
SoapMessage message = loadSoap11Message("empty-soap.xml");
|
||||
message.setSoapAction(SOAP_ACTION);
|
||||
interceptor.setSecurementUsername("Bert");
|
||||
interceptor.setSecurementPassword("Ernie");
|
||||
MessageContext messageContext = getSoap11MessageContext(message);
|
||||
interceptor.secureMessage(message, messageContext);
|
||||
|
||||
assertNotNull("Soap Action must not be null", message.getSoapAction());
|
||||
assertEquals("Soap Action is different from expected", SOAP_ACTION, message.getSoapAction());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreserveSoap12ActionOnSecurement() throws Exception {
|
||||
SoapMessage message = loadSoap12Message("empty-soap12.xml");
|
||||
message.setSoapAction(SOAP_ACTION);
|
||||
interceptor.setSecurementUsername("Bert");
|
||||
interceptor.setSecurementPassword("Ernie");
|
||||
MessageContext messageContext = getSoap12MessageContext(message);
|
||||
interceptor.secureMessage(message, messageContext);
|
||||
|
||||
assertNotNull("Soap Action must not be null", message.getSoapAction());
|
||||
assertEquals("Soap Action is different from expected", SOAP_ACTION, message.getSoapAction());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
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.SpringSecurityPasswordValidationCallbackHandler;
|
||||
|
||||
import org.apache.ws.security.WSConstants;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.easymock.EasyMock.*;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorSpringSecurityCallbackHandlerTestCase extends Wss4jTestCase {
|
||||
|
||||
private Properties users = new Properties();
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Override
|
||||
protected void onSetup() throws Exception {
|
||||
authenticationManager = createMock(AuthenticationManager.class);
|
||||
users.setProperty("Bert", "Ernie,ROLE_TEST");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
verify(authenticationManager);
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateUsernameTokenPlainText() throws Exception {
|
||||
EndpointInterceptor interceptor = prepareInterceptor("UsernameToken", true, false);
|
||||
SoapMessage message = loadSoap11Message("usernameTokenPlainText-soap.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.handleRequest(messageContext, null);
|
||||
assertValidateUsernameToken(message);
|
||||
|
||||
// test clean up
|
||||
messageContext.getResponse();
|
||||
interceptor.handleResponse(messageContext, null);
|
||||
interceptor.afterCompletion(messageContext, null, null);
|
||||
assertNull("Authentication created", SecurityContextHolder.getContext().getAuthentication());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateUsernameTokenDigest() throws Exception {
|
||||
EndpointInterceptor interceptor = prepareInterceptor("UsernameToken", true, true);
|
||||
SoapMessage message = loadSoap11Message("usernameTokenDigest-soap.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.handleRequest(messageContext, null);
|
||||
assertValidateUsernameToken(message);
|
||||
|
||||
// test clean up
|
||||
messageContext.getResponse();
|
||||
interceptor.handleResponse(messageContext, null);
|
||||
interceptor.afterCompletion(messageContext, null, null);
|
||||
assertNull("Authentication created", SecurityContextHolder.getContext().getAuthentication());
|
||||
}
|
||||
|
||||
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));
|
||||
assertNotNull("No Authentication created", SecurityContextHolder.getContext().getAuthentication());
|
||||
}
|
||||
|
||||
protected EndpointInterceptor prepareInterceptor(String actions, boolean validating, boolean digest)
|
||||
throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
|
||||
if (validating) {
|
||||
interceptor.setValidationActions(actions);
|
||||
}
|
||||
else {
|
||||
interceptor.setSecurementActions(actions);
|
||||
}
|
||||
SpringSecurityPasswordValidationCallbackHandler callbackHandler =
|
||||
new SpringSecurityPasswordValidationCallbackHandler();
|
||||
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager(users);
|
||||
callbackHandler.setUserDetailsService(userDetailsManager);
|
||||
if (digest) {
|
||||
interceptor.setSecurementPasswordType(WSConstants.PW_DIGEST);
|
||||
}
|
||||
else {
|
||||
interceptor.setSecurementPasswordType(WSConstants.PW_TEXT);
|
||||
}
|
||||
interceptor.setValidationCallbackHandler(callbackHandler);
|
||||
interceptor.afterPropertiesSet();
|
||||
replay(authenticationManager);
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import org.springframework.ws.context.DefaultMessageContext;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.security.WsSecurityValidationException;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorTimestampTestCase extends Wss4jTestCase {
|
||||
|
||||
@Test
|
||||
public void testAddTimestamp() throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
|
||||
interceptor.setSecurementActions("Timestamp");
|
||||
interceptor.afterPropertiesSet();
|
||||
SoapMessage message = loadSoap11Message("empty-soap.xml");
|
||||
MessageContext context = getSoap11MessageContext(message);
|
||||
interceptor.secureMessage(message, context);
|
||||
Document document = getDocument(message);
|
||||
assertXpathExists("timestamp header not found",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsu:Timestamp", document);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateTimestamp() throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
|
||||
interceptor.setValidationActions("Timestamp");
|
||||
interceptor.afterPropertiesSet();
|
||||
SoapMessage message = getMessageWithTimestamp();
|
||||
|
||||
MessageContext context = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.validateMessage(message, context);
|
||||
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security",
|
||||
getDocument(message));
|
||||
}
|
||||
|
||||
@Test(expected = WsSecurityValidationException.class)
|
||||
public void testValidateTimestampWithExpiredTtl() throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
|
||||
interceptor.setValidationActions("Timestamp");
|
||||
interceptor.afterPropertiesSet();
|
||||
SoapMessage message = loadSoap11Message("expiredTimestamp-soap.xml");
|
||||
MessageContext context = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.validateMessage(message, context);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSecureTimestampWithCustomTtl() throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
|
||||
interceptor.setSecurementActions("Timestamp");
|
||||
interceptor.setTimestampStrict(true);
|
||||
int ttlInSeconds = 1;
|
||||
interceptor.setSecurementTimeToLive(ttlInSeconds);
|
||||
interceptor.afterPropertiesSet();
|
||||
SoapMessage message = loadSoap11Message("empty-soap.xml");
|
||||
MessageContext context = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.secureMessage(message, context);
|
||||
|
||||
String created = xpathTemplate.evaluateAsString("/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsu:Timestamp/wsu:Created/text()",
|
||||
message.getEnvelope().getSource());
|
||||
String expires = xpathTemplate.evaluateAsString("/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsu:Timestamp/wsu:Expires/text()",
|
||||
message.getEnvelope().getSource());
|
||||
|
||||
DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SS'Z'");
|
||||
|
||||
long actualTtl = format.parse(expires).getTime() - format.parse(created).getTime();
|
||||
assertEquals("invalid ttl", 1000 * ttlInSeconds, actualTtl);
|
||||
}
|
||||
|
||||
private SoapMessage getMessageWithTimestamp() throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
|
||||
interceptor.setSecurementActions("Timestamp");
|
||||
interceptor.afterPropertiesSet();
|
||||
SoapMessage message = loadSoap11Message("empty-soap.xml");
|
||||
MessageContext context = getSoap11MessageContext(message);
|
||||
interceptor.secureMessage(message, context);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorUsernameTokenSignatureTestCase extends Wss4jTestCase {
|
||||
|
||||
@Test
|
||||
public void testAddUsernameTokenSignature() throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
|
||||
interceptor.setSecurementActions("UsernameTokenSignature");
|
||||
interceptor.setSecurementUsername("Bert");
|
||||
interceptor.setSecurementPassword("Ernie");
|
||||
interceptor.afterPropertiesSet();
|
||||
SoapMessage message = loadSoap11Message("empty-soap.xml");
|
||||
MessageContext context = getSoap11MessageContext(message);
|
||||
interceptor.secureMessage(message, context);
|
||||
|
||||
Document doc = getDocument(message);
|
||||
assertXpathEvaluatesTo("Invalid Username", "Bert",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Username/text()", doc);
|
||||
assertXpathExists("Invalid Password",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Password[@Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest']/text()",
|
||||
doc);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
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.SimplePasswordValidationCallbackHandler;
|
||||
|
||||
import org.apache.ws.security.WSConstants;
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorUsernameTokenTestCase extends Wss4jTestCase {
|
||||
|
||||
private Properties users = new Properties();
|
||||
|
||||
@Override
|
||||
protected void onSetup() throws Exception {
|
||||
users.setProperty("Bert", "Ernie");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateUsernameTokenPlainText() throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = prepareInterceptor("UsernameToken", true, false);
|
||||
SoapMessage message = loadSoap11Message("usernameTokenPlainText-soap.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.validateMessage(message, messageContext);
|
||||
assertValidateUsernameToken(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateUsernameTokenDigest() throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = prepareInterceptor("UsernameToken", true, true);
|
||||
SoapMessage message = loadSoap11Message("usernameTokenDigest-soap.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.validateMessage(message, messageContext);
|
||||
assertValidateUsernameToken(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateUsernameTokenWithQualifiedType() throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = prepareInterceptor("UsernameToken", true, false);
|
||||
SoapMessage message = loadSoap11Message("usernameTokenPlainTextQualifiedType-soap.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, getSoap11MessageFactory());
|
||||
interceptor.validateMessage(message, messageContext);
|
||||
assertValidateUsernameToken(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddUsernameTokenPlainText() throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = prepareInterceptor("UsernameToken", false, false);
|
||||
interceptor.setSecurementUsername("Bert");
|
||||
interceptor.setSecurementPassword("Ernie");
|
||||
SoapMessage message = loadSoap11Message("empty-soap.xml");
|
||||
|
||||
MessageContext messageContext = getSoap11MessageContext(message);
|
||||
|
||||
interceptor.secureMessage(message, messageContext);
|
||||
assertAddUsernameTokenPlainText(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddUsernameTokenDigest() throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = prepareInterceptor("UsernameToken", false, true);
|
||||
interceptor.setSecurementUsername("Bert");
|
||||
interceptor.setSecurementPassword("Ernie");
|
||||
SoapMessage message = loadSoap11Message("empty-soap.xml");
|
||||
|
||||
MessageContext messageContext = getSoap11MessageContext(message);
|
||||
interceptor.secureMessage(message, messageContext);
|
||||
assertAddUsernameTokenDigest(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));
|
||||
}
|
||||
|
||||
protected void assertAddUsernameTokenPlainText(SoapMessage message) throws Exception {
|
||||
Object result = getMessage(message);
|
||||
assertNotNull("No result returned", result);
|
||||
Document doc = getDocument(message);
|
||||
assertXpathEvaluatesTo("Invalid Username", "Bert",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Username/text()", doc);
|
||||
assertXpathEvaluatesTo("Invalid Password", "Ernie",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Password[@Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText']/text()",
|
||||
doc);
|
||||
}
|
||||
|
||||
protected void assertAddUsernameTokenDigest(SoapMessage message) throws Exception {
|
||||
Object result = getMessage(message);
|
||||
Document doc = getDocument(message);
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathEvaluatesTo("Invalid Username", "Bert",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Username/text()", doc);
|
||||
assertXpathExists("Password does not exist",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Password[@Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest']",
|
||||
doc);
|
||||
|
||||
}
|
||||
|
||||
protected Wss4jSecurityInterceptor prepareInterceptor(String actions, boolean validating, boolean digest)
|
||||
throws Exception {
|
||||
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
|
||||
if (validating) {
|
||||
interceptor.setValidationActions(actions);
|
||||
}
|
||||
else {
|
||||
interceptor.setSecurementActions(actions);
|
||||
}
|
||||
SimplePasswordValidationCallbackHandler callbackHandler = new SimplePasswordValidationCallbackHandler();
|
||||
callbackHandler.setUsers(users);
|
||||
if (digest) {
|
||||
interceptor.setSecurementPasswordType(WSConstants.PW_DIGEST);
|
||||
}
|
||||
else {
|
||||
interceptor.setSecurementPasswordType(WSConstants.PW_TEXT);
|
||||
}
|
||||
interceptor.setValidationCallbackHandler(callbackHandler);
|
||||
interceptor.afterPropertiesSet();
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean;
|
||||
|
||||
import org.apache.ws.security.components.crypto.Crypto;
|
||||
import org.apache.ws.security.components.crypto.Merlin;
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
public abstract class Wss4jMessageInterceptorX509TestCase extends Wss4jTestCase {
|
||||
|
||||
protected Wss4jSecurityInterceptor interceptor;
|
||||
|
||||
@Override
|
||||
protected void onSetup() throws Exception {
|
||||
interceptor = new Wss4jSecurityInterceptor();
|
||||
interceptor.setSecurementActions("Signature");
|
||||
interceptor.setValidationActions("Signature");
|
||||
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
|
||||
cryptoFactoryBean.setCryptoProvider(Merlin.class);
|
||||
cryptoFactoryBean.setKeyStoreType("jceks");
|
||||
cryptoFactoryBean.setKeyStorePassword("123456");
|
||||
cryptoFactoryBean.setKeyStoreLocation(new ClassPathResource("private.jks"));
|
||||
|
||||
cryptoFactoryBean.afterPropertiesSet();
|
||||
interceptor.setSecurementSignatureCrypto((Crypto) cryptoFactoryBean
|
||||
.getObject());
|
||||
interceptor.setValidationSignatureCrypto((Crypto) cryptoFactoryBean
|
||||
.getObject());
|
||||
interceptor.afterPropertiesSet();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddCertificate() throws Exception {
|
||||
|
||||
interceptor.setSecurementPassword("123456");
|
||||
interceptor.setSecurementUsername("rsaKey");
|
||||
SoapMessage message = loadSoap11Message("empty-soap.xml");
|
||||
MessageContext messageContext = getSoap11MessageContext(message);
|
||||
|
||||
interceptor.setSecurementSignatureKeyIdentifier("DirectReference");
|
||||
|
||||
interceptor.secureMessage(message, messageContext);
|
||||
Document document = getDocument(message);
|
||||
|
||||
assertXpathExists("Absent BinarySecurityToken element",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:BinarySecurityToken", document);
|
||||
|
||||
// lets verify the signature that we've just generated
|
||||
interceptor.validateMessage(message, messageContext);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.xml.soap.MessageFactory;
|
||||
import javax.xml.soap.MimeHeaders;
|
||||
import javax.xml.soap.SOAPConstants;
|
||||
import javax.xml.soap.SOAPMessage;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
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.SoapMessageFactory;
|
||||
import org.springframework.ws.soap.SoapVersion;
|
||||
import org.springframework.ws.soap.axiom.AxiomSoapMessage;
|
||||
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
|
||||
import org.springframework.ws.soap.axiom.support.AxiomUtils;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessage;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
|
||||
import org.springframework.xml.transform.StringSource;
|
||||
import org.springframework.xml.xpath.Jaxp13XPathTemplate;
|
||||
|
||||
import org.apache.axiom.soap.SOAP12Constants;
|
||||
import org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public abstract class Wss4jTestCase {
|
||||
|
||||
protected MessageFactory saajSoap11MessageFactory;
|
||||
|
||||
protected MessageFactory saajSoap12MessageFactory;
|
||||
|
||||
protected final boolean axiomTest = this.getClass().getSimpleName().startsWith("Axiom");
|
||||
|
||||
protected final boolean saajTest = this.getClass().getSimpleName().startsWith("Saaj");
|
||||
|
||||
protected Jaxp13XPathTemplate xpathTemplate = new Jaxp13XPathTemplate();
|
||||
|
||||
@Before
|
||||
public final void setUp() throws Exception {
|
||||
if (!axiomTest && !saajTest) {
|
||||
throw new IllegalArgumentException("test class name must start with either Axiom or Saaj");
|
||||
}
|
||||
saajSoap11MessageFactory = MessageFactory.newInstance();
|
||||
saajSoap12MessageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
|
||||
Map<String, String> namespaces = new HashMap<String, String>();
|
||||
namespaces.put("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
|
||||
namespaces.put("wsse",
|
||||
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
|
||||
namespaces.put("ds", "http://www.w3.org/2000/09/xmldsig#");
|
||||
namespaces.put("xenc", "http://www.w3.org/2001/04/xmlenc#");
|
||||
namespaces.put("wsse11", "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd");
|
||||
namespaces.put("echo", "http://www.springframework.org/spring-ws/samples/echo");
|
||||
namespaces.put("wsu",
|
||||
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
|
||||
namespaces.put("test", "http://test");
|
||||
xpathTemplate.setNamespaces(namespaces);
|
||||
onSetup();
|
||||
}
|
||||
|
||||
protected void assertXpathEvaluatesTo(String message,
|
||||
String expectedValue,
|
||||
String xpathExpression,
|
||||
Document document) {
|
||||
String actualValue = xpathTemplate.evaluateAsString(xpathExpression, new DOMSource(document));
|
||||
Assert.assertEquals(message, expectedValue, actualValue);
|
||||
}
|
||||
|
||||
protected void assertXpathEvaluatesTo(String message,
|
||||
String expectedValue,
|
||||
String xpathExpression,
|
||||
String document) {
|
||||
String actualValue = xpathTemplate.evaluateAsString(xpathExpression, new StringSource(document));
|
||||
Assert.assertEquals(message, expectedValue, actualValue);
|
||||
}
|
||||
|
||||
protected void assertXpathExists(String message, String xpathExpression, Document document) {
|
||||
Node node = xpathTemplate.evaluateAsNode(xpathExpression, new DOMSource(document));
|
||||
Assert.assertNotNull(message, node);
|
||||
}
|
||||
|
||||
protected void assertXpathNotExists(String message, String xpathExpression, Document document) {
|
||||
Node node = xpathTemplate.evaluateAsNode(xpathExpression, new DOMSource(document));
|
||||
Assert.assertNull(message, node);
|
||||
}
|
||||
|
||||
protected void assertXpathNotExists(String message, String xpathExpression, String document) {
|
||||
Node node = xpathTemplate.evaluateAsNode(xpathExpression, new StringSource(document));
|
||||
Assert.assertNull(message, node);
|
||||
}
|
||||
|
||||
protected SaajSoapMessage loadSaaj11Message(String fileName) throws Exception {
|
||||
MimeHeaders mimeHeaders = new MimeHeaders();
|
||||
mimeHeaders.addHeader("Content-Type", "text/xml");
|
||||
Resource resource = new ClassPathResource(fileName, getClass());
|
||||
InputStream is = resource.getInputStream();
|
||||
try {
|
||||
assertTrue("Could not load SAAJ message [" + resource + "]", resource.exists());
|
||||
is = resource.getInputStream();
|
||||
return new SaajSoapMessage(saajSoap11MessageFactory.createMessage(mimeHeaders, is), saajSoap11MessageFactory);
|
||||
}
|
||||
finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected SaajSoapMessage loadSaaj12Message(String fileName) throws Exception {
|
||||
MimeHeaders mimeHeaders = new MimeHeaders();
|
||||
mimeHeaders.addHeader("Content-Type", "application/soap+xml");
|
||||
Resource resource = new ClassPathResource(fileName, getClass());
|
||||
InputStream is = resource.getInputStream();
|
||||
try {
|
||||
assertTrue("Could not load SAAJ message [" + resource + "]", resource.exists());
|
||||
is = resource.getInputStream();
|
||||
return new SaajSoapMessage(saajSoap12MessageFactory.createMessage(mimeHeaders, is), saajSoap12MessageFactory);
|
||||
}
|
||||
finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected AxiomSoapMessage loadAxiom11Message(String fileName) throws Exception {
|
||||
Resource resource = new ClassPathResource(fileName, getClass());
|
||||
InputStream is = resource.getInputStream();
|
||||
try {
|
||||
assertTrue("Could not load Axiom message [" + resource + "]", resource.exists());
|
||||
is = resource.getInputStream();
|
||||
|
||||
XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(is);
|
||||
StAXSOAPModelBuilder builder = new StAXSOAPModelBuilder(parser, null);
|
||||
org.apache.axiom.soap.SOAPMessage soapMessage = builder.getSoapMessage();
|
||||
return new AxiomSoapMessage(soapMessage, "", true, true);
|
||||
}
|
||||
finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("Since15")
|
||||
protected AxiomSoapMessage loadAxiom12Message(String fileName) throws Exception {
|
||||
Resource resource = new ClassPathResource(fileName, getClass());
|
||||
InputStream is = resource.getInputStream();
|
||||
try {
|
||||
assertTrue("Could not load Axiom message [" + resource + "]", resource.exists());
|
||||
is = resource.getInputStream();
|
||||
|
||||
XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(is);
|
||||
StAXSOAPModelBuilder builder = new StAXSOAPModelBuilder(parser, SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);
|
||||
org.apache.axiom.soap.SOAPMessage soapMessage = builder.getSoapMessage();
|
||||
return new AxiomSoapMessage(soapMessage, "", true, true);
|
||||
}
|
||||
finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected Object getMessage(SoapMessage soapMessage) {
|
||||
if (soapMessage instanceof SaajSoapMessage) {
|
||||
return ((SaajSoapMessage) soapMessage).getSaajMessage();
|
||||
}
|
||||
if (soapMessage instanceof AxiomSoapMessage) {
|
||||
return ((AxiomSoapMessage) soapMessage).getAxiomMessage();
|
||||
|
||||
}
|
||||
throw new IllegalArgumentException("Illegal message: " + soapMessage);
|
||||
}
|
||||
|
||||
protected void setMessage(SoapMessage soapMessage, Object message) {
|
||||
if (soapMessage instanceof SaajSoapMessage) {
|
||||
((SaajSoapMessage) soapMessage).setSaajMessage((SOAPMessage) message);
|
||||
return;
|
||||
}
|
||||
if (soapMessage instanceof AxiomSoapMessage) {
|
||||
((AxiomSoapMessage) soapMessage).setAxiomMessage((org.apache.axiom.soap.SOAPMessage) message);
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException("Illegal message: " + message);
|
||||
}
|
||||
|
||||
protected void onSetup() throws Exception {
|
||||
}
|
||||
|
||||
protected SoapMessage loadSoap11Message(String fileName) throws Exception {
|
||||
if (axiomTest) {
|
||||
return loadAxiom11Message(fileName);
|
||||
}
|
||||
if (saajTest) {
|
||||
return loadSaaj11Message(fileName);
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
protected SoapMessage loadSoap12Message(String fileName) throws Exception {
|
||||
if (axiomTest) {
|
||||
return loadAxiom12Message(fileName);
|
||||
}
|
||||
if (saajTest) {
|
||||
return loadSaaj12Message(fileName);
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
protected SoapMessageFactory getSoap11MessageFactory() throws Exception {
|
||||
if (axiomTest) {
|
||||
return new AxiomSoapMessageFactory();
|
||||
}
|
||||
if (saajTest) {
|
||||
return new SaajSoapMessageFactory(saajSoap11MessageFactory);
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
protected SoapMessageFactory getSoap12MessageFactory() throws Exception {
|
||||
SoapMessageFactory messageFactory;
|
||||
if (axiomTest) {
|
||||
messageFactory = new AxiomSoapMessageFactory();
|
||||
} else if (saajTest) {
|
||||
messageFactory = new SaajSoapMessageFactory(saajSoap12MessageFactory);
|
||||
} else
|
||||
throw new IllegalArgumentException();
|
||||
messageFactory.setSoapVersion(SoapVersion.SOAP_12);
|
||||
return messageFactory;
|
||||
}
|
||||
|
||||
protected Document getDocument(SoapMessage message) throws Exception {
|
||||
if (axiomTest) {
|
||||
return AxiomUtils.toDocument(((AxiomSoapMessage) message).getAxiomMessage().getSOAPEnvelope());
|
||||
}
|
||||
if (saajTest) {
|
||||
return ((SaajSoapMessage) message).getSaajMessage().getSOAPPart();
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
protected MessageContext getSoap11MessageContext(final SoapMessage response) throws Exception {
|
||||
return new DefaultMessageContext(response, getSoap11MessageFactory()) {
|
||||
@Override
|
||||
public WebServiceMessage getResponse() {
|
||||
return response;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected MessageContext getSoap12MessageContext(final SoapMessage response) throws Exception {
|
||||
return new DefaultMessageContext(response, getSoap12MessageFactory()) {
|
||||
@Override
|
||||
public WebServiceMessage getResponse() {
|
||||
return response;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.security.KeyStore;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.ws.soap.security.support.KeyStoreFactoryBean;
|
||||
|
||||
import org.apache.ws.security.WSPasswordCallback;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class KeyStoreCallbackHandlerTest {
|
||||
|
||||
private KeyStoreCallbackHandler callbackHandler;
|
||||
|
||||
private WSPasswordCallback callback;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
callbackHandler = new KeyStoreCallbackHandler();
|
||||
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 = factory.getObject();
|
||||
callbackHandler.setKeyStore(keyStore);
|
||||
callbackHandler.setSymmetricKeyPassword("123456");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleKeyName() throws Exception {
|
||||
callbackHandler.handleInternal(callback);
|
||||
Assert.assertNotNull("symmetric key must not be null", callback.getKey());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
import org.apache.ws.security.WSUsernameTokenPrincipal;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.easymock.EasyMock.*;
|
||||
|
||||
/** @author tareq */
|
||||
public class SpringSecurityPasswordValidationCallbackHandlerTest {
|
||||
|
||||
private SpringSecurityPasswordValidationCallbackHandler callbackHandler;
|
||||
|
||||
private SimpleGrantedAuthority grantedAuthority;
|
||||
|
||||
private UsernameTokenPrincipalCallback callback;
|
||||
|
||||
private UserDetails user;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
callbackHandler = new SpringSecurityPasswordValidationCallbackHandler();
|
||||
|
||||
grantedAuthority = new SimpleGrantedAuthority("ROLE_1");
|
||||
user = new User("Ernie", "Bert", true, true, true, true, Collections.singleton(grantedAuthority));
|
||||
|
||||
WSUsernameTokenPrincipal principal = new WSUsernameTokenPrincipal("Ernie", true);
|
||||
callback = new UsernameTokenPrincipalCallback(principal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleUsernameTokenPrincipal() throws Exception {
|
||||
UserDetailsService userDetailsService = createMock(UserDetailsService.class);
|
||||
callbackHandler.setUserDetailsService(userDetailsService);
|
||||
|
||||
expect(userDetailsService.loadUserByUsername("Ernie")).andReturn(user).anyTimes();
|
||||
|
||||
replay(userDetailsService);
|
||||
|
||||
callbackHandler.handleUsernameTokenPrincipal(callback);
|
||||
SecurityContext context = SecurityContextHolder.getContext();
|
||||
Assert.assertNotNull("SecurityContext must not be null", context);
|
||||
Authentication authentication = context.getAuthentication();
|
||||
Assert.assertNotNull("Authentication must not be null", authentication);
|
||||
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
|
||||
Assert.assertTrue("GrantedAuthority[] must not be null or empty",
|
||||
(authorities != null && authorities.size() > 0));
|
||||
Assert.assertEquals("Unexpected authority", grantedAuthority, authorities.iterator().next());
|
||||
|
||||
verify(userDetailsService);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import org.apache.ws.security.components.crypto.Merlin;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CryptoFactoryBeanTest {
|
||||
|
||||
private CryptoFactoryBean factoryBean;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
factoryBean = new CryptoFactoryBean();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetConfiguration() throws Exception {
|
||||
Properties configuration = new Properties();
|
||||
configuration.setProperty("org.apache.ws.security.crypto.provider",
|
||||
"org.apache.ws.security.components.crypto.Merlin");
|
||||
configuration.setProperty("org.apache.ws.security.crypto.merlin.keystore.type", "jceks");
|
||||
configuration.setProperty("org.apache.ws.security.crypto.merlin.keystore.password", "123456");
|
||||
configuration.setProperty("org.apache.ws.security.crypto.merlin.file", "private.jks");
|
||||
|
||||
factoryBean.setConfiguration(configuration);
|
||||
factoryBean.setBeanClassLoader(ClassUtils.getDefaultClassLoader());
|
||||
factoryBean.afterPropertiesSet();
|
||||
|
||||
Object result = factoryBean.getObject();
|
||||
Assert.assertNotNull("No result", result);
|
||||
Assert.assertTrue("Not a Merlin instance", result instanceof Merlin);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperties() throws Exception {
|
||||
factoryBean.setKeyStoreType("jceks");
|
||||
factoryBean.setKeyStorePassword("123456");
|
||||
factoryBean.setKeyStoreLocation(new ClassPathResource("private.jks"));
|
||||
factoryBean.setBeanClassLoader(ClassUtils.getDefaultClassLoader());
|
||||
factoryBean.afterPropertiesSet();
|
||||
Object result = factoryBean.getObject();
|
||||
Assert.assertNotNull("No result", result);
|
||||
Assert.assertTrue("Not a Merlin instance", result instanceof Merlin);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.xwss;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
public abstract class AbstractXwssMessageInterceptorKeyStoreTestCase extends AbstractXwssMessageInterceptorTestCase {
|
||||
|
||||
protected X509Certificate certificate;
|
||||
|
||||
protected PrivateKey privateKey;
|
||||
|
||||
@Override
|
||||
protected void onSetup() throws Exception {
|
||||
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = getClass().getResourceAsStream("test-keystore.jks");
|
||||
keyStore.load(is, "password".toCharArray());
|
||||
}
|
||||
finally {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
certificate = (X509Certificate) keyStore.getCertificate("alias");
|
||||
privateKey = (PrivateKey) keyStore.getKey("alias", "password".toCharArray());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.xwss;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.xml.soap.MessageFactory;
|
||||
import javax.xml.soap.MimeHeaders;
|
||||
import javax.xml.soap.SOAPException;
|
||||
import javax.xml.soap.SOAPMessage;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessage;
|
||||
import org.springframework.xml.xpath.XPathExpression;
|
||||
import org.springframework.xml.xpath.XPathExpressionFactory;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public abstract class AbstractXwssMessageInterceptorTestCase {
|
||||
|
||||
protected XwsSecurityInterceptor interceptor;
|
||||
|
||||
private MessageFactory messageFactory;
|
||||
|
||||
private Map<String, String> namespaces;
|
||||
|
||||
@Before
|
||||
public final void setUp() throws Exception {
|
||||
interceptor = new XwsSecurityInterceptor();
|
||||
messageFactory = MessageFactory.newInstance();
|
||||
namespaces = new HashMap<String, String>(4);
|
||||
namespaces.put("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
|
||||
namespaces.put("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
|
||||
namespaces.put("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
|
||||
namespaces.put("ds", "http://www.w3.org/2000/09/xmldsig#");
|
||||
namespaces.put("xenc", "http://www.w3.org/2001/04/xmlenc#");
|
||||
onSetup();
|
||||
}
|
||||
|
||||
protected void assertXpathEvaluatesTo(String message,
|
||||
String expectedValue,
|
||||
String xpathExpression,
|
||||
SOAPMessage soapMessage) {
|
||||
XPathExpression expression = XPathExpressionFactory.createXPathExpression(xpathExpression, namespaces);
|
||||
Document document = soapMessage.getSOAPPart();
|
||||
String actualValue = expression.evaluateAsString(document);
|
||||
Assert.assertEquals(message, expectedValue, actualValue);
|
||||
}
|
||||
|
||||
protected void assertXpathExists(String message, String xpathExpression, SOAPMessage soapMessage) {
|
||||
XPathExpression expression = XPathExpressionFactory.createXPathExpression(xpathExpression, namespaces);
|
||||
Document document = soapMessage.getSOAPPart();
|
||||
Node node = expression.evaluateAsNode(document);
|
||||
Assert.assertNotNull(message, node);
|
||||
}
|
||||
|
||||
protected void assertXpathNotExists(String message, String xpathExpression, SOAPMessage soapMessage) {
|
||||
XPathExpression expression = XPathExpressionFactory.createXPathExpression(xpathExpression, namespaces);
|
||||
Document document = soapMessage.getSOAPPart();
|
||||
Node node = expression.evaluateAsNode(document);
|
||||
Assert.assertNull(message, node);
|
||||
}
|
||||
|
||||
protected SaajSoapMessage loadSaajMessage(String fileName) throws SOAPException, IOException {
|
||||
MimeHeaders mimeHeaders = new MimeHeaders();
|
||||
mimeHeaders.addHeader("Content-Type", "text/xml");
|
||||
Resource resource = new ClassPathResource(fileName, getClass());
|
||||
InputStream is = resource.getInputStream();
|
||||
try {
|
||||
assertTrue("Could not load SAAJ message [" + resource + "]", resource.exists());
|
||||
is = resource.getInputStream();
|
||||
return new SaajSoapMessage(messageFactory.createMessage(mimeHeaders, is));
|
||||
}
|
||||
finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onSetup() throws Exception {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2005-2011 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.xwss;
|
||||
|
||||
import javax.xml.soap.MessageFactory;
|
||||
import javax.xml.soap.SOAPMessage;
|
||||
|
||||
import org.springframework.ws.context.DefaultMessageContext;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessage;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
|
||||
import org.springframework.ws.soap.security.WsSecurityValidationException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class XwsSecurityInterceptorTest {
|
||||
|
||||
private MessageFactory messageFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
messageFactory = MessageFactory.newInstance();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleServerRequest() throws Exception {
|
||||
final SOAPMessage request = messageFactory.createMessage();
|
||||
final SOAPMessage validatedRequest = messageFactory.createMessage();
|
||||
XwsSecurityInterceptor interceptor = new XwsSecurityInterceptor() {
|
||||
|
||||
@Override
|
||||
protected void secureMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws XwsSecuritySecurementException {
|
||||
fail("secure not expected");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateMessage(SoapMessage message, MessageContext messageContext)
|
||||
throws WsSecurityValidationException {
|
||||
SaajSoapMessage saajSoapMessage = (SaajSoapMessage) message;
|
||||
assertEquals("Invalid message", request, saajSoapMessage.getSaajMessage());
|
||||
saajSoapMessage.setSaajMessage(validatedRequest);
|
||||
}
|
||||
|
||||
};
|
||||
MessageContext context =
|
||||
new DefaultMessageContext(new SaajSoapMessage(request), new SaajSoapMessageFactory(messageFactory));
|
||||
interceptor.handleRequest(context, null);
|
||||
assertEquals("Invalid request", validatedRequest, ((SaajSoapMessage) context.getRequest()).getSaajMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleServerResponse() throws Exception {
|
||||
final SOAPMessage securedResponse = messageFactory.createMessage();
|
||||
final boolean[] cleanupCalled = new boolean[1];
|
||||
cleanupCalled[0] = false;
|
||||
XwsSecurityInterceptor interceptor = new XwsSecurityInterceptor() {
|
||||
|
||||
@Override
|
||||
protected void secureMessage(SoapMessage message, MessageContext messageContext)
|
||||
throws XwsSecuritySecurementException {
|
||||
SaajSoapMessage saajSoapMessage = (SaajSoapMessage) message;
|
||||
saajSoapMessage.setSaajMessage(securedResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws WsSecurityValidationException {
|
||||
fail("validate not expected");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanUp() {
|
||||
cleanupCalled[0] = true;
|
||||
}
|
||||
};
|
||||
|
||||
SOAPMessage request = messageFactory.createMessage();
|
||||
MessageContext context =
|
||||
new DefaultMessageContext(new SaajSoapMessage(request), new SaajSoapMessageFactory(messageFactory));
|
||||
context.getResponse();
|
||||
interceptor.handleResponse(context, null);
|
||||
interceptor.afterCompletion(context, null, null);
|
||||
assertEquals("Invalid response", securedResponse, ((SaajSoapMessage) context.getResponse()).getSaajMessage());
|
||||
assertTrue("Cleanup not called", cleanupCalled[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleServerFault() throws Exception {
|
||||
final boolean[] cleanupCalled = new boolean[1];
|
||||
cleanupCalled[0] = false;
|
||||
XwsSecurityInterceptor interceptor = new XwsSecurityInterceptor() {
|
||||
|
||||
|
||||
@Override
|
||||
protected void cleanUp() {
|
||||
cleanupCalled[0] = true;
|
||||
}
|
||||
};
|
||||
|
||||
SOAPMessage request = messageFactory.createMessage();
|
||||
MessageContext context =
|
||||
new DefaultMessageContext(new SaajSoapMessage(request), new SaajSoapMessageFactory(messageFactory));
|
||||
context.getResponse();
|
||||
interceptor.handleFault(context, null);
|
||||
interceptor.afterCompletion(context, null, null);
|
||||
assertTrue("Cleanup not called", cleanupCalled[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleClientRequest() throws Exception {
|
||||
final SOAPMessage request = messageFactory.createMessage();
|
||||
final SOAPMessage securedRequest = messageFactory.createMessage();
|
||||
XwsSecurityInterceptor interceptor = new XwsSecurityInterceptor() {
|
||||
|
||||
@Override
|
||||
protected void secureMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws XwsSecuritySecurementException {
|
||||
SaajSoapMessage saajSoapMessage = (SaajSoapMessage) soapMessage;
|
||||
assertEquals("Invalid message", request, saajSoapMessage.getSaajMessage());
|
||||
saajSoapMessage.setSaajMessage(securedRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateMessage(SoapMessage message, MessageContext messageContext)
|
||||
throws WsSecurityValidationException {
|
||||
fail("validate not expected");
|
||||
}
|
||||
|
||||
};
|
||||
MessageContext context =
|
||||
new DefaultMessageContext(new SaajSoapMessage(request), new SaajSoapMessageFactory(messageFactory));
|
||||
interceptor.handleRequest(context);
|
||||
assertEquals("Invalid request", securedRequest, ((SaajSoapMessage) context.getRequest()).getSaajMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleClientResponse() throws Exception {
|
||||
final SOAPMessage validatedResponse = messageFactory.createMessage();
|
||||
XwsSecurityInterceptor interceptor = new XwsSecurityInterceptor() {
|
||||
|
||||
@Override
|
||||
protected void secureMessage(SoapMessage message, MessageContext messageContext)
|
||||
throws XwsSecuritySecurementException {
|
||||
fail("secure not expected");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateMessage(SoapMessage soapMessage, MessageContext messageContext)
|
||||
throws WsSecurityValidationException {
|
||||
SaajSoapMessage saajSoapMessage = (SaajSoapMessage) soapMessage;
|
||||
saajSoapMessage.setSaajMessage(validatedResponse);
|
||||
}
|
||||
|
||||
};
|
||||
SOAPMessage request = messageFactory.createMessage();
|
||||
MessageContext context =
|
||||
new DefaultMessageContext(new SaajSoapMessage(request), new SaajSoapMessageFactory(messageFactory));
|
||||
context.getResponse();
|
||||
interceptor.handleResponse(context);
|
||||
assertEquals("Invalid response", validatedResponse, ((SaajSoapMessage) context.getResponse()).getSaajMessage());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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.xwss;
|
||||
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.xml.soap.SOAPMessage;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessage;
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.DecryptionKeyCallback;
|
||||
import com.sun.xml.wss.impl.callback.EncryptionKeyCallback;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class XwssMessageInterceptorEncryptTest extends AbstractXwssMessageInterceptorKeyStoreTestCase {
|
||||
|
||||
@Test
|
||||
public void testEncryptDefaultCertificate() throws Exception {
|
||||
interceptor.setPolicyConfiguration(new ClassPathResource("encrypt-config.xml", getClass()));
|
||||
CallbackHandler handler = new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) {
|
||||
if (callback instanceof EncryptionKeyCallback) {
|
||||
EncryptionKeyCallback keyCallback = (EncryptionKeyCallback) callback;
|
||||
if (keyCallback.getRequest() instanceof EncryptionKeyCallback.AliasX509CertificateRequest) {
|
||||
EncryptionKeyCallback.AliasX509CertificateRequest request =
|
||||
(EncryptionKeyCallback.AliasX509CertificateRequest) keyCallback.getRequest();
|
||||
assertEquals("Invalid alias", "", request.getAlias());
|
||||
request.setX509Certificate(certificate);
|
||||
}
|
||||
else {
|
||||
fail("Unexpected request");
|
||||
}
|
||||
}
|
||||
else {
|
||||
fail("Unexpected callback");
|
||||
}
|
||||
}
|
||||
};
|
||||
interceptor.setCallbackHandler(handler);
|
||||
interceptor.afterPropertiesSet();
|
||||
SaajSoapMessage message = loadSaajMessage("empty-soap.xml");
|
||||
interceptor.secureMessage(message, null);
|
||||
SOAPMessage result = message.getSaajMessage();
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathExists("BinarySecurityToken does not exist",
|
||||
"SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:BinarySecurityToken", result);
|
||||
assertXpathExists("Signature does not exist",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/xenc:EncryptedKey", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncryptAlias() throws Exception {
|
||||
interceptor.setPolicyConfiguration(new ClassPathResource("encrypt-alias-config.xml", getClass()));
|
||||
CallbackHandler handler = new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) {
|
||||
if (callback instanceof EncryptionKeyCallback) {
|
||||
EncryptionKeyCallback keyCallback = (EncryptionKeyCallback) callback;
|
||||
if (keyCallback.getRequest() instanceof EncryptionKeyCallback.AliasX509CertificateRequest) {
|
||||
EncryptionKeyCallback.AliasX509CertificateRequest request =
|
||||
(EncryptionKeyCallback.AliasX509CertificateRequest) keyCallback.getRequest();
|
||||
assertEquals("Invalid alias", "alias", request.getAlias());
|
||||
request.setX509Certificate(certificate);
|
||||
}
|
||||
else {
|
||||
fail("Unexpected request");
|
||||
}
|
||||
}
|
||||
else {
|
||||
fail("Unexpected callback");
|
||||
}
|
||||
}
|
||||
};
|
||||
interceptor.setCallbackHandler(handler);
|
||||
interceptor.afterPropertiesSet();
|
||||
SaajSoapMessage message = loadSaajMessage("empty-soap.xml");
|
||||
interceptor.secureMessage(message, null);
|
||||
SOAPMessage result = message.getSaajMessage();
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathExists("BinarySecurityToken does not exist",
|
||||
"SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:BinarySecurityToken", result);
|
||||
assertXpathExists("Signature does not exist",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/xenc:EncryptedKey", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecrypt() throws Exception {
|
||||
interceptor.setPolicyConfiguration(new ClassPathResource("decrypt-config.xml", getClass()));
|
||||
CallbackHandler handler = new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) {
|
||||
if (callback instanceof DecryptionKeyCallback) {
|
||||
DecryptionKeyCallback keyCallback = (DecryptionKeyCallback) callback;
|
||||
if (keyCallback.getRequest() instanceof DecryptionKeyCallback.X509CertificateBasedRequest) {
|
||||
DecryptionKeyCallback.X509CertificateBasedRequest request =
|
||||
(DecryptionKeyCallback.X509CertificateBasedRequest) keyCallback.getRequest();
|
||||
assertEquals("Invalid certificate", certificate, request.getX509Certificate());
|
||||
request.setPrivateKey(privateKey);
|
||||
}
|
||||
else {
|
||||
fail("Unexpected request");
|
||||
}
|
||||
}
|
||||
else {
|
||||
fail("Unexpected callback");
|
||||
}
|
||||
}
|
||||
};
|
||||
interceptor.setCallbackHandler(handler);
|
||||
interceptor.afterPropertiesSet();
|
||||
SaajSoapMessage message = loadSaajMessage("encrypted-soap.xml");
|
||||
interceptor.validateMessage(message, null);
|
||||
SOAPMessage result = message.getSaajMessage();
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security", result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.xwss;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.xml.soap.SOAPMessage;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessage;
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
|
||||
import com.sun.xml.wss.impl.callback.SignatureKeyCallback;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class XwssMessageInterceptorSignTest extends AbstractXwssMessageInterceptorKeyStoreTestCase {
|
||||
|
||||
@Test
|
||||
public void testSignDefaultCertificate() throws Exception {
|
||||
interceptor.setPolicyConfiguration(new ClassPathResource("sign-config.xml", getClass()));
|
||||
CallbackHandler handler = new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) {
|
||||
if (callback instanceof SignatureKeyCallback) {
|
||||
SignatureKeyCallback keyCallback = (SignatureKeyCallback) callback;
|
||||
if (keyCallback.getRequest() instanceof SignatureKeyCallback.DefaultPrivKeyCertRequest) {
|
||||
SignatureKeyCallback.DefaultPrivKeyCertRequest request =
|
||||
(SignatureKeyCallback.DefaultPrivKeyCertRequest) keyCallback.getRequest();
|
||||
request.setX509Certificate(certificate);
|
||||
request.setPrivateKey(privateKey);
|
||||
}
|
||||
else {
|
||||
fail("Unexpected request");
|
||||
}
|
||||
}
|
||||
else {
|
||||
fail("Unexpected callback");
|
||||
}
|
||||
}
|
||||
};
|
||||
interceptor.setCallbackHandler(handler);
|
||||
interceptor.afterPropertiesSet();
|
||||
SaajSoapMessage message = loadSaajMessage("empty-soap.xml");
|
||||
interceptor.secureMessage(message, null);
|
||||
SOAPMessage result = message.getSaajMessage();
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathExists("BinarySecurityToken does not exist",
|
||||
"SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:BinarySecurityToken", result);
|
||||
assertXpathExists("Signature does not exist", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/ds:Signature",
|
||||
result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSignAlias() throws Exception {
|
||||
interceptor.setPolicyConfiguration(new ClassPathResource("sign-alias-config.xml", getClass()));
|
||||
CallbackHandler handler = new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) {
|
||||
if (callback instanceof SignatureKeyCallback) {
|
||||
SignatureKeyCallback keyCallback = (SignatureKeyCallback) callback;
|
||||
if (keyCallback.getRequest() instanceof SignatureKeyCallback.AliasPrivKeyCertRequest) {
|
||||
SignatureKeyCallback.AliasPrivKeyCertRequest request =
|
||||
(SignatureKeyCallback.AliasPrivKeyCertRequest) keyCallback.getRequest();
|
||||
assertEquals("Invalid alias", "alias", request.getAlias());
|
||||
request.setX509Certificate(certificate);
|
||||
request.setPrivateKey(privateKey);
|
||||
}
|
||||
else {
|
||||
fail("Unexpected request");
|
||||
}
|
||||
}
|
||||
else {
|
||||
fail("Unexpected callback");
|
||||
}
|
||||
}
|
||||
};
|
||||
interceptor.setCallbackHandler(handler);
|
||||
interceptor.afterPropertiesSet();
|
||||
SaajSoapMessage message = loadSaajMessage("empty-soap.xml");
|
||||
interceptor.secureMessage(message, null);
|
||||
SOAPMessage result = message.getSaajMessage();
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathExists("BinarySecurityToken does not exist",
|
||||
"SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:BinarySecurityToken", result);
|
||||
assertXpathExists("Signature does not exist", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/ds:Signature",
|
||||
result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCertificate() throws Exception {
|
||||
interceptor.setPolicyConfiguration(new ClassPathResource("requireSignature-config.xml", getClass()));
|
||||
CallbackHandler handler = new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) {
|
||||
if (callback instanceof CertificateValidationCallback) {
|
||||
CertificateValidationCallback validationCallback = (CertificateValidationCallback) callback;
|
||||
validationCallback.setValidator(new CertificateValidationCallback.CertificateValidator() {
|
||||
public boolean validate(X509Certificate passedCertificate) {
|
||||
assertEquals("Invalid certificate", certificate, passedCertificate);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
fail("Unexpected callback");
|
||||
}
|
||||
}
|
||||
};
|
||||
interceptor.setCallbackHandler(handler);
|
||||
interceptor.afterPropertiesSet();
|
||||
SaajSoapMessage message = loadSaajMessage("signed-soap.xml");
|
||||
interceptor.validateMessage(message, null);
|
||||
SOAPMessage result = message.getSaajMessage();
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security", result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* 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.xwss;
|
||||
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.xml.soap.SOAPMessage;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessage;
|
||||
import org.springframework.ws.soap.security.callback.AbstractCallbackHandler;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.PasswordCallback;
|
||||
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
|
||||
import com.sun.xml.wss.impl.callback.TimestampValidationCallback;
|
||||
import com.sun.xml.wss.impl.callback.UsernameCallback;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class XwssMessageInterceptorUsernameTokenTest extends AbstractXwssMessageInterceptorTestCase {
|
||||
|
||||
|
||||
@Test
|
||||
public void testAddUsernameTokenDigest() throws Exception {
|
||||
interceptor.setPolicyConfiguration(new ClassPathResource("usernameToken-digest-config.xml", getClass()));
|
||||
CallbackHandler handler = new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) {
|
||||
if (callback instanceof UsernameCallback) {
|
||||
((UsernameCallback) callback).setUsername("Bert");
|
||||
}
|
||||
else if (callback instanceof PasswordCallback) {
|
||||
PasswordCallback passwordCallback = (PasswordCallback) callback;
|
||||
passwordCallback.setPassword("Ernie");
|
||||
}
|
||||
else {
|
||||
fail("Unexpected callback");
|
||||
}
|
||||
}
|
||||
};
|
||||
interceptor.setCallbackHandler(handler);
|
||||
interceptor.afterPropertiesSet();
|
||||
SaajSoapMessage message = loadSaajMessage("empty-soap.xml");
|
||||
interceptor.secureMessage(message, null);
|
||||
SOAPMessage result = message.getSaajMessage();
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathEvaluatesTo("Invalid Username", "Bert",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Username/text()",
|
||||
result);
|
||||
assertXpathExists("Password does not exist",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Password[@Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest']",
|
||||
result);
|
||||
assertXpathExists("Nonce does not exist",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Nonce",
|
||||
result);
|
||||
assertXpathExists("Created does not exist",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsu:Created",
|
||||
result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddUsernameTokenPlainText() throws Exception {
|
||||
interceptor.setPolicyConfiguration(new ClassPathResource("usernameToken-plainText-config.xml", getClass()));
|
||||
CallbackHandler handler = new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) {
|
||||
if (callback instanceof UsernameCallback) {
|
||||
((UsernameCallback) callback).setUsername("Bert");
|
||||
}
|
||||
else if (callback instanceof PasswordCallback) {
|
||||
PasswordCallback passwordCallback = (PasswordCallback) callback;
|
||||
passwordCallback.setPassword("Ernie");
|
||||
}
|
||||
else {
|
||||
fail("Unexpected callback");
|
||||
}
|
||||
}
|
||||
};
|
||||
interceptor.setCallbackHandler(handler);
|
||||
interceptor.afterPropertiesSet();
|
||||
SaajSoapMessage message = loadSaajMessage("empty-soap.xml");
|
||||
interceptor.secureMessage(message, null);
|
||||
SOAPMessage result = message.getSaajMessage();
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathEvaluatesTo("Invalid Username", "Bert",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Username/text()", result);
|
||||
assertXpathEvaluatesTo("Invalid Password", "Ernie",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Password[@Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText']/text()",
|
||||
result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddUsernameTokenPlainTextNonce() throws Exception {
|
||||
interceptor.setPolicyConfiguration(
|
||||
new ClassPathResource("usernameToken-plainText-nonce-config.xml",
|
||||
getClass()));
|
||||
CallbackHandler handler = new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) {
|
||||
if (callback instanceof UsernameCallback) {
|
||||
((UsernameCallback) callback).setUsername("Bert");
|
||||
}
|
||||
else if (callback instanceof PasswordCallback) {
|
||||
PasswordCallback passwordCallback = (PasswordCallback) callback;
|
||||
passwordCallback.setPassword("Ernie");
|
||||
}
|
||||
else {
|
||||
fail("Unexpected callback");
|
||||
}
|
||||
}
|
||||
};
|
||||
interceptor.setCallbackHandler(handler);
|
||||
interceptor.afterPropertiesSet();
|
||||
SaajSoapMessage message = loadSaajMessage("empty-soap.xml");
|
||||
interceptor.secureMessage(message, null);
|
||||
SOAPMessage result = message.getSaajMessage();
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathEvaluatesTo("Invalid Username", "Bert",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Username/text()",
|
||||
result);
|
||||
assertXpathEvaluatesTo("Invalid Password", "Ernie",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Password[@Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText']/text()",
|
||||
result);
|
||||
assertXpathExists("Nonce does not exist",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsse:Nonce",
|
||||
result);
|
||||
assertXpathExists("Created does not exist",
|
||||
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/wsse:UsernameToken/wsu:Created",
|
||||
result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateUsernameTokenPlainText() throws Exception {
|
||||
interceptor
|
||||
.setPolicyConfiguration(new ClassPathResource("requireUsernameToken-plainText-config.xml", getClass()));
|
||||
CallbackHandler handler = new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) {
|
||||
if (callback instanceof PasswordValidationCallback) {
|
||||
PasswordValidationCallback validationCallback = (PasswordValidationCallback) callback;
|
||||
validationCallback.setValidator(new PasswordValidationCallback.PasswordValidator() {
|
||||
public boolean validate(PasswordValidationCallback.Request request) {
|
||||
if (request instanceof PasswordValidationCallback.PlainTextPasswordRequest) {
|
||||
PasswordValidationCallback.PlainTextPasswordRequest passwordRequest =
|
||||
(PasswordValidationCallback.PlainTextPasswordRequest) request;
|
||||
assertEquals("Invalid username", "Bert", passwordRequest.getUsername());
|
||||
assertEquals("Invalid password", "Ernie", passwordRequest.getPassword());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
fail("Unexpected request");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
fail("Unexpected callback");
|
||||
}
|
||||
}
|
||||
};
|
||||
interceptor.setCallbackHandler(handler);
|
||||
interceptor.afterPropertiesSet();
|
||||
SaajSoapMessage message = loadSaajMessage("usernameTokenPlainText-soap.xml");
|
||||
interceptor.validateMessage(message, null);
|
||||
SOAPMessage result = message.getSaajMessage();
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateUsernameTokenPlainTextNonce() throws Exception {
|
||||
interceptor
|
||||
.setPolicyConfiguration(new ClassPathResource("requireUsernameToken-plainText-nonce-config.xml", getClass()));
|
||||
CallbackHandler handler = new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) {
|
||||
if (callback instanceof PasswordValidationCallback) {
|
||||
PasswordValidationCallback validationCallback = (PasswordValidationCallback) callback;
|
||||
validationCallback.setValidator(new PasswordValidationCallback.PasswordValidator() {
|
||||
public boolean validate(PasswordValidationCallback.Request request) {
|
||||
if (request instanceof PasswordValidationCallback.PlainTextPasswordRequest) {
|
||||
PasswordValidationCallback.PlainTextPasswordRequest passwordRequest =
|
||||
(PasswordValidationCallback.PlainTextPasswordRequest) request;
|
||||
assertEquals("Invalid username", "Bert", passwordRequest.getUsername());
|
||||
assertEquals("Invalid password", "Ernie", passwordRequest.getPassword());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
fail("Unexpected request");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (callback instanceof TimestampValidationCallback) {
|
||||
TimestampValidationCallback validationCallback = (TimestampValidationCallback) callback;
|
||||
validationCallback.setValidator(new TimestampValidationCallback.TimestampValidator() {
|
||||
public void validate(TimestampValidationCallback.Request request) {
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
fail("Unexpected callback");
|
||||
}
|
||||
}
|
||||
};
|
||||
interceptor.setCallbackHandler(handler);
|
||||
interceptor.afterPropertiesSet();
|
||||
SaajSoapMessage message = loadSaajMessage("usernameTokenPlainText-nonce-soap.xml");
|
||||
interceptor.validateMessage(message, null);
|
||||
SOAPMessage result = message.getSaajMessage();
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateUsernameTokenDigest() throws Exception {
|
||||
interceptor.setPolicyConfiguration(new ClassPathResource("requireUsernameToken-digest-config.xml", getClass()));
|
||||
CallbackHandler handler = new AbstractCallbackHandler() {
|
||||
|
||||
@Override
|
||||
protected void handleInternal(Callback callback) {
|
||||
if (callback instanceof PasswordValidationCallback) {
|
||||
PasswordValidationCallback validationCallback = (PasswordValidationCallback) callback;
|
||||
if (validationCallback.getRequest() instanceof PasswordValidationCallback.DigestPasswordRequest) {
|
||||
PasswordValidationCallback.DigestPasswordRequest passwordRequest =
|
||||
(PasswordValidationCallback.DigestPasswordRequest) validationCallback.getRequest();
|
||||
assertEquals("Invalid username", "Bert", passwordRequest.getUsername());
|
||||
passwordRequest.setPassword("Ernie");
|
||||
validationCallback.setValidator(new PasswordValidationCallback.DigestPasswordValidator());
|
||||
}
|
||||
else {
|
||||
fail("Unexpected request");
|
||||
}
|
||||
}
|
||||
else if (callback instanceof TimestampValidationCallback) {
|
||||
TimestampValidationCallback validationCallback = (TimestampValidationCallback) callback;
|
||||
validationCallback.setValidator(new TimestampValidationCallback.TimestampValidator() {
|
||||
public void validate(TimestampValidationCallback.Request request) {
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
fail("Unexpected callback");
|
||||
}
|
||||
}
|
||||
};
|
||||
interceptor.setCallbackHandler(handler);
|
||||
interceptor.afterPropertiesSet();
|
||||
SaajSoapMessage message = loadSaajMessage("usernameTokenDigest-soap.xml");
|
||||
interceptor.validateMessage(message, null);
|
||||
SOAPMessage result = message.getSaajMessage();
|
||||
assertNotNull("No result returned", result);
|
||||
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security", result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.xwss.callback;
|
||||
|
||||
import com.sun.xml.wss.impl.callback.TimestampValidationCallback;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DefaultTimestampValidatorTest {
|
||||
|
||||
private DefaultTimestampValidator validator;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
validator = new DefaultTimestampValidator();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidate() throws Exception {
|
||||
TimestampValidationCallback.Request request = new TimestampValidationCallback.UTCTimestampRequest(
|
||||
"2006-09-25T20:42:50Z", "2107-09-25T20:42:50Z", 100, Long.MAX_VALUE);
|
||||
validator.validate(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateNoExpired() throws Exception {
|
||||
TimestampValidationCallback.Request request =
|
||||
new TimestampValidationCallback.UTCTimestampRequest("2006-09-25T20:42:50Z", null, 100, Long.MAX_VALUE);
|
||||
validator.validate(request);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user