Moved Spring-WS to separate dir.

This commit is contained in:
Arjen Poutsma
2006-09-24 19:22:56 +00:00
commit 66d3aef26c
623 changed files with 44122 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
log4j.rootCategory=INFO, stdout
log4j.logger.org.springframework.ws=DEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n

View File

@@ -0,0 +1,6 @@
PlainText {
org.springframework.ws.soap.security.xwss.callback.jaas.PlainTextLoginModule Required;
};
Certificate {
org.springframework.ws.soap.security.xwss.callback.jaas.CertificateLoginModule Required;
};

View File

@@ -0,0 +1,3 @@
<xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:RequireEncryption />
</xwss:SecurityConfiguration>

View File

@@ -0,0 +1,5 @@
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<tru:StockSymbol xmlns:tru="http://fabrikam123.com/payloads">QQQ</tru:StockSymbol>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

View File

@@ -0,0 +1,5 @@
<xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:Encrypt>
<xwss:X509Token certificateAlias="alias"/>
</xwss:Encrypt>
</xwss:SecurityConfiguration>

View File

@@ -0,0 +1,3 @@
<xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:Encrypt />
</xwss:SecurityConfiguration>

View File

@@ -0,0 +1,22 @@
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" SOAP-ENV:mustUnderstand="1"><wsse:BinarySecurityToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="XWSSGID-1149204674680-1346390970" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">MIICXDCCAcUCBER/bZ8wDQYJKoZIhvcNAQEEBQAwdTELMAkGA1UEBhMCTkwxEDAOBgNVBAgTB1Vu
a25vd24xEjAQBgNVBAcTCUFtc3RlcmRhbTEUMBIGA1UEChMLSW50ZXJmYWNlMjExEjAQBgNVBAsT
CVNwcmluZy1XUzEWMBQGA1UEAxMNQXJqZW4gUG91dHNtYTAeFw0wNjA2MDEyMjQzNDNaFw0wNjA4
MzAyMjQzNDNaMHUxCzAJBgNVBAYTAk5MMRAwDgYDVQQIEwdVbmtub3duMRIwEAYDVQQHEwlBbXN0
ZXJkYW0xFDASBgNVBAoTC0ludGVyZmFjZTIxMRIwEAYDVQQLEwlTcHJpbmctV1MxFjAUBgNVBAMT
DUFyamVuIFBvdXRzbWEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOVGA4N3bkrJhTUq/6ol
S85RAueC4QpSKlc7Ppg84f/TQZkMpAEKx/NGZq/SlqUqjYS9OSu+2xVTju/svAYcIarVvxlUfIfL
Ua4l/6ETS/bJCxZFiKiHhSjAQ9+CZOjMn4z0IzXMzM+9yqpDlJd1cRilbIVZ4GEsutWR74DoBRYB
AgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAEi9JV6Rdq9gYO9l1FjegS78SHTbKBp614fU2V9op0ArB
1iUiBjteBfELIpjIbd36lkdwsgHmK8lusNRYiwAFptkQffQPJq4F4xCv5wVLkhr1qkY9vgmCjevJ
VQK9W6ggUMHEtwiWCnLuPcUe8k3hnCmqNv5CtcKv4QduvrHPrR8=</wsse:BinarySecurityToken><xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"/><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<wsse:SecurityTokenReference>
<wsse:Reference URI="#XWSSGID-1149204674680-1346390970" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"/>
</wsse:SecurityTokenReference>
</ds:KeyInfo><xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:CipherValue xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">EaldhRqsjjckrksnrNlmwbco1MmG/cIe5U21zs8e1fOtx2yvLEP//ZeEDyiZb6qQJ/nlbs5XQriv
oHnI8BrXnWFADJijWQm3WSNxoSvUn3NOOjTj+qjlM0YG3CW2/19ZZLrj0XRiKJyCZXj0fYM+xODr
PY70j2YZcIAaH3dtLAs=</xenc:CipherValue></xenc:CipherData><xenc:ReferenceList xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:DataReference URI="#XWSSGID-1149204675657-83290958"/></xenc:ReferenceList></xenc:EncryptedKey></wsse:Security></SOAP-ENV:Header><SOAP-ENV:Body><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="XWSSGID-1149204675657-83290958" Type="http://www.w3.org/2001/04/xmlenc#Content"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"/><xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:CipherValue xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">pOPYwI954LnKSTn1iHJthTlli3m8grr+AfElSNY3mJus0CtKb+Hr+/yThIA7hkqXGYGYx3ReoKcK
J+auHXeC2llvcs8kMTZTRLxZl7/qLwWuWX0dBAmBpwXaJy0RXhx5kNr0CWDl0g6Qm4p1VRlnHWNc
YXwt4x70RthlVlX6RczAdcthlLZdXqpEjqKQ11zQ9aXFTPFL+1H8gSvSflTOOUg95fPFPZCR</xenc:CipherValue></xenc:CipherData></xenc:EncryptedData></SOAP-ENV:Body>
</SOAP-ENV:Envelope>

View File

@@ -0,0 +1,3 @@
<xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:RequireSignature requireTimestamp="false"/>
</xwss:SecurityConfiguration>

View File

@@ -0,0 +1,3 @@
<xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:RequireUsernameToken passwordDigestRequired="true" nonceRequired="true"/>
</xwss:SecurityConfiguration>

View File

@@ -0,0 +1,3 @@
<xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:RequireUsernameToken passwordDigestRequired="false" nonceRequired="false"/>
</xwss:SecurityConfiguration>

View File

@@ -0,0 +1,5 @@
<xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:Sign includeTimestamp="false">
<xwss:X509Token certificateAlias="alias"/>
</xwss:Sign>
</xwss:SecurityConfiguration>

View File

@@ -0,0 +1,3 @@
<xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:Sign includeTimestamp="false" />
</xwss:SecurityConfiguration>

View File

@@ -0,0 +1,20 @@
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" SOAP-ENV:mustUnderstand="1"><wsse:BinarySecurityToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="XWSSGID-1149203416758-1792263386" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">MIICXDCCAcUCBER/bZ8wDQYJKoZIhvcNAQEEBQAwdTELMAkGA1UEBhMCTkwxEDAOBgNVBAgTB1Vu
a25vd24xEjAQBgNVBAcTCUFtc3RlcmRhbTEUMBIGA1UEChMLSW50ZXJmYWNlMjExEjAQBgNVBAsT
CVNwcmluZy1XUzEWMBQGA1UEAxMNQXJqZW4gUG91dHNtYTAeFw0wNjA2MDEyMjQzNDNaFw0wNjA4
MzAyMjQzNDNaMHUxCzAJBgNVBAYTAk5MMRAwDgYDVQQIEwdVbmtub3duMRIwEAYDVQQHEwlBbXN0
ZXJkYW0xFDASBgNVBAoTC0ludGVyZmFjZTIxMRIwEAYDVQQLEwlTcHJpbmctV1MxFjAUBgNVBAMT
DUFyamVuIFBvdXRzbWEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOVGA4N3bkrJhTUq/6ol
S85RAueC4QpSKlc7Ppg84f/TQZkMpAEKx/NGZq/SlqUqjYS9OSu+2xVTju/svAYcIarVvxlUfIfL
Ua4l/6ETS/bJCxZFiKiHhSjAQ9+CZOjMn4z0IzXMzM+9yqpDlJd1cRilbIVZ4GEsutWR74DoBRYB
AgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAEi9JV6Rdq9gYO9l1FjegS78SHTbKBp614fU2V9op0ArB
1iUiBjteBfELIpjIbd36lkdwsgHmK8lusNRYiwAFptkQffQPJq4F4xCv5wVLkhr1qkY9vgmCjevJ
VQK9W6ggUMHEtwiWCnLuPcUe8k3hnCmqNv5CtcKv4QduvrHPrR8=</wsse:BinarySecurityToken><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><InclusiveNamespaces xmlns="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="wsse SOAP-ENV"/></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="#XWSSGID-1149203417054-305519969"><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>/ewlu0ecAQ2DsEJqDcM4AT6oWPE=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>ihZA0zibv/mSMKWb0lc6sXJmA+Tp12ku26mhh2/2QlScm6/eKBopUcskEOlLNVL5LLhvTBa+fNVw
XVAQKnYyKY2hG5Bsqc+1/Ec6eoN7H9dCbBbwDOdU/H7qV9NFJprLu98tUtPTbBT4IRtnNV5NWKYT
odKKjip/W0n1Hz/ym9I=</ds:SignatureValue><ds:KeyInfo><wsse:SecurityTokenReference xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="XWSSGID-1149203416754902281749">
<wsse:Reference URI="#XWSSGID-1149203416758-1792263386" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"/>
</wsse:SecurityTokenReference></ds:KeyInfo></ds:Signature></wsse:Security></SOAP-ENV:Header><SOAP-ENV:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="XWSSGID-1149203417054-305519969">
<tru:StockSymbol xmlns:tru="http://fabrikam123.com/payloads">QQQ</tru:StockSymbol>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

