b698821c68e129812bff257bc11920ff80408c8c
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / idp / provider / ShibbolethV1SSOHandler.java
1 /*
2  * Copyright [2005] [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.provider;
18
19 import java.io.IOException;
20 import java.io.UnsupportedEncodingException;
21 import java.net.URLEncoder;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.Date;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Vector;
30
31 import javax.servlet.RequestDispatcher;
32 import javax.servlet.ServletException;
33 import javax.servlet.http.HttpServletRequest;
34 import javax.servlet.http.HttpServletResponse;
35
36 import org.apache.log4j.Logger;
37 import org.bouncycastle.util.encoders.Base64;
38 import org.opensaml.SAMLAssertion;
39 import org.opensaml.SAMLAttribute;
40 import org.opensaml.SAMLAttributeStatement;
41 import org.opensaml.SAMLAudienceRestrictionCondition;
42 import org.opensaml.SAMLAuthenticationStatement;
43 import org.opensaml.SAMLAuthorityBinding;
44 import org.opensaml.SAMLBrowserProfile;
45 import org.opensaml.SAMLCondition;
46 import org.opensaml.SAMLException;
47 import org.opensaml.SAMLNameIdentifier;
48 import org.opensaml.SAMLRequest;
49 import org.opensaml.SAMLResponse;
50 import org.opensaml.SAMLStatement;
51 import org.opensaml.SAMLSubject;
52 import org.opensaml.SAMLSubjectStatement;
53 import org.opensaml.artifact.Artifact;
54 import org.opensaml.saml2.metadata.AssertionConsumerService;
55 import org.opensaml.saml2.metadata.EntityDescriptor;
56 import org.opensaml.saml2.metadata.SPSSODescriptor;
57 import org.opensaml.saml2.metadata.provider.MetadataProviderException;
58 import org.w3c.dom.Element;
59
60 import edu.internet2.middleware.shibboleth.aa.AAException;
61 import edu.internet2.middleware.shibboleth.common.LocalPrincipal;
62 import edu.internet2.middleware.shibboleth.common.NameIdentifierMappingException;
63 import edu.internet2.middleware.shibboleth.common.RelyingParty;
64 import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
65 import edu.internet2.middleware.shibboleth.idp.IdPProtocolHandler;
66 import edu.internet2.middleware.shibboleth.idp.IdPProtocolSupport;
67 import edu.internet2.middleware.shibboleth.idp.InvalidClientDataException;
68
69 /**
70  * <code>ProtocolHandler</code> implementation that responds to SSO flows as specified in "Shibboleth Architecture:
71  * Protocols and Profiles".
72  * 
73  * @author Walter Hoehn
74  */
75 public class ShibbolethV1SSOHandler extends SSOHandler implements IdPProtocolHandler {
76
77         private static Logger log = Logger.getLogger(ShibbolethV1SSOHandler.class.getName());
78
79         /**
80          * Required DOM-based constructor.
81          */
82         public ShibbolethV1SSOHandler(Element config) throws ShibbolethConfigurationException {
83
84                 super(config);
85         }
86
87         /*
88          * @see edu.internet2.middleware.shibboleth.idp.IdPResponder.ProtocolHandler#processRequest(javax.servlet.http.HttpServletRequest,
89          *      javax.servlet.http.HttpServletResponse)
90          */
91         public SAMLResponse processRequest(HttpServletRequest request, HttpServletResponse response,
92                         SAMLRequest samlRequest, IdPProtocolSupport support) throws SAMLException, ServletException, IOException {
93
94                 if (request == null) {
95                         log.error("Protocol Handler received a SAML Request, but is unable to handle it.");
96                         throw new SAMLException(SAMLException.RESPONDER, "General error processing request.");
97                 }
98
99                 // Set attributes that are needed by the jsp
100                 request.setAttribute("shire", request.getParameter("shire"));
101                 request.setAttribute("target", request.getParameter("target"));
102
103                 try {
104                         // Ensure that we have the required data from the servlet container
105                         validateEngineData(request);
106                         validateShibSpecificData(request);
107
108                         // Get the authN info
109                         String username = support.getIdPConfig().getAuthHeaderName().equalsIgnoreCase("REMOTE_USER") ? request
110                                         .getRemoteUser() : request.getHeader(support.getIdPConfig().getAuthHeaderName());
111                         if ((username == null) || (username.equals(""))) { throw new InvalidClientDataException(
112                                         "Unauthenticated principal. This protocol handler requires that authentication information be "
113                                                         + "provided from the servlet container."); }
114                         LocalPrincipal principal = new LocalPrincipal(username);
115
116                         // Select the appropriate Relying Party configuration for the request
117                         RelyingParty relyingParty = null;
118                         String remoteProviderId = request.getParameter("providerId");
119                         // If the SP did not send a Provider Id, then assume it is a Shib
120                         // 1.1 or older SP
121                         if (remoteProviderId == null || remoteProviderId.equals("")) {
122                                 throw new InvalidClientDataException("Invalid or missing service provider id.");
123                         } else {
124                                 log.debug("Remote provider has identified itself as: (" + remoteProviderId + ").");
125                                 relyingParty = support.getServiceProviderMapper().getRelyingParty(remoteProviderId);
126                         }
127
128                         // Grab the metadata for the provider
129                         EntityDescriptor descriptor = null;
130                         try {
131                                 descriptor = support.getEntityDescriptor(relyingParty.getProviderId());
132                         } catch (MetadataProviderException e1) {
133                                 log.error("Metadata lookup for provider (" + relyingParty.getProviderId() + ") encountered an error: "
134                                                 + e1);
135                         }
136
137                         // Make sure that the selected relying party configuration is appropriate for this
138                         // acceptance URL
139                         String acceptanceURL = request.getParameter("shire");
140
141                         if (descriptor == null) {
142                                 log.info("No metadata found for provider: (" + relyingParty.getProviderId() + ").");
143                                 relyingParty = support.getServiceProviderMapper().getRelyingParty(null);
144
145                         } else {
146                                 if (isValidAssertionConsumerURL(descriptor, acceptanceURL)) {
147                                         log.info("Supplied consumer URL validated for this provider.");
148                                 } else {
149                                         log.error("Assertion consumer service URL (" + acceptanceURL + ") is NOT valid for provider ("
150                                                         + relyingParty.getProviderId() + ").");
151                                         throw new InvalidClientDataException("Invalid assertion consumer service URL.");
152                                 }
153                         }
154
155                         // Create SAML Name Identifier & Subject
156                         SAMLNameIdentifier nameId;
157                         try {
158                                 nameId = getNameIdentifier(support.getNameMapper(), principal, relyingParty, descriptor);
159                         } catch (NameIdentifierMappingException e) {
160                                 log.error("Error converting principal to SAML Name Identifier: " + e);
161                                 throw new SAMLException("Error converting principal to SAML Name Identifier.", e);
162                         }
163
164                         String authenticationMethod = request.getHeader("SAMLAuthenticationMethod");
165                         if (authenticationMethod == null || authenticationMethod.equals("")) {
166                                 authenticationMethod = relyingParty.getDefaultAuthMethod().toString();
167                                 log.debug("User was authenticated via the default method for this relying party ("
168                                                 + authenticationMethod + ").");
169                         } else {
170                                 log.debug("User was authenticated via the method (" + authenticationMethod + ").");
171                         }
172
173                         SAMLSubject authNSubject = new SAMLSubject(nameId, null, null, null);
174
175                         // Is this artifact or POST?
176                         boolean artifactProfile = useArtifactProfile(descriptor, acceptanceURL, relyingParty);
177
178                         // SAML Artifact profile - don't even attempt this for legacy providers (they don't support it)
179                         if (artifactProfile) {
180                                 respondWithArtifact(request, response, support, principal, relyingParty, descriptor, acceptanceURL,
181                                                 nameId, authenticationMethod, authNSubject);
182
183                                 // SAML POST profile
184                         } else {
185                                 respondWithPOST(request, response, support, principal, relyingParty, descriptor, acceptanceURL, nameId,
186                                                 authenticationMethod, authNSubject);
187                         }
188                 } catch (InvalidClientDataException e) {
189                         throw new SAMLException(SAMLException.RESPONDER, e.getMessage());
190                 }
191                 return null;
192         }
193
194         private void respondWithArtifact(HttpServletRequest request, HttpServletResponse response,
195                         IdPProtocolSupport support, LocalPrincipal principal, RelyingParty relyingParty,
196                         EntityDescriptor descriptor, String acceptanceURL, SAMLNameIdentifier nameId, String authenticationMethod,
197                         SAMLSubject authNSubject) throws SAMLException, IOException, UnsupportedEncodingException {
198
199                 log.debug("Responding with Artifact profile.");
200                 ArrayList<SAMLAssertion> assertions = new ArrayList<SAMLAssertion>();
201
202                 authNSubject.addConfirmationMethod(SAMLSubject.CONF_ARTIFACT);
203                 assertions.add(generateAuthNAssertion(request, relyingParty, descriptor, nameId, authenticationMethod,
204                                 getAuthNTime(request), authNSubject));
205
206                 // Package attributes for push, if necessary.
207                 if (pushAttributes(true, relyingParty)) {
208                         log.info("Resolving attributes for push.");
209                         generateAttributes(support, principal, relyingParty, assertions, request);
210                 }
211
212                 // Sign the assertions, if necessary
213                 boolean metaDataIndicatesSignAssertions = false;
214                 if (descriptor != null) {
215                         SPSSODescriptor sp = descriptor.getSPSSODescriptor(org.opensaml.XML.SAML11_PROTOCOL_ENUM);
216                         if (sp != null) {
217                                 if (sp.getWantAssertionsSigned()) {
218                                         metaDataIndicatesSignAssertions = true;
219                                 }
220                         }
221                 }
222                 if (relyingParty.wantsAssertionsSigned() || metaDataIndicatesSignAssertions) {
223                         support.signAssertions((SAMLAssertion[]) assertions.toArray(new SAMLAssertion[0]), relyingParty);
224                 }
225
226                 // Create artifacts for each assertion
227                 ArrayList<Artifact> artifacts = new ArrayList<Artifact>();
228                 for (int i = 0; i < assertions.size(); i++) {
229                         SAMLAssertion assertion = (SAMLAssertion) assertions.get(i);
230                         Artifact artifact = support.getArtifactMapper().generateArtifact(assertion, relyingParty);
231                         artifacts.add(artifact);
232
233                         // Put attributes names in the transaction log when it is set to DEBUG
234                         if (support.getTransactionLog().isDebugEnabled()) {
235                                 Iterator statements = assertion.getStatements();
236                                 while (statements.hasNext()) {
237                                         SAMLStatement statement = (SAMLStatement) statements.next();
238                                         if (statement instanceof SAMLAttributeStatement) {
239                                                 Iterator attributes = ((SAMLAttributeStatement) statement).getAttributes();
240                                                 StringBuffer attributeBuffer = new StringBuffer();
241                                                 while (attributes.hasNext()) {
242                                                         SAMLAttribute attribute = (SAMLAttribute) attributes.next();
243                                                         attributeBuffer.append("(" + attribute.getName() + ")");
244                                                         support.getTransactionLog().debug(
245                                                                         "Artifact (" + artifact.encode() + ") created with the following attributes: "
246                                                                                         + attributeBuffer.toString());
247                                                 }
248                                         }
249                                 }
250                         }
251                 }
252
253                 // Assemble the query string
254                 StringBuffer destination = new StringBuffer(acceptanceURL);
255                 destination.append("?TARGET=");
256                 destination.append(URLEncoder.encode(request.getParameter("target"), "UTF-8"));
257                 Iterator iterator = artifacts.iterator();
258                 StringBuffer artifactBuffer = new StringBuffer(); // Buffer for the transaction log
259
260                 // Construct the artifact query parameter
261                 while (iterator.hasNext()) {
262                         Artifact artifact = (Artifact) iterator.next();
263                         artifactBuffer.append("(" + artifact.encode() + ")");
264                         destination.append("&SAMLart=");
265                         destination.append(URLEncoder.encode(artifact.encode(), "UTF-8"));
266                 }
267
268                 log.debug("Redirecting to (" + destination.toString() + ").");
269                 response.sendRedirect(destination.toString()); // Redirect to the artifact receiver
270                 support.getTransactionLog().info(
271                                 "Assertion artifact(s) (" + artifactBuffer.toString() + ") issued to provider ("
272                                                 + relyingParty.getProviderId() + ") on behalf of principal (" + principal.getName()
273                                                 + "). Name Identifier: (" + nameId.getName() + "). Name Identifier Format: ("
274                                                 + nameId.getFormat() + ").");
275         }
276
277         public static boolean pushAttributeDefault = false;
278
279         private void respondWithPOST(HttpServletRequest request, HttpServletResponse response, IdPProtocolSupport support,
280                         LocalPrincipal principal, RelyingParty relyingParty, EntityDescriptor descriptor, String acceptanceURL,
281                         SAMLNameIdentifier nameId, String authenticationMethod, SAMLSubject authNSubject) throws SAMLException,
282                         IOException, ServletException {
283
284                 log.debug("Responding with POST profile.");
285                 ArrayList<SAMLAssertion> assertions = new ArrayList<SAMLAssertion>();
286                 authNSubject.addConfirmationMethod(SAMLSubject.CONF_BEARER);
287                 assertions.add(generateAuthNAssertion(request, relyingParty, descriptor, nameId, authenticationMethod,
288                                 getAuthNTime(request), authNSubject));
289
290                 // Package attributes for push, if necessary.
291                 if (pushAttributes(pushAttributeDefault, relyingParty)) {
292                         log.info("Resolving attributes for push.");
293                         generateAttributes(support, principal, relyingParty, assertions, request);
294                 }
295
296                 // Sign the assertions, if necessary
297                 boolean metaDataIndicatesSignAssertions = false;
298                 if (descriptor != null) {
299                         SPSSODescriptor sp = descriptor.getSPSSODescriptor(org.opensaml.XML.SAML11_PROTOCOL_ENUM);
300                         if (sp != null) {
301                                 if (sp.getWantAssertionsSigned()) {
302                                         metaDataIndicatesSignAssertions = true;
303                                 }
304                         }
305                 }
306                 if (relyingParty.wantsAssertionsSigned() || metaDataIndicatesSignAssertions) {
307                         support.signAssertions((SAMLAssertion[]) assertions.toArray(new SAMLAssertion[0]), relyingParty);
308                 }
309
310                 // Set attributes needed by form
311                 request.setAttribute("acceptanceURL", acceptanceURL);
312                 request.setAttribute("target", request.getParameter("target"));
313
314                 SAMLResponse samlResponse = new SAMLResponse(null, acceptanceURL, assertions, null);
315
316                 support.signResponse(samlResponse, relyingParty);
317
318                 createPOSTForm(request, response, samlResponse.toBase64());
319
320                 // Make transaction log entry
321                 support.getTransactionLog().info(
322                                 "Authentication assertion issued to provider (" + relyingParty.getProviderId()
323                                                 + ") on behalf of principal (" + principal.getName() + "). Name Identifier: ("
324                                                 + nameId.getName() + "). Name Identifier Format: (" + nameId.getFormat() + ").");
325
326         }
327
328         private void generateAttributes(IdPProtocolSupport support, LocalPrincipal principal, RelyingParty relyingParty,
329                         ArrayList<SAMLAssertion> assertions, HttpServletRequest request) throws SAMLException {
330
331                 try {
332                         Collection<? extends SAMLAttribute> attributes = support.getReleaseAttributes(principal, relyingParty,
333                                         relyingParty.getProviderId());
334                         log.info("Found " + attributes.size() + " attribute(s) for " + principal.getName());
335
336                         // Bail if we didn't get any attributes
337                         if (attributes == null || attributes.size() < 1) {
338                                 log.info("No attributes resolved.");
339                                 return;
340                         }
341
342                         // Reference requested subject
343                         SAMLSubject attrSubject = (SAMLSubject) ((SAMLSubjectStatement) ((SAMLAssertion) assertions.get(0))
344                                         .getStatements().next()).getSubject().clone();
345
346                         // May be one assertion or two.
347                         if (relyingParty.singleAssertion()) {
348                                 log.debug("merging attributes into existing authn assertion");
349                                 // Put all attributes into an assertion
350                                 ((SAMLAssertion) assertions.get(0)).addStatement(new SAMLAttributeStatement(attrSubject, Arrays
351                                                 .asList(attributes)));
352
353                                 if (log.isDebugEnabled()) {
354                                         log.debug("Dumping combined Assertion:" + System.getProperty("line.separator")
355                                                         + assertions.get(0).toString());
356                                 }
357                         } else {
358                                 ArrayList<String> audiences = new ArrayList<String>();
359                                 if (relyingParty.getProviderId() != null) {
360                                         audiences.add(relyingParty.getProviderId());
361                                 }
362                                 if (relyingParty.getName() != null && !relyingParty.getName().equals(relyingParty.getProviderId())) {
363                                         audiences.add(relyingParty.getName());
364                                 }
365                                 String remoteProviderId = request.getParameter("providerId");
366                                 if (remoteProviderId != null && !remoteProviderId.equals("") && !audiences.contains(remoteProviderId)) {
367                                         audiences.add(remoteProviderId);
368                                 }
369
370                                 SAMLCondition condition = new SAMLAudienceRestrictionCondition(audiences);
371
372                                 // Put all attributes into an assertion
373                                 SAMLStatement statement = new SAMLAttributeStatement(attrSubject, attributes);
374
375                                 // Set assertion expiration to longest attribute expiration
376                                 long max = 0;
377                                 for (SAMLAttribute attribute : attributes) {
378                                         if (max < attribute.getLifetime()) {
379                                                 max = attribute.getLifetime();
380                                         }
381                                 }
382                                 Date now = new Date();
383                                 Date then = new Date(now.getTime() + (max * 1000)); // max is in seconds
384
385                                 SAMLAssertion attrAssertion = new SAMLAssertion(relyingParty.getIdentityProvider().getProviderId(),
386                                                 now, then, Collections.singleton(condition), null, Collections.singleton(statement));
387                                 assertions.add(attrAssertion);
388
389                                 if (log.isDebugEnabled()) {
390                                         log.debug("Dumping generated Attribute Assertion:" + System.getProperty("line.separator")
391                                                         + attrAssertion.toString());
392                                 }
393                         }
394                 } catch (AAException e) {
395                         log.error("An error was encountered while generating assertion for attribute push: " + e);
396                         throw new SAMLException(SAMLException.RESPONDER, "General error processing request.");
397                 } catch (CloneNotSupportedException e) {
398                         log.error("An error was encountered while generating assertion for attribute push: " + e);
399                         throw new SAMLException(SAMLException.RESPONDER, "General error processing request.");
400                 }
401         }
402
403         private SAMLAssertion generateAuthNAssertion(HttpServletRequest request, RelyingParty relyingParty,
404                         EntityDescriptor descriptor, SAMLNameIdentifier nameId, String authenticationMethod, Date authTime,
405                         SAMLSubject subject) throws SAMLException, IOException {
406
407                 // Determine the correct audiences
408                 ArrayList<String> audiences = new ArrayList<String>();
409                 if (relyingParty.getProviderId() != null) {
410                         audiences.add(relyingParty.getProviderId());
411                 }
412                 if (relyingParty.getName() != null && !relyingParty.getName().equals(relyingParty.getProviderId())) {
413                         audiences.add(relyingParty.getName());
414                 }
415                 String remoteProviderId = request.getParameter("providerId");
416                 if (remoteProviderId != null && !remoteProviderId.equals("") && !audiences.contains(remoteProviderId)) {
417                         audiences.add(remoteProviderId);
418                 }
419
420                 // Determine the correct issuer
421                 String issuer = relyingParty.getIdentityProvider().getProviderId();
422
423                 ArrayList<SAMLAuthorityBinding> bindings = new ArrayList<SAMLAuthorityBinding>();
424
425                 // Create the assertion
426                 Vector<SAMLCondition> conditions = new Vector<SAMLCondition>(1);
427                 if (audiences != null && audiences.size() > 0) conditions.add(new SAMLAudienceRestrictionCondition(audiences));
428
429                 SAMLStatement[] statements = {new SAMLAuthenticationStatement(subject, authenticationMethod, authTime, request
430                                 .getRemoteAddr(), null, bindings)};
431
432                 SAMLAssertion assertion = new SAMLAssertion(issuer, new Date(System.currentTimeMillis()), new Date(System
433                                 .currentTimeMillis() + 300000), conditions, null, Arrays.asList(statements));
434
435                 if (log.isDebugEnabled()) {
436                         log.debug("Dumping generated AuthN Assertion:" + System.getProperty("line.separator")
437                                         + assertion.toString());
438                 }
439
440                 return assertion;
441         }
442
443         /*
444          * @see edu.internet2.middleware.shibboleth.idp.IdPResponder.ProtocolHandler#getHandlerName()
445          */
446         public String getHandlerName() {
447
448                 return "Shibboleth v1.x SSO";
449         }
450
451         private void validateShibSpecificData(HttpServletRequest request) throws InvalidClientDataException {
452
453                 if (request.getParameter("target") == null || request.getParameter("target").equals("")) { throw new InvalidClientDataException(
454                                 "Invalid data from Service Provider: no target URL received."); }
455                 if ((request.getParameter("shire") == null) || (request.getParameter("shire").equals(""))) { throw new InvalidClientDataException(
456                                 "Invalid data from Service Provider: No acceptance URL received."); }
457         }
458
459         private static void createPOSTForm(HttpServletRequest req, HttpServletResponse res, byte[] buf) throws IOException,
460                         ServletException {
461
462                 // Hardcoded to ASCII to ensure Base64 encoding compatibility
463                 req.setAttribute("assertion", new String(buf, "ASCII"));
464
465                 if (log.isDebugEnabled()) {
466                         log.debug("Dumping generated SAML Response:" + System.getProperty("line.separator")
467                                         + new String(Base64.decode(buf)));
468                 }
469
470                 RequestDispatcher rd = req.getRequestDispatcher("/IdP.jsp");
471                 rd.forward(req, res);
472         }
473
474         /**
475          * Boolean indication of which browser profile is in effect. "true" indicates Artifact and "false" indicates POST.
476          */
477         private static boolean useArtifactProfile(EntityDescriptor descriptor, String acceptanceURL,
478                         RelyingParty relyingParty) {
479
480                 boolean artifactMeta = false;
481                 boolean postMeta = false;
482
483                 // Look at the metadata bindings, if we can find them
484                 if (descriptor != null) {
485                         SPSSODescriptor sp = descriptor.getSPSSODescriptor(org.opensaml.XML.SAML11_PROTOCOL_ENUM);
486
487                         if (sp != null) {
488
489                                 // See if this is the default endpoint location.
490                                 AssertionConsumerService defaultEndpoint = sp.getDefaultAssertionConsumerService();
491                                 if (defaultEndpoint != null && defaultEndpoint.getLocation().equals(acceptanceURL)) {
492                                         // If we recognize the default binding, this is the one to use.
493                                         if (defaultEndpoint.getBinding().equals(SAMLBrowserProfile.PROFILE_POST_URI)) return false;
494                                         else if (defaultEndpoint.getBinding().equals(SAMLBrowserProfile.PROFILE_ARTIFACT_URI)) return true;
495                                 }
496                                 // If not, look through everything we have
497                                 List<AssertionConsumerService> endpoints = sp.getAssertionConsumerServices();
498                                 for (AssertionConsumerService ep : endpoints) {
499                                         if (acceptanceURL.equals(ep.getLocation())
500                                                         && SAMLBrowserProfile.PROFILE_POST_URI.equals(ep.getBinding())) {
501                                                 log.debug("Metadata indicates support for POST profile.");
502                                                 postMeta = true;
503                                                 continue;
504                                         }
505                                 }
506
507                                 endpoints = sp.getAssertionConsumerServices();
508                                 for (AssertionConsumerService ep : endpoints) {
509                                         if (acceptanceURL.equals(ep.getLocation())
510                                                         && SAMLBrowserProfile.PROFILE_ARTIFACT_URI.equals(ep.getBinding())) {
511                                                 log.debug("Metadata indicates support for Artifact profile.");
512                                                 artifactMeta = true;
513                                                 continue;
514                                         }
515                                 }
516                         }
517                 }
518
519                 // If we have metadata for both, use the relying party default
520                 if (!(artifactMeta && postMeta)) {
521
522                         // If we only have metadata for one, use it
523                         if (artifactMeta) { return true; }
524                         if (postMeta) { return false; }
525
526                 }
527
528                 // If we have missing or incomplete metadata, use relying party default
529                 if (relyingParty.defaultToPOSTProfile()) {
530                         return false;
531                 } else {
532                         return true;
533                 }
534         }
535
536         /**
537          * Boolean indication of whether an assertion containing an attribute statement should be bundled in the response
538          * with the assertion containing the AuthN statement.
539          */
540         private static boolean pushAttributes(boolean artifactProfile, RelyingParty relyingParty) {
541
542                 // By default push for Artifact and don't push for POST
543                 // This can be overriden at the level of the relying party
544                 if (relyingParty.forceAttributePush()) {
545                         return true;
546                 } else if (relyingParty.forceAttributeNoPush()) {
547                         return false;
548                 } else if (artifactProfile) {
549                         return true;
550                 } else {
551                         return false;
552                 }
553         }
554
555         /**
556          * Boolean indication of whethere or not a given assertion consumer URL is valid for a given SP.
557          */
558         private static boolean isValidAssertionConsumerURL(EntityDescriptor descriptor, String shireURL)
559                         throws InvalidClientDataException {
560
561                 SPSSODescriptor sp = descriptor.getSPSSODescriptor(org.opensaml.XML.SAML11_PROTOCOL_ENUM);
562                 if (sp == null) {
563                         log.info("Inappropriate metadata for provider.");
564                         return false;
565                 }
566
567                 List<AssertionConsumerService> endpoints = sp.getAssertionConsumerServices();
568                 for (AssertionConsumerService endpoint : endpoints) {
569                         if (shireURL.equals(endpoint.getLocation())) { return true; }
570                 }
571                 log.info("Supplied consumer URL not found in metadata.");
572                 return false;
573         }
574 }