a30e1fd95cefb5293a21cd03b5fced9a7d5416cc
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / idp / profile / saml2 / AbstractSAML2ProfileHandler.java
1 /*
2  * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package edu.internet2.middleware.shibboleth.idp.profile.saml2;
18
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.List;
22
23 import javax.servlet.ServletRequest;
24 import javax.servlet.ServletResponse;
25
26 import org.joda.time.DateTime;
27 import org.opensaml.common.SAMLObjectBuilder;
28 import org.opensaml.common.SAMLVersion;
29 import org.opensaml.common.impl.SAMLObjectContentReference;
30 import org.opensaml.common.xml.SAMLConstants;
31 import org.opensaml.log.Level;
32 import org.opensaml.saml2.core.Advice;
33 import org.opensaml.saml2.core.Assertion;
34 import org.opensaml.saml2.core.Audience;
35 import org.opensaml.saml2.core.AudienceRestriction;
36 import org.opensaml.saml2.core.AuthnRequest;
37 import org.opensaml.saml2.core.Conditions;
38 import org.opensaml.saml2.core.Issuer;
39 import org.opensaml.saml2.core.NameID;
40 import org.opensaml.saml2.core.ProxyRestriction;
41 import org.opensaml.saml2.core.RequestAbstractType;
42 import org.opensaml.saml2.core.Response;
43 import org.opensaml.saml2.core.Statement;
44 import org.opensaml.saml2.core.Status;
45 import org.opensaml.saml2.core.StatusCode;
46 import org.opensaml.saml2.core.StatusMessage;
47 import org.opensaml.saml2.core.StatusResponseType;
48 import org.opensaml.saml2.core.Subject;
49 import org.opensaml.saml2.core.SubjectConfirmation;
50 import org.opensaml.saml2.metadata.AttributeAuthorityDescriptor;
51 import org.opensaml.saml2.metadata.AuthnAuthorityDescriptor;
52 import org.opensaml.saml2.metadata.NameIDFormat;
53 import org.opensaml.saml2.metadata.PDPDescriptor;
54 import org.opensaml.saml2.metadata.RoleDescriptor;
55 import org.opensaml.saml2.metadata.SSODescriptor;
56 import org.opensaml.saml2.metadata.provider.MetadataProviderException;
57 import org.opensaml.xml.XMLObjectBuilder;
58 import org.opensaml.xml.security.credential.Credential;
59 import org.opensaml.xml.signature.Signature;
60 import org.opensaml.xml.signature.Signer;
61 import org.opensaml.xml.util.DatatypeHelper;
62
63 import edu.internet2.middleware.shibboleth.common.attribute.AttributeRequestException;
64 import edu.internet2.middleware.shibboleth.common.log.AuditLogEntry;
65 import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
66 import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
67 import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
68 import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml2.AbstractSAML2ProfileConfiguration;
69 import edu.internet2.middleware.shibboleth.idp.profile.AbstractSAMLProfileHandler;
70
71 /**
72  * Common implementation details for profile handlers.
73  */
74 public abstract class AbstractSAML2ProfileHandler extends AbstractSAMLProfileHandler {
75
76     /** SAML Version for this profile handler. */
77     public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_20;
78
79     /** URI for the SAML 2 protocol. */
80     public static final String SAML20_PROTOCOL_URI = "urn:oasis:names:tc:SAML:2.0:protocol";
81
82     /** For building response. */
83     private SAMLObjectBuilder<Response> responseBuilder;
84
85     /** For building status. */
86     private SAMLObjectBuilder<Status> statusBuilder;
87
88     /** For building statuscode. */
89     private SAMLObjectBuilder<StatusCode> statusCodeBuilder;
90
91     /** For building StatusMessages. */
92     private SAMLObjectBuilder<StatusMessage> statusMessageBuilder;
93
94     /** For building assertion. */
95     private SAMLObjectBuilder<Assertion> assertionBuilder;
96
97     /** For building issuer. */
98     private SAMLObjectBuilder<Issuer> issuerBuilder;
99
100     /** For building subject. */
101     private SAMLObjectBuilder<Subject> subjectBuilder;
102
103     /** For builder subject confirmation. */
104     private SAMLObjectBuilder<SubjectConfirmation> subjectConfirmationBuilder;
105
106     /** For building conditions. */
107     private SAMLObjectBuilder<Conditions> conditionsBuilder;
108
109     /** For building audience restriction. */
110     private SAMLObjectBuilder<AudienceRestriction> audienceRestrictionBuilder;
111
112     /** For building proxy retrictions. */
113     private SAMLObjectBuilder<ProxyRestriction> proxyRestrictionBuilder;
114
115     /** For building audience. */
116     private SAMLObjectBuilder<Audience> audienceBuilder;
117
118     /** For building advice. */
119     private SAMLObjectBuilder<Advice> adviceBuilder;
120
121     /** For building signature. */
122     private XMLObjectBuilder<Signature> signatureBuilder;
123
124     /** Constructor. */
125     @SuppressWarnings("unchecked")
126     protected AbstractSAML2ProfileHandler() {
127         super();
128
129         responseBuilder = (SAMLObjectBuilder<Response>) getBuilderFactory().getBuilder(Response.DEFAULT_ELEMENT_NAME);
130         statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(Status.DEFAULT_ELEMENT_NAME);
131         statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory().getBuilder(
132                 StatusCode.DEFAULT_ELEMENT_NAME);
133         statusMessageBuilder = (SAMLObjectBuilder<StatusMessage>) getBuilderFactory().getBuilder(
134                 StatusMessage.DEFAULT_ELEMENT_NAME);
135         issuerBuilder = (SAMLObjectBuilder<Issuer>) getBuilderFactory().getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
136         assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory()
137                 .getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
138         subjectBuilder = (SAMLObjectBuilder<Subject>) getBuilderFactory().getBuilder(Subject.DEFAULT_ELEMENT_NAME);
139         subjectConfirmationBuilder = (SAMLObjectBuilder<SubjectConfirmation>) getBuilderFactory().getBuilder(
140                 SubjectConfirmation.DEFAULT_ELEMENT_NAME);
141         conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory().getBuilder(
142                 Conditions.DEFAULT_ELEMENT_NAME);
143         audienceRestrictionBuilder = (SAMLObjectBuilder<AudienceRestriction>) getBuilderFactory().getBuilder(
144                 AudienceRestriction.DEFAULT_ELEMENT_NAME);
145         proxyRestrictionBuilder = (SAMLObjectBuilder<ProxyRestriction>) getBuilderFactory().getBuilder(
146                 ProxyRestriction.DEFAULT_ELEMENT_NAME);
147         audienceBuilder = (SAMLObjectBuilder<Audience>) getBuilderFactory().getBuilder(Audience.DEFAULT_ELEMENT_NAME);
148         adviceBuilder = (SAMLObjectBuilder<Advice>) getBuilderFactory().getBuilder(Advice.DEFAULT_ELEMENT_NAME);
149         signatureBuilder = (XMLObjectBuilder<Signature>) getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME);
150     }
151
152     /**
153      * Convenience method for getting the SAML 2 advice builder.
154      * 
155      * @return SAML 2 advice builder
156      */
157     public SAMLObjectBuilder<Advice> getAdviceBuilder() {
158         return adviceBuilder;
159     }
160
161     /**
162      * Convenience method for getting the SAML 2 assertion builder.
163      * 
164      * @return SAML 2 assertion builder
165      */
166     public SAMLObjectBuilder<Assertion> getAssertionBuilder() {
167         return assertionBuilder;
168     }
169
170     /**
171      * Convenience method for getting the SAML 2 audience builder.
172      * 
173      * @return SAML 2 audience builder
174      */
175     public SAMLObjectBuilder<Audience> getAudienceBuilder() {
176         return audienceBuilder;
177     }
178
179     /**
180      * Convenience method for getting the SAML 2 audience restriction builder.
181      * 
182      * @return SAML 2 audience restriction builder
183      */
184     public SAMLObjectBuilder<AudienceRestriction> getAudienceRestrictionBuilder() {
185         return audienceRestrictionBuilder;
186     }
187
188     /**
189      * Convenience method for getting the SAML 2 conditions builder.
190      * 
191      * @return SAML 2 conditions builder
192      */
193     public SAMLObjectBuilder<Conditions> getConditionsBuilder() {
194         return conditionsBuilder;
195     }
196
197     /**
198      * Convenience method for getting the SAML 2 Issuer builder.
199      * 
200      * @return SAML 2 Issuer builder
201      */
202     public SAMLObjectBuilder<Issuer> getIssuerBuilder() {
203         return issuerBuilder;
204     }
205
206     /**
207      * Convenience method for getting the SAML 2 proxy restriction builder.
208      * 
209      * @return SAML 2 proxy restriction builder
210      */
211     public SAMLObjectBuilder<ProxyRestriction> getProxyRestrictionBuilder() {
212         return proxyRestrictionBuilder;
213     }
214
215     /**
216      * Convenience method for getting the SAML 2 response builder.
217      * 
218      * @return SAML 2 response builder
219      */
220     public SAMLObjectBuilder<Response> getResponseBuilder() {
221         return responseBuilder;
222     }
223
224     /**
225      * Convenience method for getting the Signature builder.
226      * 
227      * @return signature builder
228      */
229     public XMLObjectBuilder<Signature> getSignatureBuilder() {
230         return signatureBuilder;
231     }
232
233     /**
234      * Convenience method for getting the SAML 2 status builder.
235      * 
236      * @return SAML 2 status builder
237      */
238     public SAMLObjectBuilder<Status> getStatusBuilder() {
239         return statusBuilder;
240     }
241
242     /**
243      * Convenience method for getting the SAML 2 status code builder.
244      * 
245      * @return SAML 2 status code builder
246      */
247     public SAMLObjectBuilder<StatusCode> getStatusCodeBuilder() {
248         return statusCodeBuilder;
249     }
250
251     /**
252      * Convenience method for getting the SAML 2 status message builder.
253      * 
254      * @return SAML 2 status message builder
255      */
256     public SAMLObjectBuilder<StatusMessage> getStatusMessageBuilder() {
257         return statusMessageBuilder;
258     }
259
260     /**
261      * Convenience method for getting the SAML 2 subject builder.
262      * 
263      * @return SAML 2 subject builder
264      */
265     public SAMLObjectBuilder<Subject> getSubjectBuilder() {
266         return subjectBuilder;
267     }
268
269     /**
270      * Convenience method for getting the SAML 2 subject confirmation builder.
271      * 
272      * @return SAML 2 subject confirmation builder
273      */
274     public SAMLObjectBuilder<SubjectConfirmation> getSubjectConfirmationBuilder() {
275         return subjectConfirmationBuilder;
276     }
277
278     /**
279      * Builds a response to the attribute query within the request context.
280      * 
281      * @param requestContext current request context
282      * @param assertionSubject subject of the assertion within the response
283      * @param statements the statements to include in the response
284      * 
285      * @return the built response
286      * 
287      * @throws ProfileException thrown if there is a problem creating the SAML response
288      * @throws AttributeRequestException thrown if there is a problem resolving attributes
289      */
290     protected Response buildResponse(SAML2ProfileRequestContext requestContext, Subject assertionSubject,
291             List<Statement> statements) throws ProfileException, AttributeRequestException {
292
293         DateTime issueInstant = new DateTime();
294
295         // create the assertion and add the attribute statement
296         Assertion assertion = buildAssertion(requestContext, issueInstant);
297         assertion.setSubject(assertionSubject);
298         if (statements != null) {
299             assertion.getStatements().addAll(statements);
300         }
301
302         // create the SAML response and add the assertion
303         Response samlResponse = getResponseBuilder().buildObject();
304         populateStatusResponse(requestContext, samlResponse);
305
306         samlResponse.getAssertions().add(assertion);
307
308         // sign the assertion if it should be signed
309         signAssertion(requestContext, assertion);
310
311         Status status = buildStatus(StatusCode.SUCCESS_URI, null, null);
312         samlResponse.setStatus(status);
313
314         return samlResponse;
315     }
316
317     /**
318      * Builds a basic assertion with its id, issue instant, SAML version, issuer, subject, and conditions populated.
319      * 
320      * @param requestContext current request context
321      * @param issueInstant time to use as assertion issue instant
322      * 
323      * @return the built assertion
324      */
325     protected Assertion buildAssertion(SAML2ProfileRequestContext requestContext, DateTime issueInstant) {
326
327         Assertion assertion = getAssertionBuilder().buildObject();
328         assertion.setID(getIdGenerator().generateIdentifier());
329         assertion.setIssueInstant(issueInstant);
330         assertion.setVersion(SAMLVersion.VERSION_20);
331         assertion.setIssuer(buildEntityIssuer(requestContext));
332
333         Conditions conditions = buildConditions(requestContext, issueInstant);
334         assertion.setConditions(conditions);
335
336         return assertion;
337     }
338
339     /**
340      * Creates an {@link Issuer} populated with information about the relying party.
341      * 
342      * @param requestContext current request context
343      * 
344      * @return the built issuer
345      */
346     protected Issuer buildEntityIssuer(SAML2ProfileRequestContext requestContext) {
347         Issuer issuer = getIssuerBuilder().buildObject();
348         issuer.setFormat(Issuer.ENTITY);
349         issuer.setValue(requestContext.getRelyingPartyId());
350
351         return issuer;
352     }
353
354     /**
355      * Builds a SAML assertion condition set. The following fields are set; not before, not on or after, audience
356      * restrictions, and proxy restrictions.
357      * 
358      * @param requestContext current request context
359      * @param issueInstant timestamp the assertion was created
360      * 
361      * @return constructed conditions
362      */
363     protected Conditions buildConditions(SAML2ProfileRequestContext requestContext, DateTime issueInstant) {
364         AbstractSAML2ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
365
366         Conditions conditions = getConditionsBuilder().buildObject();
367         conditions.setNotBefore(issueInstant);
368         conditions.setNotOnOrAfter(issueInstant.plus(profileConfig.getAssertionLifetime()));
369
370         Collection<String> audiences;
371
372         // add audience restrictions
373         audiences = profileConfig.getAssertionAudiences();
374         if (audiences != null && audiences.size() > 0) {
375             AudienceRestriction audienceRestriction = getAudienceRestrictionBuilder().buildObject();
376             for (String audienceUri : audiences) {
377                 Audience audience = getAudienceBuilder().buildObject();
378                 audience.setAudienceURI(audienceUri);
379                 audienceRestriction.getAudiences().add(audience);
380             }
381             conditions.getAudienceRestrictions().add(audienceRestriction);
382         }
383
384         // add proxy restrictions
385         audiences = profileConfig.getProxyAudiences();
386         if (audiences != null && audiences.size() > 0) {
387             ProxyRestriction proxyRestriction = getProxyRestrictionBuilder().buildObject();
388             Audience audience;
389             for (String audienceUri : audiences) {
390                 audience = getAudienceBuilder().buildObject();
391                 audience.setAudienceURI(audienceUri);
392                 proxyRestriction.getAudiences().add(audience);
393             }
394
395             proxyRestriction.setProxyCount(profileConfig.getProxyCount());
396             conditions.getConditions().add(proxyRestriction);
397         }
398
399         return conditions;
400     }
401
402     /**
403      * Populates the response's id, in response to, issue instant, version, and issuer properties.
404      * 
405      * @param requestContext current request context
406      * @param response the response to populate
407      */
408     protected void populateStatusResponse(SAML2ProfileRequestContext requestContext, StatusResponseType response) {
409         response.setID(getIdGenerator().generateIdentifier());
410         response.setInResponseTo(requestContext.getSamlRequest().getID());
411         response.setIssueInstant(response.getIssueInstant());
412         response.setVersion(SAMLVersion.VERSION_20);
413         response.setIssuer(buildEntityIssuer(requestContext));
414     }
415
416     /**
417      * Signs the given assertion if either the current profile configuration or the relying party configuration contains
418      * signing credentials.
419      * 
420      * @param requestContext current request context
421      * @param assertion assertion to sign
422      */
423     protected void signAssertion(SAML2ProfileRequestContext requestContext, Assertion assertion) {
424         AbstractSAML2ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
425
426         if (!profileConfig.getSignAssertions()) {
427             return;
428         }
429
430         Credential signatureCredential = profileConfig.getSigningCredential();
431         if (signatureCredential == null) {
432             signatureCredential = requestContext.getRelyingPartyConfiguration().getDefaultSigningCredential();
433         }
434
435         if (signatureCredential == null) {
436             return;
437         }
438
439         SAMLObjectContentReference contentRef = new SAMLObjectContentReference(assertion);
440         Signature signature = signatureBuilder.buildObject(Signature.DEFAULT_ELEMENT_NAME);
441         signature.getContentReferences().add(contentRef);
442         assertion.setSignature(signature);
443
444         Signer.signObject(signature);
445     }
446
447     /**
448      * Build a status message, with an optional second-level failure message.
449      * 
450      * @param topLevelCode The top-level status code. Should be from saml-core-2.0-os, sec. 3.2.2.2
451      * @param secondLevelCode An optional second-level failure code. Should be from saml-core-2.0-is, sec 3.2.2.2. If
452      *            null, no second-level Status element will be set.
453      * @param secondLevelFailureMessage An optional second-level failure message
454      * 
455      * @return a Status object.
456      */
457     protected Status buildStatus(String topLevelCode, String secondLevelCode, String secondLevelFailureMessage) {
458
459         Status status = getStatusBuilder().buildObject();
460
461         StatusCode statusCode = getStatusCodeBuilder().buildObject();
462         statusCode.setValue(DatatypeHelper.safeTrimOrNullString(topLevelCode));
463         status.setStatusCode(statusCode);
464
465         if (secondLevelCode != null) {
466             StatusCode secondLevelStatusCode = getStatusCodeBuilder().buildObject();
467             secondLevelStatusCode.setValue(DatatypeHelper.safeTrimOrNullString(secondLevelCode));
468             statusCode.setStatusCode(secondLevelStatusCode);
469         }
470
471         if (secondLevelFailureMessage != null) {
472             StatusMessage msg = getStatusMessageBuilder().buildObject();
473             msg.setMessage(secondLevelFailureMessage);
474             status.setStatusMessage(msg);
475         }
476
477         return status;
478     }
479
480     /**
481      * Builds the SAML subject for the user for the service provider.
482      * 
483      * @param requestContext current request context
484      * @param confirmationMethod subject confirmation method used for the subject
485      * 
486      * @return SAML subject for the user for the service provider
487      */
488     protected Subject buildSubject(SAML2ProfileRequestContext requestContext, String confirmationMethod) {
489         NameID nameID = requestContext.getSubjectNameID();
490         // TODO handle encryption
491
492         SubjectConfirmation subjectConfirmation = getSubjectConfirmationBuilder().buildObject();
493         subjectConfirmation.setMethod(confirmationMethod);
494
495         Subject subject = getSubjectBuilder().buildObject();
496         subject.setNameID(nameID);
497         subject.getSubjectConfirmations().add(subjectConfirmation);
498
499         return subject;
500     }
501
502     /**
503      * Constructs an SAML response message carrying a request error.
504      * 
505      * @param requestContext current request context
506      * @param topLevelCode The top-level status code. Should be from saml-core-2.0-os, sec. 3.2.2.2
507      * @param secondLevelCode An optional second-level failure code. Should be from saml-core-2.0-is, sec 3.2.2.2. If
508      *            null, no second-level Status element will be set.
509      * @param secondLevelFailureMessage An optional second-level failure message
510      * 
511      * @return the constructed error response
512      */
513     protected Response buildErrorResponse(SAML2ProfileRequestContext requestContext, String topLevelCode,
514             String secondLevelCode, String secondLevelFailureMessage) {
515         Response samlResponse = getResponseBuilder().buildObject();
516         samlResponse.setIssueInstant(new DateTime());
517         populateStatusResponse(requestContext, samlResponse);
518
519         Status status = buildStatus(topLevelCode, secondLevelCode, secondLevelFailureMessage);
520         samlResponse.setStatus(status);
521
522         return samlResponse;
523     }
524
525     /**
526      * Gets the NameID format to use when creating NameIDs for the relying party.
527      * 
528      * @param requestContext current request context
529      * 
530      * @return list of nameID formats that may be used with the relying party
531      * 
532      * @throws ProfileException thrown if there is a problem determing the NameID format to use
533      */
534     protected List<String> getNameIDFormat(SAML2ProfileRequestContext requestContext) throws ProfileException {
535         ArrayList<String> nameFormats = new ArrayList<String>();
536
537         try {
538             RoleDescriptor assertingPartyRole = getMetadataProvider().getRole(requestContext.getAssertingPartyId(),
539                     requestContext.getAssertingPartyRole(), SAMLConstants.SAML20P_NS);
540             List<String> assertingPartySupportedFormats = getEntitySupportedFormats(assertingPartyRole);
541
542             String nameFormat = null;
543             if (requestContext.getSamlRequest() instanceof AuthnRequest) {
544                 AuthnRequest authnRequest = (AuthnRequest) requestContext.getSamlRequest();
545                 if (authnRequest.getNameIDPolicy() != null) {
546                     nameFormat = authnRequest.getNameIDPolicy().getFormat();
547                     if (assertingPartySupportedFormats.contains(nameFormat)) {
548                         nameFormats.add(nameFormat);
549                     } else {
550                         throw new ProfileException("NameID format required by relying party is not supported");
551                     }
552                 }
553             }
554
555             if (nameFormats.isEmpty()) {
556                 RoleDescriptor relyingPartyRole = getMetadataProvider().getRole(requestContext.getRelyingPartyId(),
557                         requestContext.getRelyingPartyRole(), SAMLConstants.SAML20P_NS);
558                 List<String> relyingPartySupportedFormats = getEntitySupportedFormats(relyingPartyRole);
559
560                 assertingPartySupportedFormats.retainAll(relyingPartySupportedFormats);
561                 nameFormats.addAll(assertingPartySupportedFormats);
562             }
563             if (nameFormats.isEmpty()) {
564                 nameFormats.add("urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified");
565             }
566
567             return nameFormats;
568
569         } catch (MetadataProviderException e) {
570             throw new ProfileException("Unable to determine lookup entity metadata", e);
571         }
572     }
573
574     /**
575      * Gets the list of NameID formats supported for a given role.
576      * 
577      * @param role the role to get the list of supported NameID formats
578      * 
579      * @return list of supported NameID formats
580      */
581     protected List<String> getEntitySupportedFormats(RoleDescriptor role) {
582         List<NameIDFormat> nameIDFormats = null;
583
584         if (role instanceof SSODescriptor) {
585             nameIDFormats = ((SSODescriptor) role).getNameIDFormats();
586         } else if (role instanceof AuthnAuthorityDescriptor) {
587             nameIDFormats = ((AuthnAuthorityDescriptor) role).getNameIDFormats();
588         } else if (role instanceof PDPDescriptor) {
589             nameIDFormats = ((PDPDescriptor) role).getNameIDFormats();
590         } else if (role instanceof AttributeAuthorityDescriptor) {
591             nameIDFormats = ((AttributeAuthorityDescriptor) role).getNameIDFormats();
592         }
593
594         ArrayList<String> supportedFormats = new ArrayList<String>();
595         if (nameIDFormats != null) {
596             for (NameIDFormat format : nameIDFormats) {
597                 supportedFormats.add(format.getFormat());
598             }
599         }
600
601         return supportedFormats;
602     }
603
604     /**
605      * Writes an aduit log entry indicating the successful response to the attribute request.
606      * 
607      * @param context current request context
608      */
609     protected void writeAuditLogEntry(SAML2ProfileRequestContext context) {
610         AuditLogEntry auditLogEntry = new AuditLogEntry();
611         auditLogEntry.setMessageProfile(getProfileId());
612         auditLogEntry.setPrincipalAuthenticationMethod(context.getPrincipalAuthenticationMethod());
613         auditLogEntry.setPrincipalName(context.getPrincipalName());
614         auditLogEntry.setAssertingPartyId(context.getAssertingPartyId());
615         auditLogEntry.setRelyingPartyId(context.getRelyingPartyId());
616         auditLogEntry.setRequestBinding(context.getMessageDecoder().getBindingURI());
617         auditLogEntry.setRequestId(context.getSamlRequest().getID());
618         auditLogEntry.setResponseBinding(context.getMessageEncoder().getBindingURI());
619         auditLogEntry.setResponseId(context.getSamlResponse().getID());
620         getAduitLog().log(Level.CRITICAL, auditLogEntry);
621     }
622
623     /**
624      * Contextual object used to accumlate information as profile requests are being processed.
625      * 
626      * @param <RequestType> type of SAML 2 request
627      * @param <ResponseType> type of SAML 2 response
628      * @param <ProfileConfigurationType> configuration type for this profile
629      */
630     protected class SAML2ProfileRequestContext<RequestType extends RequestAbstractType, 
631                                                ResponseType extends StatusResponseType, 
632                                                ProfileConfigurationType extends AbstractSAML2ProfileConfiguration>
633             extends SAMLProfileRequestContext {
634
635         /** SAML request message. */
636         private RequestType samlRequest;
637
638         /** SAML response message. */
639         private ResponseType samlResponse;
640
641         /** Request profile configuration. */
642         private ProfileConfigurationType profileConfiguration;
643
644         /** The NameID of the subject of this request. */
645         private NameID subjectNameID;
646
647         /**
648          * Constructor.
649          * 
650          * @param request current profile request
651          * @param response current profile response
652          */
653         public SAML2ProfileRequestContext(ProfileRequest<ServletRequest> request,
654                 ProfileResponse<ServletResponse> response) {
655             super(request, response);
656         }
657
658         /**
659          * Gets the NameID of the subject of this request.
660          * 
661          * @return NameID of the subject of this request
662          */
663         public NameID getSubjectNameID() {
664             return subjectNameID;
665         }
666
667         /**
668          * Sets the NameID of the subject of this request.
669          * 
670          * @param nameID NameID of the subject of this request
671          */
672         public void setSubjectNameID(NameID nameID) {
673             subjectNameID = nameID;
674         }
675
676         /**
677          * Gets the profile configuration for this request.
678          * 
679          * @return profile configuration for this request
680          */
681         public ProfileConfigurationType getProfileConfiguration() {
682             return profileConfiguration;
683         }
684
685         /**
686          * Sets the profile configuration for this request.
687          * 
688          * @param configuration profile configuration for this request
689          */
690         public void setProfileConfiguration(ProfileConfigurationType configuration) {
691             profileConfiguration = configuration;
692         }
693
694         /**
695          * Gets the SAML request message.
696          * 
697          * @return SAML request message
698          */
699         public RequestType getSamlRequest() {
700             return samlRequest;
701         }
702
703         /**
704          * Sets the SAML request message.
705          * 
706          * @param request SAML request message
707          */
708         public void setSamlRequest(RequestType request) {
709             samlRequest = request;
710         }
711
712         /**
713          * Gets the SAML response message.
714          * 
715          * @return SAML response message
716          */
717         public ResponseType getSamlResponse() {
718             return samlResponse;
719         }
720
721         /**
722          * Sets the SAML response message.
723          * 
724          * @param response SAML response message
725          */
726         public void setSamlResponse(ResponseType response) {
727             samlResponse = response;
728         }
729     }
730 }