View File

@@ -0,0 +1,3 @@
<xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:UsernameToken digestPassword="true" useNonce="true"/>
</xwss:SecurityConfiguration>

View File

@@ -0,0 +1,3 @@
<xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:UsernameToken digestPassword="false" useNonce="false"/>
</xwss:SecurityConfiguration>

View File

@@ -0,0 +1,6 @@
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" SOAP-ENV:mustUnderstand="1"><wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="XWSSGID-1149205720423-1352053129" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsse:Username>Bert</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">kwNstEaiFOrI7B31j7GuETYvdgk=</wsse:Password><wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">9mdsYDCrjjYRur0rxzYt2oD7</wsse:Nonce><wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2006-06-01T23:48:42Z</wsu:Created></wsse:UsernameToken></wsse:Security></SOAP-ENV:Header><SOAP-ENV:Body>
<tru:StockSymbol xmlns:tru="http://fabrikam123.com/payloads">QQQ</tru:StockSymbol>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

View File

@@ -0,0 +1,19 @@
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
SOAP-ENV:mustUnderstand="1">
<wsse:UsernameToken
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="XWSSGID-1149200055993710197275"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>Bert</wsse:Username>
<wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"
>Ernie</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<tru:StockSymbol xmlns:tru="http://fabrikam123.com/payloads">QQQ</tru:StockSymbol>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

View File

@@ -0,0 +1,136 @@
/*
* 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 java.util.Locale;
import javax.xml.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapEndpointInterceptor;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.SoapBody;
import org.springframework.ws.soap.context.SoapMessageContext;
/**
* Interceptor base class for interceptors that handle WS-Security.
* <p/>
* Subclasses of this base class can be configured to validate incoming and secure outgoing messages. By default, both
* are on.
*
* @author Arjen Poutsma
*/
public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInterceptor {
/**
* Logger available to subclasses.
*/
private final Log logger = LogFactory.getLog(getClass());
private boolean validateRequest = true;
private boolean secureResponse = true;
private 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");
/**
* Indicates whether outgoing responsed are to be secured. Defaults to <code>true</code>.
*/
public void setSecureResponse(boolean secureResponse) {
this.secureResponse = secureResponse;
}
/**
* Indicates whether incoming request are to be validated. Defaults to <code>true</code>.
*/
public void setValidateRequest(boolean validateRequest) {
this.validateRequest = validateRequest;
}
public final boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
if (validateRequest) {
Assert.isTrue(messageContext instanceof SoapMessageContext,
"WsSecurityInterceptor requires a SoapMessageContext");
SoapMessageContext soapMessageContext = (SoapMessageContext) messageContext;
try {
validateRequest(soapMessageContext);
return true;
}
catch (WsSecurityValidationException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Could not validate request: " + ex.getMessage());
}
SoapBody response = soapMessageContext.getSoapResponse().getSoapBody();
response.addClientOrSenderFault(ex.getMessage(), Locale.ENGLISH);
return false;
}
}
else {
return true;
}
}
public final boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
if (secureResponse) {
Assert.isTrue(messageContext instanceof SoapMessageContext,
"WsSecurityInterceptor requires a SoapMessageContext");
SoapMessageContext soapMessageContext = (SoapMessageContext) messageContext;
try {
secureResponse(soapMessageContext);
return true;
}
catch (WsSecuritySecurementException ex) {
if (logger.isErrorEnabled()) {
logger.error("Could not secure response: " + ex.getMessage(), ex);
}
return false;
}
}
else {
return true;
}
}
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
return true;
}
/**
* Abstract template method. Subclasses are required to validate the request contained in the given
* <code>SoapMessageContext</code>, and replace the original request with the validated version.
*
* @param messageContext the soap message context
* @throws WsSecurityValidationException in case of validation errors
*/
protected abstract void validateRequest(SoapMessageContext messageContext) throws WsSecurityValidationException;
/**
* Abstract template method. Subclasses are required to secure the response contained in the given
* <code>SoapMessageContext</code>, and replace the original response with the secured version.
*
* @param messageContext the soap message context
* @throws WsSecuritySecurementException in case of securement errors
*/
protected abstract void secureResponse(SoapMessageContext messageContext) throws WsSecuritySecurementException;
public boolean understands(SoapHeaderElement headerElement) {
return WS_SECURITY_NAME.equals(headerElement.getName());
}
}

View File

@@ -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;
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
*/
public abstract class WsSecurityException extends WebServiceException {
public WsSecurityException(String msg) {
super(msg);
}
public WsSecurityException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -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;
/**
* 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
*/
public abstract class WsSecuritySecurementException extends WsSecurityException {
public WsSecuritySecurementException(String msg) {
super(msg);
}
public WsSecuritySecurementException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -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;
/**
* 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
*/
public abstract class WsSecurityValidationException extends WsSecurityException {
public WsSecurityValidationException(String msg) {
super(msg);
}
public WsSecurityValidationException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Provided WS-Security implementation classes. Contains the <code>AbstractWsSecurityInterceptor</code> and exceptions.
</body>
</html>

View File

@@ -0,0 +1,131 @@
/*
* 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.support;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
/**
* Spring factory bean for a <code>java.security.KeyStore</code>.
* <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)
*/
public class KeyStoreFactoryBean implements FactoryBean, 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 Object getObject() throws Exception {
return keyStore;
}
public Class 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();
}
}
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Contains support classes for handling WS-Security messages.
</body>
</html>

View File

@@ -0,0 +1,172 @@
/*
* 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 java.io.InputStream;
import javax.security.auth.callback.CallbackHandler;
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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.ws.soap.context.SoapMessageContext;
import org.springframework.ws.soap.saaj.SaajSoapMessageContext;
import org.springframework.ws.soap.security.AbstractWsSecurityInterceptor;
import org.springframework.ws.soap.security.xwss.callback.CallbackHandlerChain;
/**
* 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>SaajSoapMessageContextFactory</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.SaajSoapMessageContextFactory
* @see <a href="https://xwss.dev.java.net/">XWSS</a>
*/
public class XwsSecurityInterceptor extends AbstractWsSecurityInterceptor implements InitializingBean {
private static final Log logger = LogFactory.getLog(XwsSecurityInterceptor.class);
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 CallbackHandlerChain(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.getFilename() + "'");
}
is = policyConfiguration.getInputStream();
processor = processorFactory.createProcessorForSecurityConfiguration(is, callbackHandler);
}
finally {
if (is != null) {
is.close();
}
}
}
protected void secureResponse(SoapMessageContext soapMessageContext) throws XwsSecuritySecurementException {
Assert.isTrue(soapMessageContext instanceof SaajSoapMessageContext,
"XwsSecurityInterceptor requires a SaajSoapMessageContext. " +
"Use a SaajSoapMessageContextFactory to create the SOAP messages.");
SaajSoapMessageContext saajMessageContext = (SaajSoapMessageContext) soapMessageContext;
SOAPMessage securedMessage = secureMessage(saajMessageContext.getSaajResponse());
saajMessageContext.setSaajResponse(securedMessage);
}
protected void validateRequest(SoapMessageContext soapMessageContext) throws XwsSecurityValidationException {
Assert.isTrue(soapMessageContext instanceof SaajSoapMessageContext,
"XwsSecurityInterceptor requires a SaajSoapMessageContext" +
"Use a SaajSoapMessageContextFactory to create the SOAP messages.");
SaajSoapMessageContext saajMessageContext = (SaajSoapMessageContext) soapMessageContext;
SOAPMessage validatedMessage = validateMessage(saajMessageContext.getSaajRequest());
saajMessageContext.setSaajRequest(validatedMessage);
}
/**
* Secures the given SAAJ message in accordance with the defined security policy and returns the secured result.
*
* @param message the message to be secured
* @return the secured message
* @throws XwsSecuritySecurementException in case of errors
*/
protected SOAPMessage secureMessage(SOAPMessage message) throws XwsSecuritySecurementException {
try {
ProcessingContext context = processor.createProcessingContext(message);
return processor.secureOutboundMessage(context);
}
catch (XWSSecurityException ex) {
throw new XwsSecuritySecurementException(ex.getMessage(), ex);
}
}
/**
* Validates the given SAAJ message in accordance with the defined security policy and returns the validated
* result.
*
* @param message the message to be validated
* @return the validated message
* @throws XwsSecurityValidationException in case of errors
*/
protected SOAPMessage validateMessage(SOAPMessage message) throws XwsSecurityValidationException {
try {
ProcessingContext context = processor.createProcessingContext(message);
return processor.verifyInboundMessage(context);
}
catch (XWSSecurityException ex) {
throw new XwsSecurityValidationException(ex.getMessage(), ex);
}
}
}

