1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.wss4j.stax.test.saml;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.security.KeyStore;
24 import java.security.cert.X509Certificate;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28
29 import javax.crypto.KeyGenerator;
30 import javax.crypto.SecretKey;
31 import javax.security.auth.callback.Callback;
32 import javax.security.auth.callback.CallbackHandler;
33 import javax.security.auth.callback.UnsupportedCallbackException;
34 import javax.xml.parsers.DocumentBuilder;
35 import javax.xml.parsers.DocumentBuilderFactory;
36
37 import org.apache.wss4j.common.crypto.Merlin;
38 import org.apache.wss4j.common.saml.SAMLCallback;
39 import org.apache.wss4j.common.saml.bean.ActionBean;
40 import org.apache.wss4j.common.saml.bean.AttributeBean;
41 import org.apache.wss4j.common.saml.bean.AttributeStatementBean;
42 import org.apache.wss4j.common.saml.bean.AuthDecisionStatementBean;
43 import org.apache.wss4j.common.saml.bean.AuthenticationStatementBean;
44 import org.apache.wss4j.common.saml.bean.ConditionsBean;
45 import org.apache.wss4j.common.saml.bean.KeyInfoBean;
46 import org.apache.wss4j.common.saml.bean.NameIDBean;
47 import org.apache.wss4j.common.saml.bean.SubjectBean;
48 import org.apache.wss4j.common.saml.bean.SubjectConfirmationDataBean;
49 import org.apache.wss4j.common.saml.bean.SubjectLocalityBean;
50 import org.apache.wss4j.common.saml.bean.Version;
51 import org.apache.wss4j.common.saml.builder.SAML1Constants;
52 import org.apache.wss4j.common.saml.builder.SAML2Constants;
53 import org.apache.wss4j.common.util.KeyUtils;
54 import org.apache.wss4j.dom.WSConstants;
55 import org.apache.wss4j.dom.message.WSSecEncryptedKey;
56 import org.w3c.dom.Document;
57 import org.w3c.dom.Element;
58
59 public class SAMLCallbackHandlerImpl implements CallbackHandler {
60
61 public enum Statement {
62 AUTHN, ATTR, AUTHZ
63 }
64
65 private String subjectName = "uid=joe,ou=people,ou=saml-demo,o=example.com";
66 private String subjectQualifier = "www.example.com";
67 private String confirmationMethod = SAML1Constants.CONF_SENDER_VOUCHES;
68 private X509Certificate[] certs;
69 private Statement statement = Statement.AUTHN;
70 private KeyInfoBean.CERT_IDENTIFIER certIdentifier = KeyInfoBean.CERT_IDENTIFIER.X509_CERT;
71 private byte[] ephemeralKey;
72 private String issuer;
73 private String issuerFormat;
74 private Version samlVersion = Version.SAML_11;
75
76 private String subjectNameIDFormat;
77 private String subjectLocalityIpAddress;
78 private String subjectLocalityDnsAddress;
79 private String resource;
80 private List<Object> customAttributeValues;
81 private ConditionsBean conditions;
82 private SubjectConfirmationDataBean subjectConfirmationData;
83
84 private boolean signAssertion = true;
85
86 public SAMLCallbackHandlerImpl() {
87 }
88
89 @Override
90 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
91 if (callbacks[0] instanceof SAMLCallback) {
92 try {
93 SAMLCallback samlCallback = (SAMLCallback) callbacks[0];
94 KeyStore keyStore = KeyStore.getInstance("jks");
95 InputStream input = this.getClass().getClassLoader().getResourceAsStream("saml/issuer.jks");
96 keyStore.load(input, "default".toCharArray());
97 input.close();
98
99 Merlin crypto = new Merlin();
100 crypto.setKeyStore(keyStore);
101 samlCallback.setIssuerCrypto(crypto);
102 samlCallback.setIssuerKeyName("samlissuer");
103 samlCallback.setIssuerKeyPassword("default");
104 samlCallback.setSignAssertion(this.signAssertion);
105 samlCallback.setIssuer(issuer);
106 samlCallback.setIssuerFormat(issuerFormat);
107
108 if (conditions != null) {
109 samlCallback.setConditions(conditions);
110 }
111
112 SubjectBean subjectBean =
113 new SubjectBean(subjectName, subjectQualifier, confirmationMethod);
114 if (subjectNameIDFormat != null) {
115 subjectBean.setSubjectNameIDFormat(subjectNameIDFormat);
116 }
117 if (subjectConfirmationData != null) {
118 subjectBean.setSubjectConfirmationNameID(new NameIDBean("dummy", null, null));
119 subjectBean.setSubjectConfirmationData(subjectConfirmationData);
120 }
121
122 if (SAML1Constants.CONF_HOLDER_KEY.equals(confirmationMethod)
123 || SAML2Constants.CONF_HOLDER_KEY.equals(confirmationMethod)) {
124 try {
125 KeyInfoBean keyInfo = createKeyInfo();
126 subjectBean.setKeyInfo(keyInfo);
127 } catch (Exception ex) {
128 throw new IOException("Problem creating KeyInfo: " + ex.getMessage());
129 }
130 }
131 samlCallback.setSubject(subjectBean);
132
133 if (getSamlVersion() == Version.SAML_11) {
134 samlCallback.setSamlVersion(Version.SAML_11);
135 createAndSetStatement(subjectBean, samlCallback);
136 } else {
137 samlCallback.setSamlVersion(Version.SAML_20);
138 createAndSetStatement(null, samlCallback);
139 }
140 } catch (Exception e) {
141 throw new IOException(e);
142 }
143 }
144 }
145
146
147
148
149 protected void createAndSetStatement(SubjectBean subjectBean, SAMLCallback callback) {
150 if (statement == Statement.AUTHN) {
151 AuthenticationStatementBean authBean = new AuthenticationStatementBean();
152 if (subjectBean != null) {
153 authBean.setSubject(subjectBean);
154 }
155 if (subjectLocalityIpAddress != null || subjectLocalityDnsAddress != null) {
156 SubjectLocalityBean subjectLocality = new SubjectLocalityBean();
157 subjectLocality.setIpAddress(subjectLocalityIpAddress);
158 subjectLocality.setDnsAddress(subjectLocalityDnsAddress);
159 authBean.setSubjectLocality(subjectLocality);
160 }
161 authBean.setAuthenticationMethod("Password");
162 callback.setAuthenticationStatementData(Collections.singletonList(authBean));
163 } else if (statement == Statement.ATTR) {
164 AttributeStatementBean attrBean = new AttributeStatementBean();
165 AttributeBean attributeBean = new AttributeBean();
166 if (subjectBean != null) {
167 attrBean.setSubject(subjectBean);
168 attributeBean.setSimpleName("role");
169 attributeBean.setQualifiedName("http://custom-ns");
170 } else {
171 attributeBean.setQualifiedName("role");
172 }
173 if (customAttributeValues != null) {
174 attributeBean.setAttributeValues(customAttributeValues);
175 } else {
176 List<Object> attributes = new ArrayList<>();
177 attributes.add("user");
178 attributeBean.setAttributeValues(attributes);
179 }
180 attrBean.setSamlAttributes(Collections.singletonList(attributeBean));
181 callback.setAttributeStatementData(Collections.singletonList(attrBean));
182 } else {
183 AuthDecisionStatementBean authzBean = new AuthDecisionStatementBean();
184 if (subjectBean != null) {
185 authzBean.setSubject(subjectBean);
186 }
187 ActionBean actionBean = new ActionBean();
188 actionBean.setContents("Read");
189 authzBean.setActions(Collections.singletonList(actionBean));
190 authzBean.setResource("endpoint");
191 authzBean.setDecision(AuthDecisionStatementBean.Decision.PERMIT);
192 authzBean.setResource(resource);
193 callback.setAuthDecisionStatementData(Collections.singletonList(authzBean));
194 }
195 }
196
197 protected KeyInfoBean createKeyInfo() throws Exception {
198 KeyInfoBean keyInfo = new KeyInfoBean();
199 if (statement == Statement.AUTHN) {
200 keyInfo.setCertificate(certs[0]);
201 keyInfo.setCertIdentifer(certIdentifier);
202 } else if (statement == Statement.ATTR) {
203
204 DocumentBuilderFactory docBuilderFactory =
205 DocumentBuilderFactory.newInstance();
206 docBuilderFactory.setNamespaceAware(true);
207 DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
208 Document doc = docBuilder.newDocument();
209
210
211 WSSecEncryptedKey encrKey = new WSSecEncryptedKey(doc);
212 encrKey.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
213 encrKey.setUseThisCert(certs[0]);
214
215 KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
216 SecretKey symmetricKey = keyGen.generateKey();
217 encrKey.prepare(null, symmetricKey);
218 ephemeralKey = symmetricKey.getEncoded();
219 keyInfo.setEphemeralKey(ephemeralKey);
220 Element encryptedKeyElement = encrKey.getEncryptedKeyElement();
221
222
223 Element keyInfoElement =
224 doc.createElementNS(
225 WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":" + WSConstants.KEYINFO_LN
226 );
227 keyInfoElement.setAttributeNS(
228 WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX, WSConstants.SIG_NS
229 );
230 keyInfoElement.appendChild(encryptedKeyElement);
231
232 keyInfo.setElement(keyInfoElement);
233 }
234 return keyInfo;
235 }
236
237 public String getSubjectName() {
238 return subjectName;
239 }
240
241 public void setSubjectName(String subjectName) {
242 this.subjectName = subjectName;
243 }
244
245 public String getSubjectQualifier() {
246 return subjectQualifier;
247 }
248
249 public void setSubjectQualifier(String subjectQualifier) {
250 this.subjectQualifier = subjectQualifier;
251 }
252
253 public String getConfirmationMethod() {
254 return confirmationMethod;
255 }
256
257 public void setConfirmationMethod(String confirmationMethod) {
258 this.confirmationMethod = confirmationMethod;
259 }
260
261 public X509Certificate[] getCerts() {
262 return certs;
263 }
264
265 public void setCerts(X509Certificate[] certs) {
266 this.certs = certs;
267 }
268
269 public Statement getStatement() {
270 return statement;
271 }
272
273 public void setStatement(Statement statement) {
274 this.statement = statement;
275 }
276
277 public KeyInfoBean.CERT_IDENTIFIER getCertIdentifier() {
278 return certIdentifier;
279 }
280
281 public void setCertIdentifier(KeyInfoBean.CERT_IDENTIFIER certIdentifier) {
282 this.certIdentifier = certIdentifier;
283 }
284
285 public byte[] getEphemeralKey() {
286 return ephemeralKey;
287 }
288
289 public void setEphemeralKey(byte[] ephemeralKey) {
290 this.ephemeralKey = ephemeralKey;
291 }
292
293 public String getIssuer() {
294 return issuer;
295 }
296
297 public void setIssuer(String issuer) {
298 this.issuer = issuer;
299 }
300
301 public void setIssuerFormat(String issuerFormat) {
302 this.issuerFormat = issuerFormat;
303 }
304
305 public boolean isSignAssertion() {
306 return signAssertion;
307 }
308
309 public void setSignAssertion(boolean signAssertion) {
310 this.signAssertion = signAssertion;
311 }
312
313 public Version getSamlVersion() {
314 return samlVersion;
315 }
316
317 public void setSamlVersion(Version samlVersion) {
318 this.samlVersion = samlVersion;
319 }
320
321 public void setConditions(ConditionsBean conditionsBean) {
322 this.conditions = conditionsBean;
323 }
324
325 public void setSubjectNameIDFormat(String subjectNameIDFormat) {
326 this.subjectNameIDFormat = subjectNameIDFormat;
327 }
328
329 public void setSubjectLocality(String ipAddress, String dnsAddress) {
330 this.subjectLocalityIpAddress = ipAddress;
331 this.subjectLocalityDnsAddress = dnsAddress;
332 }
333
334 public void setResource(String resource) {
335 this.resource = resource;
336 }
337
338 public void setCustomAttributeValues(List<Object> customAttributeValues) {
339 this.customAttributeValues = customAttributeValues;
340 }
341
342 public SubjectConfirmationDataBean getSubjectConfirmationData() {
343 return subjectConfirmationData;
344 }
345
346 public void setSubjectConfirmationData(SubjectConfirmationDataBean subjectConfirmationData) {
347 this.subjectConfirmationData = subjectConfirmationData;
348 }
349 }