Skip to content

Commit e34fb93

Browse files
jaminhgregturn
authored andcommitted
SWS-955 - Add method for configuring SAML callback.
1 parent 05092c3 commit e34fb93

File tree

5 files changed

+138
-1
lines changed

5 files changed

+138
-1
lines changed

spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecurityInterceptor.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
143143

144144
private boolean securementUseDerivedKey;
145145

146+
private CallbackHandler samlCallbackHandler;
147+
146148
// Allow RSA 15 to maintain default behavior
147149
private boolean allowRSA15KeyTransportAlgorithm = true;
148150

@@ -373,6 +375,15 @@ public void setSecurementTimeToLive(int securementTimeToLive) {
373375
public void setSecurementUseDerivedKey(boolean securementUseDerivedKey) {
374376
this.securementUseDerivedKey = securementUseDerivedKey;
375377
}
378+
379+
/**
380+
* Sets the SAML Callback used for generating SAML tokens.
381+
*
382+
* @param samlCallback
383+
*/
384+
public void setSecurementSamlCallbackHandler(CallbackHandler samlCallbackHandler) {
385+
this.samlCallbackHandler = samlCallbackHandler;
386+
}
376387

377388
/** Sets the server-side time to live */
378389
public void setValidationTimeToLive(int validationTimeToLive) {
@@ -595,7 +606,11 @@ protected RequestData initializeRequestData(MessageContext messageContext) {
595606
requestData.setWssConfig(wssConfig);
596607

597608
messageContext.setProperty(WSHandlerConstants.TTL_TIMESTAMP, Integer.toString(securementTimeToLive));
598-
609+
610+
if (this.samlCallbackHandler != null) {
611+
messageContext.setProperty(WSHandlerConstants.SAML_CALLBACK_REF, this.samlCallbackHandler);
612+
}
613+
599614
// allow for qualified password types for .Net interoperability
600615
requestData.setAllowNamespaceQualifiedPasswordTypes(true);
601616

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package org.springframework.ws.soap.security.wss4j2;
2+
3+
public class AxiomWss4jMessageInterceptorSamlTest extends Wss4jMessageInterceptorSamlTestCase {
4+
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package org.springframework.ws.soap.security.wss4j2;
2+
3+
public class SaajWss4jMessageInterceptorSamlTest extends Wss4jMessageInterceptorSamlTestCase {
4+
5+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package org.springframework.ws.soap.security.wss4j2;
2+
3+
import java.io.IOException;
4+
import java.security.cert.X509Certificate;
5+
6+
import javax.security.auth.callback.Callback;
7+
import javax.security.auth.callback.CallbackHandler;
8+
import javax.security.auth.callback.UnsupportedCallbackException;
9+
10+
import org.apache.wss4j.common.crypto.Crypto;
11+
import org.apache.wss4j.common.crypto.CryptoType;
12+
import org.apache.wss4j.common.crypto.Merlin;
13+
import org.apache.wss4j.common.saml.SAMLCallback;
14+
import org.apache.wss4j.common.saml.bean.KeyInfoBean;
15+
import org.apache.wss4j.common.saml.bean.SubjectBean;
16+
import org.apache.wss4j.common.saml.bean.Version;
17+
import org.apache.wss4j.common.saml.builder.SAML2Constants;
18+
import org.junit.Test;
19+
import org.springframework.core.io.ClassPathResource;
20+
import org.springframework.ws.context.MessageContext;
21+
import org.springframework.ws.soap.SoapMessage;
22+
import org.springframework.ws.soap.security.wss4j2.support.CryptoFactoryBean;
23+
import org.w3c.dom.Document;
24+
25+
public abstract class Wss4jMessageInterceptorSamlTestCase extends Wss4jTestCase {
26+
27+
protected Wss4jSecurityInterceptor interceptor;
28+
29+
@Override
30+
protected void onSetup() throws Exception {
31+
interceptor = new Wss4jSecurityInterceptor();
32+
interceptor.setSecurementActions("SAMLTokenSigned");
33+
interceptor.setValidationActions("SAMLTokenSigned Signature");
34+
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
35+
cryptoFactoryBean.setCryptoProvider(Merlin.class);
36+
cryptoFactoryBean.setKeyStoreType("jceks");
37+
cryptoFactoryBean.setKeyStorePassword("123456");
38+
cryptoFactoryBean.setKeyStoreLocation(new ClassPathResource("private.jks"));
39+
cryptoFactoryBean.afterPropertiesSet();
40+
Crypto crypto = cryptoFactoryBean.getObject();
41+
42+
CryptoType type = new CryptoType(CryptoType.TYPE.ALIAS);
43+
type.setAlias("rsaKey");
44+
X509Certificate userCertificate = crypto.getX509Certificates(type)[0];
45+
46+
interceptor.setSecurementSignatureCrypto(crypto);
47+
interceptor.setValidationSignatureCrypto(crypto);
48+
interceptor.setSecurementSamlCallbackHandler(getSamlCalbackHandler(crypto, userCertificate));
49+
interceptor.afterPropertiesSet();
50+
51+
}
52+
53+
@Test
54+
public void testAddSAML() throws Exception
55+
{
56+
interceptor.setSecurementPassword("123456");
57+
interceptor.setSecurementUsername("rsaKey");
58+
SoapMessage message = loadSoap11Message("empty-soap.xml");
59+
MessageContext messageContext = getSoap11MessageContext(message);
60+
61+
interceptor.secureMessage(message, messageContext);
62+
Document document = getDocument(message);
63+
64+
assertXpathExists("Absent SAML Assertion element",
65+
"/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/saml:Assertion", document);
66+
67+
// lets verify the signature that we've just generated
68+
interceptor.validateMessage(message, messageContext);
69+
}
70+
71+
protected CallbackHandler getSamlCalbackHandler(Crypto crypto, X509Certificate userCert)
72+
{
73+
return new SamlCallbackHandler(crypto, userCert);
74+
}
75+
76+
private class SamlCallbackHandler implements CallbackHandler {
77+
78+
private Crypto crypto;
79+
80+
private X509Certificate userCertificate;
81+
82+
public SamlCallbackHandler(Crypto crypto, X509Certificate userCertificate)
83+
{
84+
this.crypto = crypto;
85+
this.userCertificate = userCertificate;
86+
}
87+
88+
@Override
89+
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
90+
91+
for (int i = 0; i < callbacks.length; i++) {
92+
if (callbacks[i] instanceof SAMLCallback) {
93+
SAMLCallback callback = (SAMLCallback) callbacks[i];
94+
callback.setSamlVersion(Version.SAML_20);
95+
callback.setIssuerCrypto(crypto);
96+
callback.setIssuerKeyName("rsaKey");
97+
callback.setIssuerKeyPassword("123456");
98+
callback.setIssuer("test-issuer");
99+
SubjectBean subject = new SubjectBean("test-subject", "", SAML2Constants.CONF_BEARER);
100+
KeyInfoBean keyInfo = new KeyInfoBean();
101+
keyInfo.setCertificate(userCertificate);
102+
subject.setKeyInfo(keyInfo);
103+
callback.setSubject(subject);
104+
callback.setSignAssertion(true);
105+
}
106+
}
107+
}
108+
109+
}
110+
111+
}

spring-ws-security/src/test/java/org/springframework/ws/soap/security/wss4j2/Wss4jTestCase.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public final void setUp() throws Exception {
7979
namespaces.put("echo", "http://www.springframework.org/spring-ws/samples/echo");
8080
namespaces.put("wsu",
8181
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
82+
namespaces.put("saml", "urn:oasis:names:tc:SAML:2.0:assertion");
8283
namespaces.put("test", "http://test");
8384
xpathTemplate.setNamespaces(namespaces);
8485
onSetup();

0 commit comments

Comments
 (0)