View File

@@ -0,0 +1,30 @@
/*
* 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;
public class XwsSecuritySecurementException extends WsSecuritySecurementException {
public XwsSecuritySecurementException(String msg) {
super(msg);
}
public XwsSecuritySecurementException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,30 @@
/*
* 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;
public class XwsSecurityValidationException extends WsSecurityValidationException {
public XwsSecurityValidationException(String msg) {
super(msg);
}
public XwsSecurityValidationException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,59 @@
/*
* 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.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
*/
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 (int i = 0; i < callbacks.length; i++) {
handleInternal(callbacks[i]);
}
}
/**
* Template method that should be implemented by subclasses.
*/
protected abstract void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException;
}

View File

@@ -0,0 +1,175 @@
/*
* 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.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;
/**
* 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
*/
public class CallbackHandlerChain extends AbstractCallbackHandler {
private CallbackHandler[] callbackHandlers;
public CallbackHandlerChain(CallbackHandler[] callbackHandlers) {
this.callbackHandlers = callbackHandlers;
}
public void setCallbackHandlers(CallbackHandler[] callbackHandlers) {
this.callbackHandlers = callbackHandlers;
}
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 {
boolean allUnsupported = true;
for (int i = 0; i < callbackHandlers.length; i++) {
CallbackHandler callbackHandler = callbackHandlers[i];
try {
callbackHandler.handle(new Callback[]{callback});
allUnsupported = false;
}
catch (UnsupportedCallbackException ex) {
// if an UnsupportedCallbackException occurs, go to the next handler
}
}
if (allUnsupported) {
throw new UnsupportedCallbackException(callback);
}
}
}
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 < callbackHandlers.length; i++) {
CallbackHandler callbackHandler = callbackHandlers[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 < callbackHandlers.length; i++) {
CallbackHandler callbackHandler = callbackHandlers[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 < callbackHandlers.length; i++) {
CallbackHandler callbackHandler = callbackHandlers[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;
}
}
}

View File

@@ -0,0 +1,492 @@
/*
* 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.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;
/**
* 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
*/
public class CryptographyCallbackHandler extends AbstractCallbackHandler {
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);
}
}

View File

@@ -0,0 +1,131 @@
/*
* 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
*/
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());
Date expired = parseDate(utcRequest.getExpired());
validateCreationTime(created, utcRequest.getMaxClockSkew(), utcRequest.getTimestampFreshnessLimit());
if (expired != null) {
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");
}
}
}

View File

