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.bean.ActionBean;
24 import org.apache.ws.security.saml.ext.bean.AttributeBean;
25 import org.apache.ws.security.saml.ext.bean.AttributeStatementBean;
26 import org.apache.ws.security.saml.ext.bean.AuthDecisionStatementBean;
27 import org.apache.ws.security.saml.ext.bean.AuthenticationStatementBean;
28 import org.apache.ws.security.saml.ext.bean.ConditionsBean;
29 import org.apache.ws.security.saml.ext.bean.KeyInfoBean;
30 import org.apache.ws.security.saml.ext.bean.SubjectBean;
31 import org.apache.ws.security.saml.ext.bean.SubjectConfirmationDataBean;
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.saml2.core.Action;
41 import org.opensaml.saml2.core.Assertion;
42 import org.opensaml.saml2.core.Attribute;
43 import org.opensaml.saml2.core.AttributeStatement;
44 import org.opensaml.saml2.core.AttributeValue;
45 import org.opensaml.saml2.core.Audience;
46 import org.opensaml.saml2.core.AudienceRestriction;
47 import org.opensaml.saml2.core.AuthnContext;
48 import org.opensaml.saml2.core.AuthnContextClassRef;
49 import org.opensaml.saml2.core.AuthnStatement;
50 import org.opensaml.saml2.core.AuthzDecisionStatement;
51 import org.opensaml.saml2.core.Conditions;
52 import org.opensaml.saml2.core.DecisionTypeEnumeration;
53 import org.opensaml.saml2.core.Evidence;
54 import org.opensaml.saml2.core.Issuer;
55 import org.opensaml.saml2.core.KeyInfoConfirmationDataType;
56 import org.opensaml.saml2.core.NameID;
57 import org.opensaml.saml2.core.Subject;
58 import org.opensaml.saml2.core.SubjectConfirmation;
59 import org.opensaml.saml2.core.SubjectConfirmationData;
60 import org.opensaml.saml2.core.SubjectLocality;
61
62 import org.opensaml.xml.XMLObject;
63 import org.opensaml.xml.XMLObjectBuilderFactory;
64 import org.opensaml.xml.schema.XSString;
65 import org.opensaml.xml.schema.impl.XSStringBuilder;
66 import org.opensaml.xml.signature.KeyInfo;
67
68 import java.util.ArrayList;
69 import java.util.List;
70
71
72
73
74
75
76
77
78 public final class SAML2ComponentBuilder {
79 private static volatile SAMLObjectBuilder<Assertion> assertionBuilder;
80
81 private static volatile SAMLObjectBuilder<Issuer> issuerBuilder;
82
83 private static volatile SAMLObjectBuilder<Subject> subjectBuilder;
84
85 private static volatile SAMLObjectBuilder<NameID> nameIdBuilder;
86
87 private static volatile SAMLObjectBuilder<SubjectConfirmation> subjectConfirmationBuilder;
88
89 private static volatile SAMLObjectBuilder<Conditions> conditionsBuilder;
90
91 private static volatile SAMLObjectBuilder<SubjectConfirmationData> subjectConfirmationDataBuilder;
92
93 private static volatile SAMLObjectBuilder<KeyInfoConfirmationDataType> keyInfoConfirmationDataBuilder;
94
95 private static volatile SAMLObjectBuilder<AuthnStatement> authnStatementBuilder;
96
97 private static volatile SAMLObjectBuilder<AuthnContext> authnContextBuilder;
98
99 private static volatile SAMLObjectBuilder<AuthnContextClassRef> authnContextClassRefBuilder;
100
101 private static volatile SAMLObjectBuilder<AttributeStatement> attributeStatementBuilder;
102
103 private static volatile SAMLObjectBuilder<Attribute> attributeBuilder;
104
105 private static volatile XSStringBuilder stringBuilder;
106
107 private static volatile SAMLObjectBuilder<AudienceRestriction> audienceRestrictionBuilder;
108
109 private static volatile SAMLObjectBuilder<Audience> audienceBuilder;
110
111 private static volatile SAMLObjectBuilder<AuthzDecisionStatement> authorizationDecisionStatementBuilder;
112
113 private static volatile SAMLObjectBuilder<Action> actionElementBuilder;
114
115 private static volatile XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();
116
117 private static volatile SAMLObjectBuilder<SubjectLocality> subjectLocalityBuilder;
118
119 private SAML2ComponentBuilder() {
120
121 }
122
123
124
125
126
127
128 @SuppressWarnings("unchecked")
129 public static Assertion createAssertion() {
130 if (assertionBuilder == null) {
131 assertionBuilder = (SAMLObjectBuilder<Assertion>)
132 builderFactory.getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
133 if (assertionBuilder == null) {
134 throw new IllegalStateException(
135 "OpenSaml engine not initialized. Please make sure to initialize the OpenSaml engine "
136 + "prior using it"
137 );
138 }
139 }
140 Assertion assertion =
141 assertionBuilder.buildObject(Assertion.DEFAULT_ELEMENT_NAME, Assertion.TYPE_NAME);
142 assertion.setID("_" + UUIDGenerator.getUUID());
143 assertion.setVersion(SAMLVersion.VERSION_20);
144 assertion.setIssueInstant(new DateTime());
145 return assertion;
146 }
147
148
149
150
151
152
153
154 @SuppressWarnings("unchecked")
155 public static Issuer createIssuer(String issuerValue) {
156 if (issuerBuilder == null) {
157 issuerBuilder = (SAMLObjectBuilder<Issuer>)
158 builderFactory.getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
159
160 }
161 Issuer issuer = issuerBuilder.buildObject();
162
163
164
165 issuer.setValue(issuerValue);
166 return issuer;
167 }
168
169
170
171
172
173
174
175 @SuppressWarnings("unchecked")
176 public static Conditions createConditions(ConditionsBean conditionsBean) {
177 if (conditionsBuilder == null) {
178 conditionsBuilder = (SAMLObjectBuilder<Conditions>)
179 builderFactory.getBuilder(Conditions.DEFAULT_ELEMENT_NAME);
180 }
181
182 Conditions conditions = conditionsBuilder.buildObject();
183
184 if (conditionsBean == null) {
185 DateTime newNotBefore = new DateTime();
186 conditions.setNotBefore(newNotBefore);
187 conditions.setNotOnOrAfter(newNotBefore.plusMinutes(5));
188 return conditions;
189 }
190
191 int tokenPeriodMinutes = conditionsBean.getTokenPeriodMinutes();
192 DateTime notBefore = conditionsBean.getNotBefore();
193 DateTime notAfter = conditionsBean.getNotAfter();
194
195 if (notBefore != null && notAfter != null) {
196 if (notBefore.isAfter(notAfter)) {
197 throw new IllegalStateException(
198 "The value of notBefore may not be after the value of notAfter"
199 );
200 }
201 conditions.setNotBefore(notBefore);
202 conditions.setNotOnOrAfter(notAfter);
203 } else {
204 DateTime newNotBefore = new DateTime();
205 conditions.setNotBefore(newNotBefore);
206 if (tokenPeriodMinutes <= 0) {
207 tokenPeriodMinutes = 5;
208 }
209 conditions.setNotOnOrAfter(newNotBefore.plusMinutes(tokenPeriodMinutes));
210 }
211
212 if (conditionsBean.getAudienceURI() != null) {
213 AudienceRestriction audienceRestriction =
214 createAudienceRestriction(conditionsBean.getAudienceURI());
215 conditions.getAudienceRestrictions().add(audienceRestriction);
216 }
217
218 return conditions;
219 }
220
221
222
223
224
225
226
227 @SuppressWarnings("unchecked")
228 public static AudienceRestriction createAudienceRestriction(String audienceURI) {
229 if (audienceRestrictionBuilder == null) {
230 audienceRestrictionBuilder = (SAMLObjectBuilder<AudienceRestriction>)
231 builderFactory.getBuilder(AudienceRestriction.DEFAULT_ELEMENT_NAME);
232 }
233 if (audienceBuilder == null) {
234 audienceBuilder = (SAMLObjectBuilder<Audience>)
235 builderFactory.getBuilder(Audience.DEFAULT_ELEMENT_NAME);
236 }
237
238 AudienceRestriction audienceRestriction = audienceRestrictionBuilder.buildObject();
239 Audience audience = audienceBuilder.buildObject();
240 audience.setAudienceURI(audienceURI);
241 audienceRestriction.getAudiences().add(audience);
242 return audienceRestriction;
243 }
244
245
246
247
248
249
250
251 @SuppressWarnings("unchecked")
252 public static List<AuthnStatement> createAuthnStatement(
253 List<AuthenticationStatementBean> authBeans
254 ) {
255 List<AuthnStatement> authnStatements = new ArrayList<AuthnStatement>();
256
257 if (authnStatementBuilder == null) {
258 authnStatementBuilder = (SAMLObjectBuilder<AuthnStatement>)
259 builderFactory.getBuilder(AuthnStatement.DEFAULT_ELEMENT_NAME);
260 }
261 if (authnContextBuilder == null) {
262 authnContextBuilder = (SAMLObjectBuilder<AuthnContext>)
263 builderFactory.getBuilder(AuthnContext.DEFAULT_ELEMENT_NAME);
264 }
265 if (authnContextClassRefBuilder == null) {
266 authnContextClassRefBuilder = (SAMLObjectBuilder<AuthnContextClassRef>)
267 builderFactory.getBuilder(AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
268 }
269 if (subjectLocalityBuilder == null) {
270 subjectLocalityBuilder = (SAMLObjectBuilder<SubjectLocality>)
271 builderFactory.getBuilder(SubjectLocality.DEFAULT_ELEMENT_NAME);
272 }
273
274 if (authBeans != null && authBeans.size() > 0) {
275 for (AuthenticationStatementBean statementBean : authBeans) {
276 AuthnStatement authnStatement = authnStatementBuilder.buildObject();
277 DateTime authInstant = statementBean.getAuthenticationInstant();
278 if (authInstant == null) {
279 authInstant = new DateTime();
280 }
281 authnStatement.setAuthnInstant(authInstant);
282
283 if (statementBean.getSessionIndex() != null) {
284 authnStatement.setSessionIndex(statementBean.getSessionIndex());
285 }
286
287 AuthnContextClassRef authnContextClassRef = authnContextClassRefBuilder.buildObject();
288 authnContextClassRef.setAuthnContextClassRef(
289 transformAuthenticationMethod(statementBean.getAuthenticationMethod())
290 );
291 AuthnContext authnContext = authnContextBuilder.buildObject();
292 authnContext.setAuthnContextClassRef(authnContextClassRef);
293 authnStatement.setAuthnContext(authnContext);
294
295 SubjectLocalityBean subjectLocalityBean = statementBean.getSubjectLocality();
296 if (subjectLocalityBean != null) {
297 SubjectLocality subjectLocality = subjectLocalityBuilder.buildObject();
298 subjectLocality.setDNSName(subjectLocalityBean.getDnsAddress());
299 subjectLocality.setAddress(subjectLocalityBean.getIpAddress());
300
301 authnStatement.setSubjectLocality(subjectLocality);
302 }
303
304 authnStatements.add(authnStatement);
305 }
306 }
307
308 return authnStatements;
309 }
310
311
312
313
314
315
316
317
318 private static String transformAuthenticationMethod(String sourceMethod) {
319 String transformedMethod = "";
320
321 if ("Password".equalsIgnoreCase(sourceMethod)) {
322 transformedMethod = SAML2Constants.AUTH_CONTEXT_CLASS_REF_PASSWORD;
323 } else if (sourceMethod != null && !"".equals(sourceMethod)) {
324 return sourceMethod;
325 }
326
327 return transformedMethod;
328 }
329
330
331
332
333
334
335
336
337
338
339 public static Attribute createAttribute(String friendlyName, String name, List<String> values) {
340 return createAttribute(friendlyName, name, null, values);
341 }
342
343
344
345
346
347
348
349
350
351
352 public static Attribute createAttribute(
353 String friendlyName, String name, String nameFormat, List<?> values
354 ) {
355 if (stringBuilder == null) {
356 stringBuilder = (XSStringBuilder)builderFactory.getBuilder(XSString.TYPE_NAME);
357 }
358 Attribute attribute = createAttribute(friendlyName, name, nameFormat);
359
360 for (Object value : values) {
361 if (value instanceof String) {
362 XSString attributeValue =
363 stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME);
364 attributeValue.setValue((String)value);
365 attribute.getAttributeValues().add(attributeValue);
366 } else if (value instanceof XMLObject) {
367 attribute.getAttributeValues().add((XMLObject)value);
368 }
369 }
370
371 return attribute;
372 }
373
374
375
376
377
378
379
380 @SuppressWarnings("unchecked")
381 public static Subject createSaml2Subject(SubjectBean subjectBean)
382 throws org.opensaml.xml.security.SecurityException, WSSecurityException {
383 if (subjectBuilder == null) {
384 subjectBuilder = (SAMLObjectBuilder<Subject>)
385 builderFactory.getBuilder(Subject.DEFAULT_ELEMENT_NAME);
386 }
387 Subject subject = subjectBuilder.buildObject();
388
389 NameID nameID = SAML2ComponentBuilder.createNameID(subjectBean);
390 subject.setNameID(nameID);
391
392 SubjectConfirmationData subjectConfData = null;
393 if (subjectBean.getKeyInfo() != null || subjectBean.getSubjectConfirmationData() != null) {
394 subjectConfData =
395 SAML2ComponentBuilder.createSubjectConfirmationData(
396 subjectBean.getSubjectConfirmationData(),
397 subjectBean.getKeyInfo()
398 );
399 }
400
401 String confirmationMethodStr = subjectBean.getSubjectConfirmationMethod();
402 if (confirmationMethodStr == null) {
403 confirmationMethodStr = SAML2Constants.CONF_SENDER_VOUCHES;
404 }
405 SubjectConfirmation subjectConfirmation =
406 SAML2ComponentBuilder.createSubjectConfirmation(
407 confirmationMethodStr, subjectConfData
408 );
409
410 subject.getSubjectConfirmations().add(subjectConfirmation);
411 return subject;
412 }
413
414
415
416
417
418
419
420
421
422
423 @Deprecated
424 public static SubjectConfirmationData createSubjectConfirmationData(
425 String inResponseTo,
426 String recipient,
427 DateTime notOnOrAfter,
428 KeyInfoBean keyInfoBean
429 ) throws org.opensaml.xml.security.SecurityException, WSSecurityException {
430 SubjectConfirmationDataBean subjectConfirmationDataBean =
431 new SubjectConfirmationDataBean();
432 subjectConfirmationDataBean.setInResponseTo(inResponseTo);
433 subjectConfirmationDataBean.setRecipient(recipient);
434 subjectConfirmationDataBean.setNotAfter(notOnOrAfter);
435 return createSubjectConfirmationData(subjectConfirmationDataBean, keyInfoBean);
436 }
437
438
439
440
441
442
443
444
445 @SuppressWarnings("unchecked")
446 public static SubjectConfirmationData createSubjectConfirmationData(
447 SubjectConfirmationDataBean subjectConfirmationDataBean,
448 KeyInfoBean keyInfoBean
449 ) throws org.opensaml.xml.security.SecurityException, WSSecurityException {
450 SubjectConfirmationData subjectConfirmationData = null;
451 KeyInfo keyInfo = null;
452 if (keyInfoBean == null) {
453 if (subjectConfirmationDataBuilder == null) {
454 subjectConfirmationDataBuilder = (SAMLObjectBuilder<SubjectConfirmationData>)
455 builderFactory.getBuilder(SubjectConfirmationData.DEFAULT_ELEMENT_NAME);
456 }
457 subjectConfirmationData = subjectConfirmationDataBuilder.buildObject();
458 } else {
459 if (keyInfoConfirmationDataBuilder == null) {
460 keyInfoConfirmationDataBuilder = (SAMLObjectBuilder<KeyInfoConfirmationDataType>)
461 builderFactory.getBuilder(KeyInfoConfirmationDataType.TYPE_NAME);
462 }
463 subjectConfirmationData = keyInfoConfirmationDataBuilder.buildObject();
464 keyInfo = SAML1ComponentBuilder.createKeyInfo(keyInfoBean);
465 ((KeyInfoConfirmationDataType)subjectConfirmationData).getKeyInfos().add(keyInfo);
466 }
467
468 if (subjectConfirmationDataBean != null) {
469 if (subjectConfirmationDataBean.getInResponseTo() != null) {
470 subjectConfirmationData.setInResponseTo(subjectConfirmationDataBean.getInResponseTo());
471 }
472 if (subjectConfirmationDataBean.getRecipient() != null) {
473 subjectConfirmationData.setRecipient(subjectConfirmationDataBean.getRecipient());
474 }
475 if (subjectConfirmationDataBean.getAddress() != null) {
476 subjectConfirmationData.setAddress(subjectConfirmationDataBean.getAddress());
477 }
478 if (subjectConfirmationDataBean.getNotAfter() != null) {
479 subjectConfirmationData.setNotOnOrAfter(subjectConfirmationDataBean.getNotAfter());
480 }
481 if (subjectConfirmationDataBean.getNotBefore() != null) {
482 subjectConfirmationData.setNotBefore(subjectConfirmationDataBean.getNotBefore());
483 }
484 }
485
486 return subjectConfirmationData;
487 }
488
489
490
491
492
493
494
495
496
497
498
499
500 @SuppressWarnings("unchecked")
501 public static SubjectConfirmation createSubjectConfirmation(
502 String method,
503 SubjectConfirmationData subjectConfirmationData
504 ) {
505 if (subjectConfirmationBuilder == null) {
506 subjectConfirmationBuilder = (SAMLObjectBuilder<SubjectConfirmation>)
507 builderFactory.getBuilder(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
508 }
509
510 SubjectConfirmation subjectConfirmation = subjectConfirmationBuilder.buildObject();
511 subjectConfirmation.setMethod(method);
512 subjectConfirmation.setSubjectConfirmationData(subjectConfirmationData);
513 return subjectConfirmation;
514 }
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531 @SuppressWarnings("unchecked")
532 public static NameID createNameID(SubjectBean subject) {
533 if (nameIdBuilder == null) {
534 nameIdBuilder = (SAMLObjectBuilder<NameID>)
535 builderFactory.getBuilder(NameID.DEFAULT_ELEMENT_NAME);
536 }
537 NameID nameID = nameIdBuilder.buildObject();
538 nameID.setNameQualifier(subject.getSubjectNameQualifier());
539 nameID.setFormat(subject.getSubjectNameIDFormat());
540 nameID.setValue(subject.getSubjectName());
541 return nameID;
542 }
543
544
545
546
547
548
549
550
551 @SuppressWarnings("unchecked")
552 public static List<AttributeStatement> createAttributeStatement(
553 List<AttributeStatementBean> attributeData
554 ) {
555 List<AttributeStatement> attributeStatements = new ArrayList<AttributeStatement>();
556 if (attributeStatementBuilder == null) {
557 attributeStatementBuilder = (SAMLObjectBuilder<AttributeStatement>)
558 builderFactory.getBuilder(AttributeStatement.DEFAULT_ELEMENT_NAME);
559 }
560
561 if (attributeData != null && attributeData.size() > 0) {
562 for (AttributeStatementBean statementBean : attributeData) {
563 AttributeStatement attributeStatement = attributeStatementBuilder.buildObject();
564 for (AttributeBean values : statementBean.getSamlAttributes()) {
565 List<?> attributeValues = values.getAttributeValues();
566 if (attributeValues == null || attributeValues.isEmpty()) {
567 attributeValues = values.getCustomAttributeValues();
568 }
569 Attribute samlAttribute =
570 createAttribute(
571 values.getSimpleName(),
572 values.getQualifiedName(),
573 values.getNameFormat(),
574 attributeValues
575 );
576 attributeStatement.getAttributes().add(samlAttribute);
577 }
578
579 attributeStatements.add(attributeStatement);
580 }
581 }
582
583 return attributeStatements;
584 }
585
586
587
588
589
590
591
592
593
594
595
596
597 public static Attribute createAttribute(String friendlyName, String name) {
598 return createAttribute(friendlyName, name, (String)null);
599 }
600
601
602
603
604
605
606
607
608
609 @SuppressWarnings("unchecked")
610 public static Attribute createAttribute(String friendlyName, String name, String nameFormat) {
611 if (attributeBuilder == null) {
612 attributeBuilder = (SAMLObjectBuilder<Attribute>)
613 builderFactory.getBuilder(Attribute.DEFAULT_ELEMENT_NAME);
614 }
615
616 Attribute attribute = attributeBuilder.buildObject();
617 attribute.setFriendlyName(friendlyName);
618 if (nameFormat == null) {
619 attribute.setNameFormat(SAML2Constants.ATTRNAME_FORMAT_URI);
620 } else {
621 attribute.setNameFormat(nameFormat);
622 }
623 attribute.setName(name);
624 return attribute;
625 }
626
627
628
629
630
631
632
633 @SuppressWarnings("unchecked")
634 public static List<AuthzDecisionStatement> createAuthorizationDecisionStatement(
635 List<AuthDecisionStatementBean> decisionData
636 ) {
637 List<AuthzDecisionStatement> authDecisionStatements =
638 new ArrayList<AuthzDecisionStatement>();
639 if (authorizationDecisionStatementBuilder == null) {
640 authorizationDecisionStatementBuilder =
641 (SAMLObjectBuilder<AuthzDecisionStatement>)
642 builderFactory.getBuilder(AuthzDecisionStatement.DEFAULT_ELEMENT_NAME);
643 }
644
645 if (decisionData != null && decisionData.size() > 0) {
646 for (AuthDecisionStatementBean decisionStatementBean : decisionData) {
647 AuthzDecisionStatement authDecision =
648 authorizationDecisionStatementBuilder.buildObject();
649 authDecision.setResource(decisionStatementBean.getResource());
650 authDecision.setDecision(
651 transformDecisionType(decisionStatementBean.getDecision())
652 );
653
654 for (ActionBean actionBean : decisionStatementBean.getActions()) {
655 Action actionElement = createSamlAction(actionBean);
656 authDecision.getActions().add(actionElement);
657 }
658
659 if (decisionStatementBean.getEvidence() instanceof Evidence) {
660 authDecision.setEvidence((Evidence)decisionStatementBean.getEvidence());
661 }
662
663 authDecisionStatements.add(authDecision);
664 }
665 }
666
667 return authDecisionStatements;
668 }
669
670
671
672
673
674
675
676
677 @SuppressWarnings("unchecked")
678 public static Action createSamlAction(ActionBean actionBean) {
679 if (actionElementBuilder == null) {
680 actionElementBuilder = (SAMLObjectBuilder<Action>)
681 builderFactory.getBuilder(Action.DEFAULT_ELEMENT_NAME);
682 }
683 Action actionElement = actionElementBuilder.buildObject();
684 actionElement.setNamespace(actionBean.getActionNamespace());
685 if (actionBean.getActionNamespace() == null) {
686 actionElement.setNamespace("urn:oasis:names:tc:SAML:1.0:action:rwedc-negation");
687 }
688 actionElement.setAction(actionBean.getContents());
689
690 return actionElement;
691 }
692
693
694
695
696
697
698
699 private static DecisionTypeEnumeration transformDecisionType(
700 AuthDecisionStatementBean.Decision decision
701 ) {
702 DecisionTypeEnumeration decisionTypeEnum = DecisionTypeEnumeration.DENY;
703 if (decision.equals(AuthDecisionStatementBean.Decision.PERMIT)) {
704 decisionTypeEnum = DecisionTypeEnumeration.PERMIT;
705 } else if (decision.equals(AuthDecisionStatementBean.Decision.INDETERMINATE)) {
706 decisionTypeEnum = DecisionTypeEnumeration.INDETERMINATE;
707 }
708
709 return decisionTypeEnum;
710 }
711
712 }