1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.ws.security.saml.ext.builder;
21
22 import org.apache.ws.security.WSSecurityException;
23 import org.apache.ws.security.saml.ext.OpenSAMLUtil;
24 import org.apache.ws.security.saml.ext.bean.ActionBean;
25 import org.apache.ws.security.saml.ext.bean.AttributeBean;
26 import org.apache.ws.security.saml.ext.bean.AttributeStatementBean;
27 import org.apache.ws.security.saml.ext.bean.AuthDecisionStatementBean;
28 import org.apache.ws.security.saml.ext.bean.AuthenticationStatementBean;
29 import org.apache.ws.security.saml.ext.bean.ConditionsBean;
30 import org.apache.ws.security.saml.ext.bean.KeyInfoBean;
31 import org.apache.ws.security.saml.ext.bean.SubjectBean;
32 import org.apache.ws.security.saml.ext.bean.SubjectLocalityBean;
33 import org.apache.ws.security.util.UUIDGenerator;
34
35 import org.joda.time.DateTime;
36 import org.opensaml.Configuration;
37 import org.opensaml.common.SAMLObjectBuilder;
38 import org.opensaml.common.SAMLVersion;
39
40 import org.opensaml.saml1.core.Action;
41 import org.opensaml.saml1.core.Assertion;
42 import org.opensaml.saml1.core.Attribute;
43 import org.opensaml.saml1.core.AttributeStatement;
44 import org.opensaml.saml1.core.AttributeValue;
45 import org.opensaml.saml1.core.Audience;
46 import org.opensaml.saml1.core.AudienceRestrictionCondition;
47 import org.opensaml.saml1.core.AuthenticationStatement;
48 import org.opensaml.saml1.core.AuthorizationDecisionStatement;
49 import org.opensaml.saml1.core.Conditions;
50 import org.opensaml.saml1.core.ConfirmationMethod;
51 import org.opensaml.saml1.core.DecisionTypeEnumeration;
52 import org.opensaml.saml1.core.Evidence;
53 import org.opensaml.saml1.core.NameIdentifier;
54 import org.opensaml.saml1.core.Subject;
55 import org.opensaml.saml1.core.SubjectConfirmation;
56 import org.opensaml.saml1.core.SubjectLocality;
57
58 import org.opensaml.xml.XMLObject;
59 import org.opensaml.xml.XMLObjectBuilderFactory;
60 import org.opensaml.xml.schema.XSString;
61 import org.opensaml.xml.schema.impl.XSStringBuilder;
62 import org.opensaml.xml.security.x509.BasicX509Credential;
63 import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory;
64 import org.opensaml.xml.signature.KeyInfo;
65
66 import java.util.ArrayList;
67 import java.util.List;
68
69
70
71
72
73
74
75 public final class SAML1ComponentBuilder {
76
77 private static volatile SAMLObjectBuilder<Assertion> assertionV1Builder;
78
79 private static volatile SAMLObjectBuilder<Conditions> conditionsV1Builder;
80
81 private static volatile SAMLObjectBuilder<AudienceRestrictionCondition> audienceRestrictionV1Builder;
82
83 private static volatile SAMLObjectBuilder<Audience> audienceV1Builder;
84
85 private static volatile SAMLObjectBuilder<AuthenticationStatement> authenticationStatementV1Builder;
86
87 private static volatile SAMLObjectBuilder<Subject> subjectV1Builder;
88
89 private static volatile SAMLObjectBuilder<NameIdentifier> nameIdentifierV1Builder;
90
91 private static volatile SAMLObjectBuilder<SubjectConfirmation>
92 subjectConfirmationV1Builder;
93
94 private static volatile SAMLObjectBuilder<ConfirmationMethod> confirmationMethodV1Builder;
95
96 private static volatile SAMLObjectBuilder<AttributeStatement>
97 attributeStatementV1Builder;
98
99 private static volatile SAMLObjectBuilder<Attribute> attributeV1Builder;
100
101 private static volatile XSStringBuilder stringBuilder;
102
103 private static volatile SAMLObjectBuilder<AuthorizationDecisionStatement>
104 authorizationDecisionStatementV1Builder;
105
106 private static volatile SAMLObjectBuilder<Action> actionElementV1Builder;
107
108 private static volatile XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();
109
110 private static volatile SAMLObjectBuilder<SubjectLocality> subjectLocalityBuilder;
111
112 private SAML1ComponentBuilder() {
113
114 }
115
116
117
118
119
120
121
122 @SuppressWarnings("unchecked")
123 public static Assertion createSamlv1Assertion(String issuer) {
124 if (assertionV1Builder == null) {
125 assertionV1Builder = (SAMLObjectBuilder<Assertion>)
126 builderFactory.getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
127 if (assertionV1Builder == null) {
128 throw new IllegalStateException(
129 "OpenSaml engine not initialized. Please make sure to initialize the OpenSaml "
130 + "engine prior using it"
131 );
132 }
133 }
134 Assertion assertion =
135 assertionV1Builder.buildObject(
136 Assertion.DEFAULT_ELEMENT_NAME,
137 Assertion.TYPE_NAME
138 );
139 assertion.setVersion(SAMLVersion.VERSION_11);
140 assertion.setIssuer(issuer);
141 assertion.setIssueInstant(new DateTime());
142 assertion.setID("_" + UUIDGenerator.getUUID());
143 return assertion;
144 }
145
146
147
148
149
150
151
152
153 @SuppressWarnings("unchecked")
154 public static Subject createSaml1v1Subject(SubjectBean subjectBean)
155 throws org.opensaml.xml.security.SecurityException, WSSecurityException {
156 if (subjectV1Builder == null) {
157 subjectV1Builder = (SAMLObjectBuilder<Subject>)
158 builderFactory.getBuilder(Subject.DEFAULT_ELEMENT_NAME);
159 }
160 if (nameIdentifierV1Builder == null) {
161 nameIdentifierV1Builder = (SAMLObjectBuilder<NameIdentifier>)
162 builderFactory.getBuilder(NameIdentifier.DEFAULT_ELEMENT_NAME);
163 }
164 if (subjectConfirmationV1Builder == null) {
165 subjectConfirmationV1Builder = (SAMLObjectBuilder<SubjectConfirmation>)
166 builderFactory.getBuilder(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
167
168 }
169 if (confirmationMethodV1Builder == null) {
170 confirmationMethodV1Builder = (SAMLObjectBuilder<ConfirmationMethod>)
171 builderFactory.getBuilder(ConfirmationMethod.DEFAULT_ELEMENT_NAME);
172 }
173
174 Subject subject = subjectV1Builder.buildObject();
175 NameIdentifier nameIdentifier = nameIdentifierV1Builder.buildObject();
176 SubjectConfirmation subjectConfirmation = subjectConfirmationV1Builder.buildObject();
177 ConfirmationMethod confirmationMethod = confirmationMethodV1Builder.buildObject();
178
179 nameIdentifier.setNameQualifier(subjectBean.getSubjectNameQualifier());
180 nameIdentifier.setNameIdentifier(subjectBean.getSubjectName());
181 nameIdentifier.setFormat(subjectBean.getSubjectNameIDFormat());
182 String confirmationMethodStr = subjectBean.getSubjectConfirmationMethod();
183
184 if (confirmationMethodStr == null) {
185 confirmationMethodStr = SAML1Constants.CONF_SENDER_VOUCHES;
186 }
187
188 confirmationMethod.setConfirmationMethod(confirmationMethodStr);
189 subjectConfirmation.getConfirmationMethods().add(confirmationMethod);
190 if (subjectBean.getKeyInfo() != null) {
191 KeyInfo keyInfo = createKeyInfo(subjectBean.getKeyInfo());
192 subjectConfirmation.setKeyInfo(keyInfo);
193 }
194 subject.setNameIdentifier(nameIdentifier);
195 subject.setSubjectConfirmation(subjectConfirmation);
196
197 return subject;
198 }
199
200
201
202
203
204
205
206 public static KeyInfo createKeyInfo(KeyInfoBean keyInfo)
207 throws org.opensaml.xml.security.SecurityException, WSSecurityException {
208 if (keyInfo.getElement() != null) {
209 return (KeyInfo)OpenSAMLUtil.fromDom(keyInfo.getElement());
210 } else {
211
212 BasicX509Credential keyInfoCredential = new BasicX509Credential();
213 if (keyInfo.getCertificate() != null) {
214 keyInfoCredential.setEntityCertificate(keyInfo.getCertificate());
215 } else if (keyInfo.getPublicKey() != null) {
216 keyInfoCredential.setPublicKey(keyInfo.getPublicKey());
217 }
218
219
220 X509KeyInfoGeneratorFactory kiFactory = new X509KeyInfoGeneratorFactory();
221 KeyInfoBean.CERT_IDENTIFIER certIdentifier = keyInfo.getCertIdentifer();
222 switch (certIdentifier) {
223 case X509_CERT: {
224 kiFactory.setEmitEntityCertificate(true);
225 break;
226 }
227 case KEY_VALUE: {
228 kiFactory.setEmitPublicKeyValue(true);
229 break;
230 }
231 case X509_ISSUER_SERIAL: {
232 kiFactory.setEmitX509IssuerSerial(true);
233 }
234 }
235 return kiFactory.newInstance().generate(keyInfoCredential);
236 }
237 }
238
239
240
241
242
243
244
245 @SuppressWarnings("unchecked")
246 public static Conditions createSamlv1Conditions(ConditionsBean conditionsBean) {
247 if (conditionsV1Builder == null) {
248 conditionsV1Builder = (SAMLObjectBuilder<Conditions>)
249 builderFactory.getBuilder(Conditions.DEFAULT_ELEMENT_NAME);
250
251 }
252 Conditions conditions = conditionsV1Builder.buildObject();
253
254 if (conditionsBean == null) {
255 DateTime newNotBefore = new DateTime();
256 conditions.setNotBefore(newNotBefore);
257 conditions.setNotOnOrAfter(newNotBefore.plusMinutes(5));
258 return conditions;
259 }
260
261 int tokenPeriodMinutes = conditionsBean.getTokenPeriodMinutes();
262 DateTime notBefore = conditionsBean.getNotBefore();
263 DateTime notAfter = conditionsBean.getNotAfter();
264
265 if (notBefore != null && notAfter != null) {
266 if (notBefore.isAfter(notAfter)) {
267 throw new IllegalStateException(
268 "The value of notBefore may not be after the value of notAfter"
269 );
270 }
271 conditions.setNotBefore(notBefore);
272 conditions.setNotOnOrAfter(notAfter);
273 } else {
274 DateTime newNotBefore = new DateTime();
275 conditions.setNotBefore(newNotBefore);
276 if (tokenPeriodMinutes <= 0) {
277 tokenPeriodMinutes = 5;
278 }
279 conditions.setNotOnOrAfter(newNotBefore.plusMinutes(tokenPeriodMinutes));
280 }
281
282 if (conditionsBean.getAudienceURI() != null) {
283 AudienceRestrictionCondition audienceRestriction =
284 createSamlv1AudienceRestriction(conditionsBean.getAudienceURI());
285 conditions.getAudienceRestrictionConditions().add(audienceRestriction);
286 }
287
288 return conditions;
289 }
290
291
292
293
294
295
296
297 @SuppressWarnings("unchecked")
298 public static AudienceRestrictionCondition
299 createSamlv1AudienceRestriction(String audienceURI) {
300 if (audienceRestrictionV1Builder == null) {
301 audienceRestrictionV1Builder = (SAMLObjectBuilder<AudienceRestrictionCondition>)
302 builderFactory.getBuilder(AudienceRestrictionCondition.DEFAULT_ELEMENT_NAME);
303 }
304 if (audienceV1Builder == null) {
305 audienceV1Builder = (SAMLObjectBuilder<Audience>)
306 builderFactory.getBuilder(Audience.DEFAULT_ELEMENT_NAME);
307 }
308
309 AudienceRestrictionCondition audienceRestriction =
310 audienceRestrictionV1Builder.buildObject();
311 Audience audience = audienceV1Builder.buildObject();
312 audience.setUri(audienceURI);
313 audienceRestriction.getAudiences().add(audience);
314 return audienceRestriction;
315 }
316
317
318
319
320
321
322
323 @SuppressWarnings("unchecked")
324 public static List<AuthenticationStatement> createSamlv1AuthenticationStatement(
325 List<AuthenticationStatementBean> authBeans
326 ) throws org.opensaml.xml.security.SecurityException, WSSecurityException {
327 List<AuthenticationStatement> authenticationStatements =
328 new ArrayList<AuthenticationStatement>();
329
330 if (authenticationStatementV1Builder == null) {
331 authenticationStatementV1Builder = (SAMLObjectBuilder<AuthenticationStatement>)
332 builderFactory.getBuilder(AuthenticationStatement.DEFAULT_ELEMENT_NAME);
333 }
334 if (subjectLocalityBuilder == null) {
335 subjectLocalityBuilder = (SAMLObjectBuilder<SubjectLocality>)
336 builderFactory.getBuilder(SubjectLocality.DEFAULT_ELEMENT_NAME);
337 }
338
339 if (authBeans != null && authBeans.size() > 0) {
340 for (AuthenticationStatementBean statementBean : authBeans) {
341 AuthenticationStatement authenticationStatement =
342 authenticationStatementV1Builder.buildObject(
343 AuthenticationStatement.DEFAULT_ELEMENT_NAME,
344 AuthenticationStatement.TYPE_NAME
345 );
346 Subject authSubject =
347 SAML1ComponentBuilder.createSaml1v1Subject(statementBean.getSubject());
348 authenticationStatement.setSubject(authSubject);
349
350 if (statementBean.getAuthenticationInstant() != null) {
351 authenticationStatement.setAuthenticationInstant(
352 statementBean.getAuthenticationInstant()
353 );
354 } else {
355 authenticationStatement.setAuthenticationInstant(new DateTime());
356 }
357
358 authenticationStatement.setAuthenticationMethod(
359 transformAuthenticationMethod(statementBean.getAuthenticationMethod())
360 );
361
362 SubjectLocalityBean subjectLocalityBean = statementBean.getSubjectLocality();
363 if (subjectLocalityBean != null) {
364 SubjectLocality subjectLocality = subjectLocalityBuilder.buildObject();
365 subjectLocality.setDNSAddress(subjectLocalityBean.getDnsAddress());
366 subjectLocality.setIPAddress(subjectLocalityBean.getIpAddress());
367
368 authenticationStatement.setSubjectLocality(subjectLocality);
369 }
370
371 authenticationStatements.add(authenticationStatement);
372 }
373 }
374
375 return authenticationStatements;
376 }
377
378
379
380
381
382
383
384
385 private static String transformAuthenticationMethod(String sourceMethod) {
386 String transformedMethod = "";
387
388 if ("Password".equals(sourceMethod)) {
389 transformedMethod = SAML1Constants.AUTH_METHOD_PASSWORD;
390 } else if (sourceMethod != null && !"".equals(sourceMethod)) {
391 return sourceMethod;
392 }
393
394 return transformedMethod;
395 }
396
397
398
399
400
401
402
403 @SuppressWarnings("unchecked")
404 public static List<AttributeStatement> createSamlv1AttributeStatement(
405 List<AttributeStatementBean> attributeData
406 ) throws org.opensaml.xml.security.SecurityException, WSSecurityException {
407 if (attributeStatementV1Builder == null) {
408 attributeStatementV1Builder = (SAMLObjectBuilder<AttributeStatement>)
409 builderFactory.getBuilder(AttributeStatement.DEFAULT_ELEMENT_NAME);
410 }
411
412 List<AttributeStatement> attributeStatements = new ArrayList<AttributeStatement>();
413
414 if (attributeData != null && attributeData.size() > 0) {
415 for (AttributeStatementBean statementBean : attributeData) {
416
417 AttributeStatement attributeStatement = attributeStatementV1Builder.buildObject();
418 Subject attributeSubject =
419 SAML1ComponentBuilder.createSaml1v1Subject(statementBean.getSubject());
420 attributeStatement.setSubject(attributeSubject);
421
422 for (AttributeBean values : statementBean.getSamlAttributes()) {
423 List<?> attributeValues = values.getAttributeValues();
424 if (attributeValues == null || attributeValues.isEmpty()) {
425 attributeValues = values.getCustomAttributeValues();
426 }
427
428 Attribute samlAttribute =
429 createSamlv1Attribute(
430 values.getSimpleName(),
431 values.getQualifiedName(),
432 attributeValues
433 );
434 attributeStatement.getAttributes().add(samlAttribute);
435 }
436
437 attributeStatements.add(attributeStatement);
438 }
439 }
440
441 return attributeStatements;
442 }
443
444
445
446
447
448
449
450
451
452 @SuppressWarnings("unchecked")
453 public static Attribute createSamlv1Attribute(
454 String attributeName,
455 String attributeUrn,
456 List<?> values
457 ) {
458 if (attributeV1Builder == null) {
459 attributeV1Builder = (SAMLObjectBuilder<Attribute>)
460 builderFactory.getBuilder(Attribute.DEFAULT_ELEMENT_NAME);
461 }
462 if (stringBuilder == null) {
463 stringBuilder = (XSStringBuilder)builderFactory.getBuilder(XSString.TYPE_NAME);
464 }
465
466 Attribute attribute = attributeV1Builder.buildObject();
467 attribute.setAttributeName(attributeName);
468 attribute.setAttributeNamespace(attributeUrn);
469
470 for (Object value : values) {
471 if (value instanceof String) {
472 XSString attribute1 =
473 stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME);
474 attribute1.setValue((String)value);
475 attribute.getAttributeValues().add(attribute1);
476 } else if (value instanceof XMLObject) {
477 attribute.getAttributeValues().add((XMLObject)value);
478 }
479 }
480
481 return attribute;
482 }
483
484
485
486
487
488
489
490 @SuppressWarnings("unchecked")
491 public static List<AuthorizationDecisionStatement> createSamlv1AuthorizationDecisionStatement(
492 List<AuthDecisionStatementBean> decisionData)
493 throws org.opensaml.xml.security.SecurityException, WSSecurityException {
494 List<AuthorizationDecisionStatement> authDecisionStatements =
495 new ArrayList<AuthorizationDecisionStatement>();
496 if (authorizationDecisionStatementV1Builder == null) {
497 authorizationDecisionStatementV1Builder =
498 (SAMLObjectBuilder<AuthorizationDecisionStatement>)
499 builderFactory.getBuilder(AuthorizationDecisionStatement.DEFAULT_ELEMENT_NAME);
500
501 }
502
503 if (decisionData != null && decisionData.size() > 0) {
504 for (AuthDecisionStatementBean decisionStatementBean : decisionData) {
505 AuthorizationDecisionStatement authDecision =
506 authorizationDecisionStatementV1Builder.buildObject();
507 Subject authDecisionSubject =
508 SAML1ComponentBuilder.createSaml1v1Subject(decisionStatementBean.getSubject());
509 authDecision.setSubject(authDecisionSubject);
510
511 authDecision.setResource(decisionStatementBean.getResource());
512 authDecision.setDecision(transformDecisionType(decisionStatementBean.getDecision()));
513
514 for (ActionBean actionBean : decisionStatementBean.getActions()) {
515 Action actionElement = createSamlv1Action(actionBean);
516 authDecision.getActions().add(actionElement);
517 }
518
519 if (decisionStatementBean.getEvidence() instanceof Evidence) {
520 authDecision.setEvidence((Evidence)decisionStatementBean.getEvidence());
521 }
522
523 authDecisionStatements.add(authDecision);
524 }
525 }
526
527 return authDecisionStatements;
528 }
529
530
531
532
533
534
535
536 @SuppressWarnings("unchecked")
537 public static Action createSamlv1Action(ActionBean actionBean) {
538 if (actionElementV1Builder == null) {
539 actionElementV1Builder = (SAMLObjectBuilder<Action>)
540 builderFactory.getBuilder(Action.DEFAULT_ELEMENT_NAME);
541 }
542
543 Action actionElement = actionElementV1Builder.buildObject();
544 actionElement.setNamespace(actionBean.getActionNamespace());
545 actionElement.setContents(actionBean.getContents());
546
547 return actionElement;
548 }
549
550
551
552
553
554
555
556 private static DecisionTypeEnumeration transformDecisionType(
557 AuthDecisionStatementBean.Decision decision
558 ) {
559 DecisionTypeEnumeration decisionTypeEnum = DecisionTypeEnumeration.DENY;
560 if (decision.equals(AuthDecisionStatementBean.Decision.PERMIT)) {
561 decisionTypeEnum = DecisionTypeEnumeration.PERMIT;
562 } else if (decision.equals(AuthDecisionStatementBean.Decision.INDETERMINATE)) {
563 decisionTypeEnum = DecisionTypeEnumeration.INDETERMINATE;
564 }
565
566 return decisionTypeEnum;
567 }
568
569 }