@@ -0,0 +1,772 @@
/*
* 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.io.File;
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 com.sun.org.apache.xml.internal.security.utils.RFC2253Parser;
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.beans.factory.InitializingBean;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
import org.springframework.ws.soap.security.support.KeyStoreFactoryBean;
/**
* 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>
* &lt;bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler"&gt;
* &lt;property name="trustStore" ref="trustStore"/&gt;
* &lt;/bean&gt;
* <p/>
* &lt;bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean"&gt;
* &lt;property name="location" value="classpath:truststore.jks"/&gt;
* &lt;property name="password" value="changeit"/&gt;
* &lt;/bean&gt;
* </pre>
* If you want to use it to decrypt incoming certificates or sign outgoing messages, you would use a key store, like
* so:
* <pre>
* &lt;bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler"&gt;
* &lt;property name="keyStore" ref="keyStore"/&gt;
* &lt;property name="privateKeyPassword" value="changeit"/&gt;
* &lt;/bean&gt;
* <p/>
* &lt;bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean"&gt;
* &lt;property name="location" value="classpath:keystore.jks"/&gt;
* &lt;property name="password" value="changeit"/&gt;
* &lt;/bean&gt;
* </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>
*/
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 aliases = store.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) 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;
}
}
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);
}
protected final void handleAliasSymmetricKeyRequest(DecryptionKeyCallback callback,
DecryptionKeyCallback.AliasSymmetricKeyRequest request)
throws IOException {
SecretKey secretKey = getSymmetricKey(request.getAlias());
request.setSymmetricKey(secretKey);
}
//
// Encryption
//
protected final void handleAliasSymmetricKeyRequest(EncryptionKeyCallback callback,
EncryptionKeyCallback.AliasSymmetricKeyRequest request)
throws IOException {
SecretKey secretKey = getSymmetricKey(request.getAlias());
request.setSymmetricKey(secretKey);
}
protected final void handleAliasX509CertificateRequest(EncryptionKeyCallback callback,
EncryptionKeyCallback.AliasX509CertificateRequest request)
throws IOException {
X509Certificate certificate = getCertificateFromTrustStore(request.getAlias());
request.setX509Certificate(certificate);
}
//
// Certificate validation
//
protected final void handleCertificateValidationCallback(CertificateValidationCallback callback) {
callback.setValidator(new KeyStoreCertificateValidator());
}
//
// Signing
//
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);
}
protected final void handleDefaultX509CertificateRequest(EncryptionKeyCallback callback,
EncryptionKeyCallback.DefaultX509CertificateRequest request)
throws IOException {
X509Certificate certificate = getCertificateFromTrustStore(defaultAlias);
request.setX509Certificate(certificate);
}
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
//
protected final void handlePublicKeyBasedPrivKeyRequest(DecryptionKeyCallback callback,
DecryptionKeyCallback.PublicKeyBasedPrivKeyRequest request)
throws IOException {
PrivateKey key = getPrivateKey(request.getPublicKey());
request.setPrivateKey(key);
}
protected final void handlePublicKeyBasedRequest(EncryptionKeyCallback callback,
EncryptionKeyCallback.PublicKeyBasedRequest request)
throws IOException {
X509Certificate certificate = getCertificateFromTrustStore(request.getPublicKey());
request.setX509Certificate(certificate);
}
protected final void handlePublicKeyBasedRequest(SignatureVerificationKeyCallback callback,
SignatureVerificationKeyCallback.PublicKeyBasedRequest request)
throws IOException {
X509Certificate certificate = getCertificateFromTrustStore(request.getPublicKey());
request.setX509Certificate(certificate);
}
protected final void handleX509CertificateBasedRequest(DecryptionKeyCallback callback,
DecryptionKeyCallback.X509CertificateBasedRequest request)
throws IOException {
PrivateKey privKey = getPrivateKey(request.getX509Certificate());
request.setPrivateKey(privKey);
}
protected final void handleX509IssuerSerialBasedRequest(DecryptionKeyCallback callback,
DecryptionKeyCallback.X509IssuerSerialBasedRequest request)
throws IOException {
PrivateKey key = getPrivateKey(request.getIssuerName(), request.getSerialNumber());
request.setPrivateKey(key);
}
protected final void handleX509IssuerSerialBasedRequest(SignatureVerificationKeyCallback callback,
SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest request)
throws IOException {
X509Certificate certificate = getCertificateFromTrustStore(request.getIssuerName(), request.getSerialNumber());
request.setX509Certificate(certificate);
}
protected final void handleX509SubjectKeyIdentifierBasedRequest(DecryptionKeyCallback callback,
DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest request)
throws IOException {
PrivateKey key = getPrivateKey(request.getSubjectKeyIdentifier());
request.setPrivateKey(key);
}
//
// Signature verification
//
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 aliases = trustStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) 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 aliases = trustStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) 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 aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) 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 aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) 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 aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) 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 aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) 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. 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>
*/
protected void loadDefaultKeyStore() {
Resource location = null;
String type = null;
String password = null;
String locationProperty = System.getProperty("javax.net.ssl.keyStore");
if (StringUtils.hasLength(locationProperty)) {
File f = new File(locationProperty);
if (f.exists() && f.isFile() && f.canRead()) {
location = new FileSystemResource(f);
}
String passwordProperty = System.getProperty("javax.net.ssl.keyStorePassword");
if (StringUtils.hasLength(passwordProperty)) {
password = passwordProperty;
}
type = System.getProperty("javax.net.ssl.trustStore");
}
// use the factory bean here, easier to setup
KeyStoreFactoryBean factoryBean = new KeyStoreFactoryBean();
factoryBean.setLocation(location);
factoryBean.setPassword(password);
factoryBean.setType(type);
try {
factoryBean.afterPropertiesSet();
this.trustStore = (KeyStore) factoryBean.getObject();
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. 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>
*/
protected void loadDefaultTrustStore() {
Resource location = null;
String type = null;
String password = null;
String locationProperty = System.getProperty("javax.net.ssl.trustStore");
if (StringUtils.hasLength(locationProperty)) {
File f = new File(locationProperty);
if (f.exists() && f.isFile() && f.canRead()) {
location = new FileSystemResource(f);
}
String passwordProperty = System.getProperty("javax.net.ssl.trustStorePassword");
if (StringUtils.hasLength(passwordProperty)) {
password = passwordProperty;
}
type = System.getProperty("javax.net.ssl.trustStoreType");
}
else {
String javaHome = System.getProperty("java.home");
location = new FileSystemResource(javaHome + "/lib/security/jssecacerts");
if (!location.exists()) {
location = new FileSystemResource(javaHome + "/lib/security/cacerts");
}
}
// use the factory bean here, easier to setup
KeyStoreFactoryBean factoryBean = new KeyStoreFactoryBean();
factoryBean.setLocation(location);
factoryBean.setPassword(password);
factoryBean.setType(type);
try {
factoryBean.afterPropertiesSet();
this.trustStore = (KeyStore) factoryBean.getObject();
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 aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) 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);
}
}
}
}

View File

@@ -0,0 +1,83 @@
/*
* 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.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;
/**
* 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
*/
public class MockValidationCallbackHandler extends AbstractCallbackHandler {
private boolean isValid = true;
public MockValidationCallbackHandler() {
}
public MockValidationCallbackHandler(boolean valid) {
isValid = valid;
}
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;
}
}
}

View File

@@ -0,0 +1,100 @@
/*
* 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.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
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.util.Assert;
/**
* Simple callback handler that validates passwords agains a in-memory <code>Properties</code> object. Password
* validation is done on a case-sensitive basis.
* <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)
*/
public class SimplePasswordValidationCallbackHandler extends AbstractCallbackHandler implements InitializingBean {
private Properties users = new Properties();
/**
* Sets the users to validate against. Property names are usernames, property values are passwords.
*/
public void setUsers(Properties users) {
this.users = users;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(users, "users is required");
}
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.getProperty(digestPasswordRequest.getUsername());
digestPasswordRequest.setPassword(password);
passwordCallback.setValidator(new PasswordValidationCallback.DigestPasswordValidator());
}
passwordCallback.setValidator(new SimplePlainTextPasswordValidator());
}
else if (callback instanceof TimestampValidationCallback) {
TimestampValidationCallback timestampCallback = (TimestampValidationCallback) callback;
timestampCallback.setValidator(new DefaultTimestampValidator());
}
else {
throw new UnsupportedCallbackException(callback);
}
}
public void setUsersMap(Map users) {
for (Iterator iterator = users.keySet().iterator(); iterator.hasNext();) {
String username = (String) iterator.next();
String password = (String) users.get(username);
this.users.setProperty(username, password);
}
}
private class SimplePlainTextPasswordValidator implements PasswordValidationCallback.PasswordValidator {
public boolean validate(PasswordValidationCallback.Request request)
throws PasswordValidationCallback.PasswordValidationException {
PasswordValidationCallback.PlainTextPasswordRequest plainTextPasswordRequest =
(PasswordValidationCallback.PlainTextPasswordRequest) request;
String password = users.getProperty(plainTextPasswordRequest.getUsername());
return password != null && password.equals(plainTextPasswordRequest.getPassword());
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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.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.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* 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)
*/
public class SimpleUsernamePasswordCallbackHandler extends AbstractCallbackHandler implements InitializingBean {
private String username;
private String 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");
}
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);
}
}
}

View File

@@ -0,0 +1,115 @@
/*
* 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.acegi;
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.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.x509.X509AuthenticationToken;
import org.springframework.util.Assert;
import org.springframework.ws.soap.security.xwss.callback.AbstractCallbackHandler;
/**
* Callback handler that validates a certificate using an Acegi <code>AuthenticationManager</code>. Logic based on
* Acegi's <code>X509ProcessingFilter</code>.
* <p/>
* An Acegi <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 X509AuthenticationToken
* @see org.acegisecurity.providers.x509.X509AuthenticationProvider
* @see org.acegisecurity.ui.x509.X509ProcessingFilter
* @see CertificateValidationCallback
*/
public class AcegiCertificateValidationCallbackHandler extends AbstractCallbackHandler {
private AuthenticationManager authenticationManager;
private boolean ignoreFailure = false;
/**
* Sets the Acegi authentication manager. Required.
*/
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public void setIgnoreFailure(boolean ignoreFailure) {
this.ignoreFailure = ignoreFailure;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(authenticationManager, "authenticationManager is required");
}
/**
* Handles <code>CertificateValidationCallback</code>s, and throws an <code>UnsupportedCallbackException</code> for
* others
*
* @throws UnsupportedCallbackException when the callback is not supported
*/
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
if (callback instanceof CertificateValidationCallback) {
((CertificateValidationCallback) callback).setValidator(new AcegiCertificateValidator());
}
else {
throw new UnsupportedCallbackException(callback);
}
}
private class AcegiCertificateValidator 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.getContext().setAuthentication(null);
result = ignoreFailure;
}
return result;
}
}
}

