View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
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   * Class SAML2ComponentBuilder provides builder methods that can be used
74   * to construct SAML v2.0 statements using the OpenSaml library.
75   * <p/>
76   * Created on May 18, 2009
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         // Complete
121     }
122     
123     /**
124      * Create a SAML 2 assertion
125      *
126      * @return a SAML 2 assertion
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      * Create an Issuer object
150      *
151      * @param issuerValue of type String
152      * @return an Issuer object
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         // The SAML authority that is making the claim(s) in the assertion. The issuer SHOULD 
164         // be unambiguous to the intended relying parties.
165         issuer.setValue(issuerValue);
166         return issuer;
167     }
168 
169     /**
170      * Create a Conditions object
171      *
172      * @param conditionsBean A ConditionsBean object
173      * @return a Conditions object
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      * Create an AudienceRestriction object
223      *
224      * @param audienceURI of type String
225      * @return an AudienceRestriction object
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      * Create SAML 2 Authentication Statement(s).
247      *
248      * @param authBeans A list of AuthenticationStatementBean instances
249      * @return SAML 2 Authentication Statement(s).
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      * Transform the user-supplied authentication method value into one of the supported 
313      * specification-compliant values.
314      *
315      * @param sourceMethod of type String
316      * @return String
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      * Create a SAML2 Attribute
332      *
333      * @param friendlyName of type String
334      * @param name         of type String
335      * @param values       of type ArrayList
336      * @return a SAML2 Attribute
337      * @deprecated
338      */
339     public static Attribute createAttribute(String friendlyName, String name, List<String> values) {
340         return createAttribute(friendlyName, name, null, values);
341     }
342     
343     /**
344      * Create a SAML2 Attribute
345      *
346      * @param friendlyName of type String
347      * @param name         of type String
348      * @param nameFormat   of type String
349      * @param values       of type ArrayList
350      * @return a SAML2 Attribute
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      * Create a Subject.
376      *
377      * @param subjectBean of type SubjectBean
378      * @return a Subject
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      * Create a SubjectConfirmationData object
416      *
417      * @param inResponseTo of type String
418      * @param recipient    of type String
419      * @param notOnOrAfter of type DateTime
420      * @param keyInfoBean of type KeyInfoBean
421      * @return a SubjectConfirmationData object
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      * Create a SubjectConfirmationData object
440      *
441      * @param subjectConfirmationDataBean of type SubjectConfirmationDataBean
442      * @param keyInfoBean of type KeyInfoBean
443      * @return a SubjectConfirmationData object
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      * Create a SubjectConfirmation object
491      * One of the following subject confirmation methods MUST be used:
492      *   urn:oasis:names:tc:SAML:2.0:cm:holder-of-key
493      *   urn:oasis:names:tc:SAML:2.0:cm:sender-vouches
494      *   urn:oasis:names:tc:SAML:2.0:cm:bearer
495      *
496      * @param method of type String
497      * @param subjectConfirmationData of type SubjectConfirmationData
498      * @return a SubjectConfirmation object
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      * Create a NameID object
518      * One of the following formats MUST be used:
519      *   urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
520      *   urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
521      *   urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
522      *   urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName
523      *   urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos
524      *   urn:oasis:names:tc:SAML:2.0:nameid-format:entity
525      *   urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
526      *   urn:oasis:names:tc:SAML:2.0:nameid-format:transient
527      *
528      * @param subject A SubjectBean instance
529      * @return NameID
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      * Create SAML2 Attribute Statement(s)
547      *
548      * @param attributeData A list of AttributeStatementBean instances
549      * @return SAML2 Attribute Statement(s)
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                 // Add the completed attribute statementBean to the collection
579                 attributeStatements.add(attributeStatement);
580             }
581         }
582 
583         return attributeStatements;
584     }
585 
586     /**
587      * Create an Attribute object. The name format is of type:
588      *   urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified
589      *   urn:oasis:names:tc:SAML:2.0:attrname-format:uri
590      *   urn:oasis:names:tc:SAML:2.0:attrname-format:basic
591      *
592      * @param friendlyName of type String
593      * @param name of type String
594      * @return an Attribute object
595      * @deprecated
596      */
597     public static Attribute createAttribute(String friendlyName, String name) {
598         return createAttribute(friendlyName, name, (String)null);
599     }
600     
601     /**
602      * Create an Attribute object.
603      *
604      * @param friendlyName of type String
605      * @param name of type String
606      * @param nameFormat of type String
607      * @return an Attribute object
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      * Create SAML2 AuthorizationDecisionStatement(s)
629      *
630      * @param decisionData A list of AuthDecisionStatementBean instances
631      * @return SAML2 AuthorizationDecisionStatement(s)
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      * Create an Action object
673      *
674      * @param actionBean An ActionBean instance
675      * @return an Action object
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      * Create a DecisionTypeEnumeration object
695      *
696      * @param decision of type Decision
697      * @return a DecisionTypeEnumeration object 
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 }