View File

@@ -0,0 +1,152 @@
/*
* 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.acegi;
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.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.dao.UserCache;
import org.acegisecurity.providers.dao.cache.NullUserCache;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.springframework.util.Assert;
import org.springframework.ws.soap.security.xwss.callback.AbstractCallbackHandler;
import org.springframework.ws.soap.security.xwss.callback.DefaultTimestampValidator;
/**
* Callback handler that validates a password digest using an Acegi <code>UserDetailsService</code>. Logic based on
* Acegi's <code>DigestProcessingFilter</code>.
* <p/>
* An Acegi <code>UserDetailService</code> is used to load <code>UserDetails</code> from. The digest of the password
* contained in this details object is then compared with the digest in the message.
* <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 UserDetailsService
* @see PasswordValidationCallback
* @see com.sun.xml.wss.impl.callback.PasswordValidationCallback.DigestPasswordRequest
* @see org.acegisecurity.ui.digestauth.DigestProcessingFilter
*/
public class AcegiDigestPasswordValidationCallbackHandler extends AbstractCallbackHandler {
private UserCache userCache = new NullUserCache();
private UserDetailsService userDetailsService;
/**
* Sets the users cache. Not required, but can benefit performance.
*/
public void setUserCache(UserCache userCache) {
this.userCache = userCache;
}
/**
* Sets the Acegi user details service. Required.
*/
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(userDetailsService, "userDetailsService is required");
}
/**
* Handles <code>PasswordValidationCallback</code>s that contain a <code>DigestPasswordRequest</code>, and throws an
* <code>UnsupportedCallbackException</code> for others
*
* @throws UnsupportedCallbackException when the callback is not supported
*/
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) {
request.setPassword(user.getPassword());
}
AcegiDigestPasswordValidator validator = new AcegiDigestPasswordValidator(user);
passwordCallback.setValidator(validator);
return;
}
}
else if (callback instanceof TimestampValidationCallback) {
TimestampValidationCallback timestampCallback = (TimestampValidationCallback) callback;
timestampCallback.setValidator(new DefaultTimestampValidator());
}
throw new UnsupportedCallbackException(callback);
}
private UserDetails loadUserDetails(String username) {
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 AcegiDigestPasswordValidator extends PasswordValidationCallback.DigestPasswordValidator {
private UserDetails user;
private AcegiDigestPasswordValidator(UserDetails user) {
this.user = user;
}
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;
}
}
}
}

View File

@@ -0,0 +1,115 @@
/*
* 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.acegi;
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.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.springframework.util.Assert;
import org.springframework.ws.soap.security.xwss.callback.AbstractCallbackHandler;
/**
* Callback handler that validates a certificate uses an Acegi <code>AuthenticationManager</code>. Logic based on
* Acegi's <code>BasicProcessingFilter</code>.
* <p/>
* This handler requires an Acegi <code>AuthenticationManager</code> to operate. It can be set using the
* <code>authenticationManager</code> property. An Acegi <code>UsernamePasswordAuthenticationToken</code> is created
* with the username as principal and password as credentials.
* <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 UsernamePasswordAuthenticationToken
* @see PasswordValidationCallback
* @see com.sun.xml.wss.impl.callback.PasswordValidationCallback.PlainTextPasswordRequest
* @see org.acegisecurity.ui.basicauth.BasicProcessingFilter
*/
public class AcegiPlainTextPasswordValidationCallbackHandler extends AbstractCallbackHandler {
private AuthenticationManager authenticationManager;
private boolean ignoreFailure = false;
/**
* Sets the Acegi authentication manager. Required.
*/
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public void setIgnoreFailure(boolean ignoreFailure) {
this.ignoreFailure = ignoreFailure;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(authenticationManager, "authenticationManager is required");
}
/**
* 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
*/
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 AcegiPlainTextPasswordValidator());
return;
}
}
throw new UnsupportedCallbackException(callback);
}
private class AcegiPlainTextPasswordValidator 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.getContext().setAuthentication(null);
return ignoreFailure;
}
}
}
}

View File

@@ -0,0 +1,6 @@
<html>
<body>
Contains <code>CallbackHandler</code> implementations for XWSS that use the <a href="http://www.acegisecurity.org/">Acegi
Security System for Spring</a>.
</body>
</html>

View File

@@ -0,0 +1,53 @@
/*
* 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.xwss.callback.AbstractCallbackHandler;
/**
* Abstract base class for integrating with JAAS. Provides a login context name property.
*
* @author Arjen Poutsma
*/
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");
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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 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)
*/
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
*/
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 {
LoginContext loginContext = null;
Subject subject = new Subject();
subject.getPrincipals().add(certificate.getSubjectX500Principal());
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;
}
}
}
}

View File

@@ -0,0 +1,123 @@
/*
* 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 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.xwss.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()
*/
public class JaasPlainTextPasswordValidationCallbackHandler extends AbstractJaasValidationCallbackHandler {
protected JaasPlainTextPasswordValidationCallbackHandler() {
}
/**
* 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
*/
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 = null;
try {
loginContext = new LoginContext(getLoginContextName(), new AbstractCallbackHandler() {
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;
}
}
}
}

View File

@@ -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>

View File

@@ -0,0 +1,5 @@
<html>
<body>
Contains <code>CallbackHandler</code> implementations for XWSS.
</body>
</html>

View File

@@ -0,0 +1,6 @@
<html>
<body>
Contains classes for using the <a href="https://xwss.dev.java.net/">XML and WebServices Security</a> WS-Security
implementation within Spring-WS.
</body>
</html>

View File

@@ -0,0 +1,101 @@
/*
* 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 java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Iterator;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import junit.framework.TestCase;
import org.springframework.ws.soap.saaj.SaajSoapMessageContext;
import org.springframework.ws.transport.TransportRequest;
import org.springframework.ws.transport.TransportException;
public class XwsSecurityInterceptorTest extends TestCase {
private MessageFactory messageFactory;
protected void setUp() throws Exception {
messageFactory = MessageFactory.newInstance();
}
public void testhandleRequest() throws Exception {
final SOAPMessage request = messageFactory.createMessage();
final SOAPMessage validatedRequest = messageFactory.createMessage();
XwsSecurityInterceptor interceptor = new XwsSecurityInterceptor() {
protected SOAPMessage secureMessage(SOAPMessage message) throws XwsSecuritySecurementException {
fail("secure not expected");
return null;
}
protected SOAPMessage validateMessage(SOAPMessage message) throws XwsSecurityValidationException {
assertEquals("Invalid message", request, message);
return validatedRequest;
}
};
SaajSoapMessageContext context =
new SaajSoapMessageContext(request, new DummyTransportRequest(), messageFactory);
interceptor.handleRequest(context, null);
assertEquals("Invalid request", validatedRequest, context.getSaajRequest());
}
public void testhandleResponse() throws Exception {
final SOAPMessage response = messageFactory.createMessage();
final SOAPMessage securedResponse = messageFactory.createMessage();
XwsSecurityInterceptor interceptor = new XwsSecurityInterceptor() {
protected SOAPMessage secureMessage(SOAPMessage message) throws XwsSecuritySecurementException {
assertEquals("Invalid message", response, message);
return securedResponse;
}
protected SOAPMessage validateMessage(SOAPMessage message) throws XwsSecurityValidationException {
fail("validate not expected");
return null;
}
};
SOAPMessage request = messageFactory.createMessage();
SaajSoapMessageContext context =
new SaajSoapMessageContext(request, new DummyTransportRequest(), messageFactory);
context.setSaajResponse(response);
interceptor.handleResponse(context, null);
assertEquals("Invalid response", securedResponse, context.getSaajResponse());
}
private static class DummyTransportRequest implements TransportRequest {
public Iterator getHeaderNames() {
return Collections.EMPTY_LIST.iterator();
}
public Iterator getHeaders(String name) {
return Collections.EMPTY_LIST.iterator();
}
public String getUrl() throws TransportException {
return null;
}
public InputStream getInputStream() throws IOException {
return null;
}
}
}

View File

@@ -0,0 +1,127 @@
/*
* 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 javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.xml.soap.SOAPMessage;
import com.sun.xml.wss.impl.callback.DecryptionKeyCallback;
import com.sun.xml.wss.impl.callback.EncryptionKeyCallback;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.soap.security.xwss.callback.AbstractCallbackHandler;
public class XwssMessageInterceptorEncryptTest extends XwssMessageInterceptorKeyStoreTestCase {
public void testEncryptDefaultCertificate() throws Exception {
interceptor.setPolicyConfiguration(new ClassPathResource("encrypt-config.xml", getClass()));
CallbackHandler handler = new AbstractCallbackHandler() {
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();
SOAPMessage message = loadSaajMessage("empty-soap.xml");
SOAPMessage result = interceptor.secureMessage(message);
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);
}
public void testEncryptAlias() throws Exception {
interceptor.setPolicyConfiguration(new ClassPathResource("encrypt-alias-config.xml", getClass()));
CallbackHandler handler = new AbstractCallbackHandler() {
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();
SOAPMessage message = loadSaajMessage("empty-soap.xml");
SOAPMessage result = interceptor.secureMessage(message);
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);
}
public void testDecrypt() throws Exception {
interceptor.setPolicyConfiguration(new ClassPathResource("decrypt-config.xml", getClass()));
CallbackHandler handler = new AbstractCallbackHandler() {
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();
SOAPMessage message = loadSaajMessage("encrypted-soap.xml");
SOAPMessage result = interceptor.validateMessage(message);
assertNotNull("No result returned", result);
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security", result);
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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 java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
public abstract class XwssMessageInterceptorKeyStoreTestCase extends XwssMessageInterceptorTestCase {
protected X509Certificate certificate;
protected PrivateKey privateKey;
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());
}
}

View File

@@ -0,0 +1,127 @@
/*
* 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 java.security.cert.X509Certificate;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.xml.soap.SOAPMessage;
import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
import com.sun.xml.wss.impl.callback.SignatureKeyCallback;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.soap.security.xwss.callback.AbstractCallbackHandler;
public class XwssMessageInterceptorSignTest extends XwssMessageInterceptorKeyStoreTestCase {
public void testSignDefaultCertificate() throws Exception {
interceptor.setPolicyConfiguration(new ClassPathResource("sign-config.xml", getClass()));
CallbackHandler handler = new AbstractCallbackHandler() {
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();
SOAPMessage message = loadSaajMessage("empty-soap.xml");
SOAPMessage result = interceptor.secureMessage(message);
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);
}
public void testSignAlias() throws Exception {
interceptor.setPolicyConfiguration(new ClassPathResource("sign-alias-config.xml", getClass()));
CallbackHandler handler = new AbstractCallbackHandler() {
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();
SOAPMessage message = loadSaajMessage("empty-soap.xml");
SOAPMessage result = interceptor.secureMessage(message);
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);
}
public void testValidateCertificate() throws Exception {
interceptor.setPolicyConfiguration(new ClassPathResource("requireSignature-config.xml", getClass()));
CallbackHandler handler = new AbstractCallbackHandler() {
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();
SOAPMessage message = loadSaajMessage("signed-soap.xml");
SOAPMessage result = interceptor.validateMessage(message);
assertNotNull("No result returned", result);
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security", result);
}
}

View File

@@ -0,0 +1,97 @@
/*
* 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 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 junit.framework.TestCase;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.springframework.xml.xpath.XPathExpression;
import org.springframework.xml.xpath.XPathExpressionFactory;
public abstract class XwssMessageInterceptorTestCase extends TestCase {
protected XwsSecurityInterceptor interceptor;
private MessageFactory messageFactory;
private Map namespaces;
protected final void setUp() throws Exception {
interceptor = new XwsSecurityInterceptor();
messageFactory = MessageFactory.newInstance();
namespaces = new HashMap();
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#");
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);
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);
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);
assertNull(message, node);
}
protected SOAPMessage loadSaajMessage(String fileName) throws SOAPException, IOException {
MimeHeaders mimeHeaders = new MimeHeaders();
mimeHeaders.addHeader("Content-Type", "text/xml");
InputStream is = null;
try {
is = getClass().getResourceAsStream(fileName);
assertNotNull("Could not load SAAJ message with name [" + fileName + "]", is);
return messageFactory.createMessage(mimeHeaders, is);
}
finally {
if (is != null) {
is.close();
}
}
}
protected void onSetup() throws Exception {
}
}

View File

@@ -0,0 +1,170 @@
/*
* 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 javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.xml.soap.SOAPMessage;
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.springframework.core.io.ClassPathResource;
import org.springframework.ws.soap.security.xwss.callback.AbstractCallbackHandler;
public class XwssMessageInterceptorUsernameTokenTest extends XwssMessageInterceptorTestCase {
public void testAddUsernameTokenDigest() throws Exception {
interceptor.setPolicyConfiguration(new ClassPathResource("usernameToken-digest-config.xml", getClass()));
CallbackHandler handler = new AbstractCallbackHandler() {
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();
SOAPMessage message = loadSaajMessage("empty-soap.xml");
SOAPMessage result = interceptor.secureMessage(message);
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);
}
public void testAddUsernameTokenPlainText() throws Exception {
interceptor.setPolicyConfiguration(new ClassPathResource("usernameToken-plainText-config.xml", getClass()));
CallbackHandler handler = new AbstractCallbackHandler() {
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();
SOAPMessage message = loadSaajMessage("empty-soap.xml");
SOAPMessage result = interceptor.secureMessage(message);
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);
}
public void testValidateUsernameTokenPlainText() throws Exception {
interceptor
.setPolicyConfiguration(new ClassPathResource("requireUsernameToken-plainText-config.xml", getClass()));
CallbackHandler handler = new AbstractCallbackHandler() {
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();
SOAPMessage message = loadSaajMessage("usernameTokenPlainText-soap.xml");
SOAPMessage result = interceptor.validateMessage(message);
assertNotNull("No result returned", result);
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security", result);
}
public void testValidateUsernameTokenDigest() throws Exception {
interceptor.setPolicyConfiguration(new ClassPathResource("requireUsernameToken-digest-config.xml", getClass()));
CallbackHandler handler = new AbstractCallbackHandler() {
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();
SOAPMessage message = loadSaajMessage("usernameTokenDigest-soap.xml");
SOAPMessage result = interceptor.validateMessage(message);
assertNotNull("No result returned", result);
assertXpathNotExists("Security Header not removed", "/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security", result);
}
}

View File

@@ -0,0 +1,64 @@
/*
* 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 javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import junit.framework.TestCase;
public class CallbackHandlerChainTest extends TestCase {
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() {
};
protected void setUp() throws Exception {
}
public void testSupported() throws Exception {
CallbackHandlerChain chain = new CallbackHandlerChain(new CallbackHandler[]{supported});
chain.handle(new Callback[]{callback});
}
public void testUnsupportedNormal() throws Exception {
CallbackHandlerChain chain = new CallbackHandlerChain(new CallbackHandler[]{unsupported, supported});
chain.handle(new Callback[]{callback});
}
public void testUnsupported() throws Exception {
CallbackHandlerChain chain = new CallbackHandlerChain(new CallbackHandler[]{unsupported});
try {
chain.handle(new Callback[]{callback});
fail("Expected UnsupportedCallbackException");
}
catch (UnsupportedCallbackException ex) {
// expected behavior
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* 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 junit.framework.TestCase;
public class KeyStoreCallbackHandlerTest extends TestCase {
private KeyStoreCallbackHandler handler;
protected void setUp() throws Exception {
handler = new KeyStoreCallbackHandler();
}
public void testLoadDefaultTrustStore() throws Exception {
System.setProperty("javax.net.ssl.trustStore",
"/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/");
handler.loadDefaultTrustStore();
}
}

View File

@@ -0,0 +1,89 @@
/*
* 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.util.Properties;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
import junit.framework.TestCase;
public class SimplePasswordValidationCallbackHandlerTest extends TestCase {
private SimplePasswordValidationCallbackHandler handler;
protected void setUp() throws Exception {
handler = new SimplePasswordValidationCallbackHandler();
Properties users = new Properties();
users.setProperty("Bert", "Ernie");
handler.setUsers(users);
}
public void testPlainTextPasswordValid() throws Exception {
PasswordValidationCallback.PlainTextPasswordRequest request =
new PasswordValidationCallback.PlainTextPasswordRequest("Bert", "Ernie");
PasswordValidationCallback callback = new PasswordValidationCallback(request);
handler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertTrue("Not authenticated", authenticated);
}
public void testPlainTextPasswordInvalid() throws Exception {
PasswordValidationCallback.PlainTextPasswordRequest request =
new PasswordValidationCallback.PlainTextPasswordRequest("Bert", "Big bird");
PasswordValidationCallback callback = new PasswordValidationCallback(request);
handler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertFalse("Authenticated", authenticated);
}
public void testPlainTextPasswordNoSuchUser() throws Exception {
PasswordValidationCallback.PlainTextPasswordRequest request =
new PasswordValidationCallback.PlainTextPasswordRequest("Big bird", "Bert");
PasswordValidationCallback callback = new PasswordValidationCallback(request);
handler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertFalse("Authenticated", authenticated);
}
public void testDigestPasswordValid() throws Exception {
String username = "Bert";
String nonce = "9mdsYDCrjjYRur0rxzYt2oD7";
String passwordDigest = "kwNstEaiFOrI7B31j7GuETYvdgk=";
String creationTime = "2006-06-01T23:48:42Z";
PasswordValidationCallback.DigestPasswordRequest request =
new PasswordValidationCallback.DigestPasswordRequest(username, passwordDigest, nonce, creationTime);
PasswordValidationCallback callback = new PasswordValidationCallback(request);
handler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertFalse("Authenticated", authenticated);
}
public void testDigestPasswordInvalid() throws Exception {
String username = "Bert";
String nonce = "9mdsYDCrjjYRur0rxzYt2oD7";
String passwordDigest = "kwNstEaiFOrI7B31j7GuETYvdgk";
String creationTime = "2006-06-01T23:48:42Z";
PasswordValidationCallback.DigestPasswordRequest request =
new PasswordValidationCallback.DigestPasswordRequest(username, passwordDigest, nonce, creationTime);
PasswordValidationCallback callback = new PasswordValidationCallback(request);
handler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertFalse("Authenticated", authenticated);
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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 com.sun.xml.wss.impl.callback.PasswordCallback;
import com.sun.xml.wss.impl.callback.UsernameCallback;
import junit.framework.TestCase;
public class SimpleUsernamePasswordCallbackHandlerTest extends TestCase {
private SimpleUsernamePasswordCallbackHandler handler;
protected void setUp() throws Exception {
handler = new SimpleUsernamePasswordCallbackHandler();
handler.setUsername("Bert");
handler.setPassword("Ernie");
}
public void testUsernameCallback() throws Exception {
UsernameCallback usernameCallback = new UsernameCallback();
handler.handleInternal(usernameCallback);
assertEquals("Invalid username", "Bert", usernameCallback.getUsername());
}
public void testPasswordCallback() throws Exception {
PasswordCallback passwordCallback = new PasswordCallback();
handler.handleInternal(passwordCallback);
assertEquals("Invalid username", "Ernie", passwordCallback.getPassword());
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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.acegi;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
import junit.framework.TestCase;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.providers.TestingAuthenticationToken;
import org.acegisecurity.providers.x509.X509AuthenticationToken;
import org.easymock.MockControl;
import org.springframework.core.io.ClassPathResource;
public class AcegiCertificateValidationCallbackHandlerTest extends TestCase {
private AcegiCertificateValidationCallbackHandler callbackHandler;
private MockControl control;
private AuthenticationManager mock;
private X509Certificate certificate;
private CertificateValidationCallback callback;
protected void setUp() throws Exception {
callbackHandler = new AcegiCertificateValidationCallbackHandler();
control = MockControl.createControl(AuthenticationManager.class);
mock = (AuthenticationManager) control.getMock();
callbackHandler.setAuthenticationManager(mock);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream is = null;
try {
is = new ClassPathResource("/org/springframework/ws/soap/security/xwss/test-keystore.jks").getInputStream();
keyStore.load(is, "password".toCharArray());
}
finally {
if (is != null) {
is.close();
}
}
certificate = (X509Certificate) keyStore.getCertificate("alias");
callback = new CertificateValidationCallback(certificate);
}
public void testValidateCertificateValid() throws Exception {
mock.authenticate(new X509AuthenticationToken(certificate));
control.setMatcher(MockControl.ALWAYS_MATCHER);
control.setReturnValue(new TestingAuthenticationToken(certificate, null, new GrantedAuthority[0]));
control.replay();
callbackHandler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertTrue("Not authenticated", authenticated);
control.verify();
}
public void testValidateCertificateInvalid() throws Exception {
mock.authenticate(new X509AuthenticationToken(certificate));
control.setMatcher(MockControl.ALWAYS_MATCHER);
control.setThrowable(new BadCredentialsException(""));
control.replay();
callbackHandler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertFalse("Authenticated", authenticated);
control.verify();
}
}

View File

@@ -0,0 +1,84 @@
/*
* 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.acegi;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
import junit.framework.TestCase;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.User;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.easymock.MockControl;
public class AcegiDigestPasswordValidationCallbackHandlerTest extends TestCase {
private AcegiDigestPasswordValidationCallbackHandler callbackHandler;
private MockControl control;
private UserDetailsService mock;
private String username;
private String password;
private PasswordValidationCallback callback;
protected void setUp() throws Exception {
callbackHandler = new AcegiDigestPasswordValidationCallbackHandler();
control = MockControl.createControl(UserDetailsService.class);
mock = (UserDetailsService) control.getMock();
callbackHandler.setUserDetailsService(mock);
username = "Bert";
password = "Ernie";
String nonce = "9mdsYDCrjjYRur0rxzYt2oD7";
String passwordDigest = "kwNstEaiFOrI7B31j7GuETYvdgk=";
String creationTime = "2006-06-01T23:48:42Z";
PasswordValidationCallback.DigestPasswordRequest request =
new PasswordValidationCallback.DigestPasswordRequest(username, passwordDigest, nonce, creationTime);
callback = new PasswordValidationCallback(request);
}
public void testAuthenticateUserDigestUserNotFound() throws Exception {
control.expectAndThrow(mock.loadUserByUsername(username), new UsernameNotFoundException(username));
control.replay();
callbackHandler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertFalse("Authenticated", authenticated);
control.verify();
}
public void testAuthenticateUserDigestValid() throws Exception {
User user = new User(username, password, true, true, true, true, new GrantedAuthority[0]);
control.expectAndReturn(mock.loadUserByUsername(username), user);
control.replay();
callbackHandler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertTrue("Not authenticated", authenticated);
control.verify();
}
public void testAuthenticateUserDigestValidInvalid() throws Exception {
User user = new User(username, "Big bird", true, true, true, true, new GrantedAuthority[0]);
control.expectAndReturn(mock.loadUserByUsername(username), user);
control.replay();
callbackHandler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertFalse("Authenticated", authenticated);
control.verify();
}
}

View File

@@ -0,0 +1,76 @@
/*
* 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.acegi;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
import junit.framework.TestCase;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.providers.TestingAuthenticationToken;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.easymock.MockControl;
public class AcegiPlainTextPasswordValidationCallbackHandlerTest extends TestCase {
private AcegiPlainTextPasswordValidationCallbackHandler callbackHandler;
private MockControl control;
private AuthenticationManager mock;
private PasswordValidationCallback callback;
private String username;
private String password;
protected void setUp() throws Exception {
callbackHandler = new AcegiPlainTextPasswordValidationCallbackHandler();
control = MockControl.createControl(AuthenticationManager.class);
mock = (AuthenticationManager) control.getMock();
callbackHandler.setAuthenticationManager(mock);
username = "Bert";
password = "Ernie";
PasswordValidationCallback.PlainTextPasswordRequest request =
new PasswordValidationCallback.PlainTextPasswordRequest(username, password);
callback = new PasswordValidationCallback(request);
}
public void testAuthenticateUserPlainTextValid() throws Exception {
Authentication authResult = new TestingAuthenticationToken(username, password, new GrantedAuthority[0]);
control.expectAndReturn(mock.authenticate(new UsernamePasswordAuthenticationToken(username, password)),
authResult);
control.replay();
callbackHandler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertTrue("Not authenticated", authenticated);
control.verify();
}
public void testAuthenticateUserPlainTextInvalid() throws Exception {
control.expectAndThrow(mock.authenticate(new UsernamePasswordAuthenticationToken(username, password)),
new BadCredentialsException(""));
control.replay();
callbackHandler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertFalse("Authenticated", authenticated);
control.verify();
}
}

View File

@@ -0,0 +1,80 @@
/*
* 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 java.security.Principal;
import java.util.Iterator;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import javax.security.auth.x500.X500Principal;
public class CertificateLoginModule implements LoginModule {
private Subject subject;
private boolean loginSuccessful = false;
public boolean abort() {
return true;
}
public boolean commit() {
if (!loginSuccessful) {
subject.getPrincipals().clear();
subject.getPrivateCredentials().clear();
return false;
}
return true;
}
public void initialize(Subject subject,
CallbackHandler callbackHandler,
java.util.Map sharedState,
java.util.Map options) {
this.subject = subject;
}
public boolean login() throws LoginException {
if (subject == null) {
return false;
}
String name = getName(subject);
loginSuccessful = "CN=Arjen Poutsma,OU=Spring-WS,O=Interface21,L=Amsterdam,ST=Unknown,C=NL".equals(name);
return loginSuccessful;
}
public boolean logout() {
subject.getPrincipals().clear();
subject.getPrivateCredentials().clear();
return true;
}
private String getName(Subject subject) {
for (Iterator iterator = subject.getPrincipals().iterator(); iterator.hasNext();) {
Principal principal = (Principal) iterator.next();
if (principal instanceof X500Principal) {
return ((X500Principal) principal).getName();
}
}
return null;
}
}

View File

@@ -0,0 +1,59 @@
/*
* 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 java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
import junit.framework.TestCase;
import org.springframework.core.io.ClassPathResource;
public class JaasCertificateValidationCallbackHandlerTest extends TestCase {
private JaasCertificateValidationCallbackHandler callbackHandler;
private CertificateValidationCallback callback;
protected void setUp() throws Exception {
System.setProperty("java.security.auth.login.config", getClass().getResource("jaas.config").toString());
callbackHandler = new JaasCertificateValidationCallbackHandler();
callbackHandler.setLoginContextName("Certificate");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream is = null;
try {
is = new ClassPathResource("/org/springframework/ws/soap/security/xwss/test-keystore.jks").getInputStream();
keyStore.load(is, "password".toCharArray());
}
finally {
if (is != null) {
is.close();
}
}
X509Certificate certificate = (X509Certificate) keyStore.getCertificate("alias");
callback = new CertificateValidationCallback(certificate);
}
public void testValidateCertificateValid() throws Exception {
callbackHandler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertTrue("Not authenticated", authenticated);
}
}

View File

@@ -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 com.sun.xml.wss.impl.callback.PasswordValidationCallback;
import junit.framework.TestCase;
public class JaasPlainTextPasswordValidationCallbackHandlerTest extends TestCase {
private JaasPlainTextPasswordValidationCallbackHandler callbackHandler;
protected void setUp() throws Exception {
System.setProperty("java.security.auth.login.config", getClass().getResource("jaas.config").toString());
callbackHandler = new JaasPlainTextPasswordValidationCallbackHandler();
callbackHandler.setLoginContextName("PlainText");
}
public void testAuthenticateUserPlainTextValid() throws Exception {
PasswordValidationCallback.PlainTextPasswordRequest request =
new PasswordValidationCallback.PlainTextPasswordRequest("Bert", "Ernie");
PasswordValidationCallback callback = new PasswordValidationCallback(request);
callbackHandler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertTrue("Not authenticated", authenticated);
}
public void testAuthenticateUserPlainTextInvalid() throws Exception {
PasswordValidationCallback.PlainTextPasswordRequest request =
new PasswordValidationCallback.PlainTextPasswordRequest("Bert", "Big bird");
PasswordValidationCallback callback = new PasswordValidationCallback(request);
callbackHandler.handleInternal(callback);
boolean authenticated = callback.getResult();
assertFalse("Authenticated", authenticated);
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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 java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
public class PlainTextLoginModule implements LoginModule {
private Subject subject;
private CallbackHandler callbackHandler;
private boolean success;
private List principals = new ArrayList();
public boolean abort() {
success = false;
logout();
return true;
}
public boolean commit() throws LoginException {
if (success) {
if (subject.isReadOnly()) {
throw new LoginException("Subject is read-only");
}
try {
subject.getPrincipals().addAll(principals);
principals.clear();
return true;
}
catch (Exception e) {
throw new LoginException(e.getMessage());
}
}
else {
principals.clear();
}
return true;
}
public void initialize(Subject subject,
CallbackHandler callbackHandler,
java.util.Map sharedState,
java.util.Map options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
}
public boolean login() throws LoginException {
if (callbackHandler == null) {
return false;
}
try {
NameCallback nameCallback = new NameCallback("Username: ");
PasswordCallback passwordCallback = new PasswordCallback("Password: ", false);
Callback[] callbacks = new Callback[]{nameCallback, passwordCallback};
callbackHandler.handle(callbacks);
String username = nameCallback.getName();
String password = new String(passwordCallback.getPassword());
((PasswordCallback) callbacks[1]).clearPassword();
success = validate(username, password);
callbacks[0] = null;
callbacks[1] = null;
if (!success) {
throw new LoginException("Authentication failed: Password does not match");
}
return true;
}
catch (LoginException ex) {
throw ex;
}
catch (Exception ex) {
success = false;
throw new LoginException(ex.getMessage());
}
}
private boolean validate(String username, String password) {
if ("Bert".equals(username) && "Ernie".equals(password)) {
this.principals.add(new SimplePrincipal(username));
return true;
}
else {
return false;
}
}
public boolean logout() {
principals.clear();
Iterator iterator = subject.getPrincipals(SimplePrincipal.class).iterator();
while (iterator.hasNext()) {
SimplePrincipal principal = (SimplePrincipal) iterator.next();
subject.getPrincipals().remove(principal);
}
return true;
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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 java.security.Principal;
public final class SimplePrincipal implements Principal {
private String name;
public SimplePrincipal() {
name = "";
}
public SimplePrincipal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int hashCode() {
return name.hashCode();
}
public boolean equals(Object o) {
if (!(o instanceof SimplePrincipal)) {
return false;
}
return name.equals(((SimplePrincipal) o).name);
}
public String toString() {
return name;
}
}