1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package edu.internet2.middleware.shibboleth.idp.profile.saml1;
18
19 import java.util.Collection;
20 import java.util.List;
21 import java.util.Map;
22
23 import javax.xml.namespace.QName;
24
25 import org.joda.time.DateTime;
26 import org.opensaml.Configuration;
27 import org.opensaml.common.SAMLObject;
28 import org.opensaml.common.SAMLObjectBuilder;
29 import org.opensaml.common.SAMLVersion;
30 import org.opensaml.common.binding.encoding.SAMLMessageEncoder;
31 import org.opensaml.saml1.core.Assertion;
32 import org.opensaml.saml1.core.AttributeQuery;
33 import org.opensaml.saml1.core.AttributeStatement;
34 import org.opensaml.saml1.core.Audience;
35 import org.opensaml.saml1.core.AudienceRestrictionCondition;
36 import org.opensaml.saml1.core.Conditions;
37 import org.opensaml.saml1.core.ConfirmationMethod;
38 import org.opensaml.saml1.core.NameIdentifier;
39 import org.opensaml.saml1.core.RequestAbstractType;
40 import org.opensaml.saml1.core.Response;
41 import org.opensaml.saml1.core.ResponseAbstractType;
42 import org.opensaml.saml1.core.Statement;
43 import org.opensaml.saml1.core.Status;
44 import org.opensaml.saml1.core.StatusCode;
45 import org.opensaml.saml1.core.StatusMessage;
46 import org.opensaml.saml1.core.Subject;
47 import org.opensaml.saml1.core.SubjectConfirmation;
48 import org.opensaml.saml1.core.SubjectStatement;
49 import org.opensaml.saml2.metadata.SPSSODescriptor;
50 import org.opensaml.ws.message.encoder.MessageEncodingException;
51 import org.opensaml.xml.XMLObjectBuilder;
52 import org.opensaml.xml.io.Marshaller;
53 import org.opensaml.xml.io.MarshallingException;
54 import org.opensaml.xml.security.SecurityException;
55 import org.opensaml.xml.security.SecurityHelper;
56 import org.opensaml.xml.security.credential.Credential;
57 import org.opensaml.xml.signature.Signature;
58 import org.opensaml.xml.signature.SignatureException;
59 import org.opensaml.xml.signature.Signer;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62 import org.slf4j.helpers.MessageFormatter;
63
64 import edu.internet2.middleware.shibboleth.common.attribute.AttributeRequestException;
65 import edu.internet2.middleware.shibboleth.common.attribute.BaseAttribute;
66 import edu.internet2.middleware.shibboleth.common.attribute.encoding.AttributeEncoder;
67 import edu.internet2.middleware.shibboleth.common.attribute.encoding.AttributeEncodingException;
68 import edu.internet2.middleware.shibboleth.common.attribute.encoding.SAML1NameIdentifierEncoder;
69 import edu.internet2.middleware.shibboleth.common.attribute.provider.SAML1AttributeAuthority;
70 import edu.internet2.middleware.shibboleth.common.log.AuditLogEntry;
71 import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
72 import edu.internet2.middleware.shibboleth.common.profile.provider.BaseSAMLProfileRequestContext;
73 import edu.internet2.middleware.shibboleth.common.relyingparty.provider.CryptoOperationRequirementLevel;
74 import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml1.AbstractSAML1ProfileConfiguration;
75 import edu.internet2.middleware.shibboleth.idp.profile.AbstractSAMLProfileHandler;
76 import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
77 import edu.internet2.middleware.shibboleth.idp.session.Session;
78
79
80 public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHandler {
81
82
83 public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_11;
84
85
86 private static Logger log = LoggerFactory.getLogger(AbstractSAML1ProfileHandler.class);
87
88
89 private SAMLObjectBuilder<Response> responseBuilder;
90
91
92 private SAMLObjectBuilder<Assertion> assertionBuilder;
93
94
95 private SAMLObjectBuilder<Conditions> conditionsBuilder;
96
97
98 private SAMLObjectBuilder<AudienceRestrictionCondition> audienceRestrictionConditionBuilder;
99
100
101 private SAMLObjectBuilder<Audience> audienceBuilder;
102
103
104 private SAMLObjectBuilder<SubjectConfirmation> subjectConfirmationBuilder;
105
106
107 private SAMLObjectBuilder<ConfirmationMethod> confirmationMethodBuilder;
108
109
110 private SAMLObjectBuilder<Subject> subjectBuilder;
111
112
113 private SAMLObjectBuilder<Status> statusBuilder;
114
115
116 private SAMLObjectBuilder<StatusCode> statusCodeBuilder;
117
118
119 private SAMLObjectBuilder<StatusMessage> statusMessageBuilder;
120
121
122 private XMLObjectBuilder<Signature> signatureBuilder;
123
124
125
126
127 @SuppressWarnings("unchecked")
128 public AbstractSAML1ProfileHandler() {
129 super();
130 responseBuilder = (SAMLObjectBuilder<Response>) getBuilderFactory().getBuilder(Response.DEFAULT_ELEMENT_NAME);
131 assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory()
132 .getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
133 conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory().getBuilder(
134 Conditions.DEFAULT_ELEMENT_NAME);
135 audienceRestrictionConditionBuilder = (SAMLObjectBuilder<AudienceRestrictionCondition>) getBuilderFactory()
136 .getBuilder(AudienceRestrictionCondition.DEFAULT_ELEMENT_NAME);
137 audienceBuilder = (SAMLObjectBuilder<Audience>) getBuilderFactory().getBuilder(Audience.DEFAULT_ELEMENT_NAME);
138 subjectConfirmationBuilder = (SAMLObjectBuilder<SubjectConfirmation>) getBuilderFactory().getBuilder(
139 SubjectConfirmation.DEFAULT_ELEMENT_NAME);
140 confirmationMethodBuilder = (SAMLObjectBuilder<ConfirmationMethod>) getBuilderFactory().getBuilder(
141 ConfirmationMethod.DEFAULT_ELEMENT_NAME);
142 subjectBuilder = (SAMLObjectBuilder<Subject>) getBuilderFactory().getBuilder(Subject.DEFAULT_ELEMENT_NAME);
143 statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(Status.DEFAULT_ELEMENT_NAME);
144 statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory().getBuilder(
145 StatusCode.DEFAULT_ELEMENT_NAME);
146 statusMessageBuilder = (SAMLObjectBuilder<StatusMessage>) getBuilderFactory().getBuilder(
147 StatusMessage.DEFAULT_ELEMENT_NAME);
148 signatureBuilder = (XMLObjectBuilder<Signature>) getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME);
149 }
150
151
152 protected void populateRequestContext(BaseSAMLProfileRequestContext requestContext) throws ProfileException {
153 BaseSAML1ProfileRequestContext saml1Request = (BaseSAML1ProfileRequestContext) requestContext;
154 try {
155 super.populateRequestContext(requestContext);
156 } catch (ProfileException e) {
157 if (saml1Request.getFailureStatus() == null) {
158 saml1Request.setFailureStatus(buildStatus(StatusCode.REQUESTER, null, e.getMessage()));
159 }
160 throw e;
161 }
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175 protected void populateUserInformation(BaseSAMLProfileRequestContext requestContext) {
176 Session userSession = getUserSession(requestContext.getInboundMessageTransport());
177 if (userSession == null) {
178 NameIdentifier subject = (NameIdentifier) requestContext.getSubjectNameIdentifier();
179 if (subject != null && subject.getNameIdentifier() != null) {
180 userSession = getUserSession(subject.getNameIdentifier());
181 }
182 }
183
184 if (userSession != null) {
185 requestContext.setUserSession(userSession);
186 requestContext.setPrincipalName(userSession.getPrincipalName());
187 ServiceInformation serviceInfo = userSession.getServicesInformation().get(
188 requestContext.getInboundMessageIssuer());
189 if (serviceInfo != null) {
190 requestContext.setPrincipalAuthenticationMethod(serviceInfo.getAuthenticationMethod()
191 .getAuthenticationMethod());
192 }
193 }
194 }
195
196
197
198
199
200
201
202
203 protected void checkSamlVersion(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext) throws ProfileException {
204 SAMLObject samlObject = requestContext.getInboundSAMLMessage();
205
206 if (samlObject instanceof RequestAbstractType) {
207 RequestAbstractType request = (RequestAbstractType) samlObject;
208 if (request.getMajorVersion() < 1) {
209 requestContext.setFailureStatus(buildStatus(StatusCode.REQUESTER, StatusCode.REQUEST_VERSION_TOO_LOW,
210 null));
211 throw new ProfileException("SAML request major version too low");
212 } else if (request.getMajorVersion() > 1) {
213 requestContext.setFailureStatus(buildStatus(StatusCode.REQUESTER, StatusCode.REQUEST_VERSION_TOO_HIGH,
214 null));
215 throw new ProfileException("SAML request major version too low");
216 }
217 }
218 }
219
220
221
222
223
224
225
226
227
228
229
230 protected Response buildResponse(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext, List<Statement> statements)
231 throws ProfileException {
232
233 DateTime issueInstant = new DateTime();
234
235
236 Response samlResponse = responseBuilder.buildObject();
237 samlResponse.setIssueInstant(issueInstant);
238 populateStatusResponse(requestContext, samlResponse);
239
240
241 Assertion assertion = null;
242 if (statements != null && !statements.isEmpty()) {
243 assertion = buildAssertion(requestContext, issueInstant);
244 assertion.getStatements().addAll(statements);
245 samlResponse.getAssertions().add(assertion);
246 signAssertion(requestContext, assertion);
247 }
248
249 Status status = buildStatus(StatusCode.SUCCESS, null, null);
250 samlResponse.setStatus(status);
251
252 return samlResponse;
253 }
254
255
256
257
258
259
260
261
262
263 protected Assertion buildAssertion(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext, DateTime issueInstant) {
264 Assertion assertion = assertionBuilder.buildObject();
265 assertion.setID(getIdGenerator().generateIdentifier());
266 assertion.setIssueInstant(issueInstant);
267 assertion.setVersion(SAMLVersion.VERSION_11);
268 assertion.setIssuer(requestContext.getLocalEntityId());
269
270 Conditions conditions = buildConditions(requestContext, issueInstant);
271 assertion.setConditions(conditions);
272
273 return assertion;
274 }
275
276
277
278
279
280
281
282
283
284
285 protected Conditions buildConditions(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext, DateTime issueInstant) {
286 AbstractSAML1ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
287
288 Conditions conditions = conditionsBuilder.buildObject();
289 conditions.setNotBefore(issueInstant);
290 conditions.setNotOnOrAfter(issueInstant.plus(profileConfig.getAssertionLifetime()));
291
292 Collection<String> audiences;
293
294 AudienceRestrictionCondition audienceRestriction = audienceRestrictionConditionBuilder.buildObject();
295 conditions.getAudienceRestrictionConditions().add(audienceRestriction);
296
297 Audience audience = audienceBuilder.buildObject();
298 audience.setUri(requestContext.getInboundMessageIssuer());
299 audienceRestriction.getAudiences().add(audience);
300
301
302 audiences = profileConfig.getAssertionAudiences();
303 if (audiences != null && audiences.size() > 0) {
304 for (String audienceUri : audiences) {
305 audience = audienceBuilder.buildObject();
306 audience.setUri(audienceUri);
307 audienceRestriction.getAudiences().add(audience);
308 }
309 }
310
311 return conditions;
312 }
313
314
315
316
317
318
319
320
321
322
323
324
325 protected Subject buildSubject(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext, String confirmationMethod)
326 throws ProfileException {
327
328 ConfirmationMethod method = confirmationMethodBuilder.buildObject();
329 method.setConfirmationMethod(confirmationMethod);
330
331 SubjectConfirmation subjectConfirmation = subjectConfirmationBuilder.buildObject();
332 subjectConfirmation.getConfirmationMethods().add(method);
333
334 NameIdentifier nameID = buildNameId(requestContext);
335
336 Subject subject = subjectBuilder.buildObject();
337 subject.setSubjectConfirmation(subjectConfirmation);
338
339 if (nameID != null) {
340 subject.setNameIdentifier(nameID);
341 requestContext.setSubjectNameIdentifier(nameID);
342 }
343
344 return subject;
345 }
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361 protected NameIdentifier buildNameId(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext)
362 throws ProfileException {
363 log.debug("Attemping to build NameIdentifier for principal '{}' in response to request from relying party '{}",
364 requestContext.getPrincipalName(), requestContext.getInboundMessageIssuer());
365
366 List<String> supportedNameFormats = getNameFormats(requestContext);
367 if (!supportedNameFormats.isEmpty()) {
368 log.debug("Relying party '{}' supports the name formats: {}", requestContext.getInboundMessageIssuer(),
369 supportedNameFormats);
370 } else {
371 log.debug("Relying party '{}' indicated no preferred name formats", requestContext
372 .getInboundMessageIssuer());
373 }
374
375 Map<String, BaseAttribute> principalAttributes = requestContext.getAttributes();
376 if (principalAttributes == null || principalAttributes.isEmpty()) {
377 log.debug("No attributes for principal '{}', no NameIdentifier will be created for relying party '{}'",
378 requestContext.getPrincipalName(), requestContext.getInboundMessageIssuer());
379 return null;
380 }
381
382 BaseAttribute<?> nameIdAttribute = null;
383 SAML1NameIdentifierEncoder nameIdEncoder = null;
384 for (BaseAttribute<?> attribute : principalAttributes.values()) {
385 if (attribute == null) {
386 continue;
387 }
388 for (AttributeEncoder encoder : attribute.getEncoders()) {
389 if (encoder == null) {
390 continue;
391 }
392 if (encoder instanceof SAML1NameIdentifierEncoder) {
393 nameIdEncoder = (SAML1NameIdentifierEncoder) encoder;
394 if (supportedNameFormats.isEmpty() || supportedNameFormats.contains(nameIdEncoder.getNameFormat())) {
395 nameIdAttribute = attribute;
396 break;
397 }
398 }
399 }
400 }
401
402 if (nameIdAttribute == null || nameIdEncoder == null) {
403 log
404 .debug(
405 "No attributes for principal '{}' supports encoding into a supported NameIdentifier format for relying party '{}'",
406 requestContext.getPrincipalName(), requestContext.getInboundMessageIssuer());
407 return null;
408 }
409
410 try {
411 log
412 .debug(
413 "Using attribute '{}' supporting name format '{}' to create the NameIdentifier for relying party '{}'",
414 new Object[] { nameIdAttribute.getId(), nameIdEncoder.getNameFormat(),
415 requestContext.getInboundMessageIssuer() });
416 return nameIdEncoder.encode(nameIdAttribute);
417 } catch (AttributeEncodingException e) {
418 requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, null, "Unable to encode NameIdentifier"));
419 String msg = MessageFormatter.format("Unable to encode NameIdentifier for relying party '{}'",
420 requestContext.getInboundMessageIssuer());
421 log.error(msg, e);
422 throw new ProfileException(msg, e);
423 }
424 }
425
426
427
428
429
430
431
432
433 protected Response buildErrorResponse(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext) {
434 Response samlResponse = responseBuilder.buildObject();
435 samlResponse.setIssueInstant(new DateTime());
436 populateStatusResponse(requestContext, samlResponse);
437
438 samlResponse.setStatus(requestContext.getFailureStatus());
439
440 return samlResponse;
441 }
442
443
444
445
446
447
448
449 protected void populateStatusResponse(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext,
450 ResponseAbstractType response) {
451 response.setID(getIdGenerator().generateIdentifier());
452
453 SAMLObject samlMessage = requestContext.getInboundSAMLMessage();
454 if (samlMessage != null && samlMessage instanceof RequestAbstractType) {
455 response.setInResponseTo(((RequestAbstractType) samlMessage).getID());
456 }
457
458 response.setVersion(SAMLVersion.VERSION_11);
459 }
460
461
462
463
464
465
466
467
468
469
470 protected Status buildStatus(QName topLevelCode, QName secondLevelCode, String failureMessage) {
471 Status status = statusBuilder.buildObject();
472
473 StatusCode statusCode = statusCodeBuilder.buildObject();
474 statusCode.setValue(topLevelCode);
475 status.setStatusCode(statusCode);
476
477 if (secondLevelCode != null) {
478 StatusCode secondLevelStatusCode = statusCodeBuilder.buildObject();
479 secondLevelStatusCode.setValue(secondLevelCode);
480 statusCode.setStatusCode(secondLevelStatusCode);
481 }
482
483 if (failureMessage != null) {
484 StatusMessage msg = statusMessageBuilder.buildObject();
485 msg.setMessage(failureMessage);
486 status.setStatusMessage(msg);
487 }
488
489 return status;
490 }
491
492
493
494
495
496
497
498
499 protected void resolveAttributes(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext) throws ProfileException {
500 AbstractSAML1ProfileConfiguration profileConfiguration = requestContext.getProfileConfiguration();
501 SAML1AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
502
503 try {
504 log.debug("Resolving attributes for principal '{}' for SAML request from relying party '{}'",
505 requestContext.getPrincipalName(), requestContext.getInboundMessageIssuer());
506 Map<String, BaseAttribute> principalAttributes = attributeAuthority.getAttributes(requestContext);
507
508 requestContext.setAttributes(principalAttributes);
509 } catch (AttributeRequestException e) {
510 requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, null, "Error resolving attributes"));
511 String msg = MessageFormatter.format(
512 "Error resolving attributes for principal '{}' for SAML request from relying party '{}'",
513 requestContext.getPrincipalName(), requestContext.getInboundMessageIssuer());
514 log.error(msg, e);
515 throw new ProfileException(msg, e);
516 }
517 }
518
519
520
521
522
523
524
525
526
527
528
529 protected AttributeStatement buildAttributeStatement(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext,
530 String subjectConfMethod) throws ProfileException {
531
532 log.debug(
533 "Creating attribute statement about principal '{}'in response to SAML request from relying party '{}'",
534 requestContext.getPrincipalName(), requestContext.getInboundMessageIssuer());
535 AbstractSAML1ProfileConfiguration profileConfiguration = requestContext.getProfileConfiguration();
536 SAML1AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
537
538 try {
539 AttributeStatement statment;
540 if (requestContext.getInboundSAMLMessage() instanceof AttributeQuery) {
541 statment = attributeAuthority.buildAttributeStatement((AttributeQuery) requestContext
542 .getInboundSAMLMessage(), requestContext.getAttributes().values());
543 } else {
544 statment = attributeAuthority.buildAttributeStatement(null, requestContext.getAttributes().values());
545 }
546
547 if (statment != null) {
548 Subject statementSubject = buildSubject(requestContext, subjectConfMethod);
549 statment.setSubject(statementSubject);
550 }
551
552 return statment;
553 } catch (AttributeRequestException e) {
554 requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, null, "Error resolving attributes"));
555 String msg = MessageFormatter.format("Error encoding attributes for principal '{}'", requestContext
556 .getPrincipalName());
557 log.error(msg, e);
558 throw new ProfileException(msg, e);
559 }
560 }
561
562
563
564
565
566
567
568
569 protected void resolvePrincipal(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext) throws ProfileException {
570 AbstractSAML1ProfileConfiguration profileConfiguration = requestContext.getProfileConfiguration();
571 SAML1AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
572
573 log.debug("Resolving principal name for subject of SAML request from relying party '{}'", requestContext
574 .getInboundMessageIssuer());
575
576 try {
577 String principal = attributeAuthority.getPrincipal(requestContext);
578 requestContext.setPrincipalName(principal);
579 } catch (AttributeRequestException e) {
580 requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, StatusCode.REQUEST_DENIED,
581 "Error resolving principal"));
582 String msg = MessageFormatter.format(
583 "Error resolving principal name for SAML request from relying party '{}'", requestContext
584 .getInboundMessageIssuer());
585 log.warn(msg, e);
586 throw new ProfileException(msg, e);
587 }
588 }
589
590
591
592
593
594
595
596
597
598
599
600 protected void signAssertion(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext, Assertion assertion)
601 throws ProfileException {
602 log.debug("Determining if SAML assertion to relying party '{}' should be signed", requestContext
603 .getInboundMessageIssuer());
604
605 boolean signAssertion = isSignAssertion(requestContext);
606
607 if (!signAssertion) {
608 return;
609 }
610
611 AbstractSAML1ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
612
613 log.debug("Determining credential to use to sign assertion to relying party '{}'", requestContext
614 .getInboundMessageIssuer());
615 Credential signatureCredential = profileConfig.getSigningCredential();
616 if (signatureCredential == null) {
617 signatureCredential = requestContext.getRelyingPartyConfiguration().getDefaultSigningCredential();
618 }
619
620 if (signatureCredential == null) {
621 String msg = MessageFormatter.format(
622 "No signing credential is specified for relying party configuration '{}'", requestContext
623 .getRelyingPartyConfiguration().getProviderId());
624 log.warn(msg);
625 throw new ProfileException(msg);
626 }
627
628 log.debug("Signing assertion to relying party '{}'", requestContext.getInboundMessageIssuer());
629 Signature signature = signatureBuilder.buildObject(Signature.DEFAULT_ELEMENT_NAME);
630
631 signature.setSigningCredential(signatureCredential);
632 try {
633
634
635 SecurityHelper.prepareSignatureParams(signature, signatureCredential, null, null);
636 } catch (SecurityException e) {
637 String msg = "Error preparing signature for signing";
638 log.error(msg);
639 throw new ProfileException(msg, e);
640 }
641
642 assertion.setSignature(signature);
643
644 Marshaller assertionMarshaller = Configuration.getMarshallerFactory().getMarshaller(assertion);
645 try {
646 assertionMarshaller.marshall(assertion);
647 Signer.signObject(signature);
648 } catch (MarshallingException e) {
649 String errMsg = "Unable to marshall assertion for signing";
650 log.error(errMsg, e);
651 throw new ProfileException(errMsg, e);
652 } catch (SignatureException e) {
653 String msg = "Unable to sign assertion";
654 log.error(msg, e);
655 throw new ProfileException(msg, e);
656 }
657 }
658
659
660
661
662
663
664
665
666 protected boolean isSignAssertion(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext) throws ProfileException {
667
668 SAMLMessageEncoder encoder = getOutboundMessageEncoder(requestContext);
669 AbstractSAML1ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
670
671 try {
672 boolean signAssertion = profileConfig.getSignAssertions() == CryptoOperationRequirementLevel.always
673 || (profileConfig.getSignAssertions() == CryptoOperationRequirementLevel.conditional
674 && !encoder.providesMessageIntegrity(requestContext));
675
676 log.debug("IdP relying party configuration '{}' indicates to sign assertions: {}", requestContext
677 .getRelyingPartyConfiguration().getRelyingPartyId(), signAssertion);
678
679 if (!signAssertion && requestContext.getPeerEntityRoleMetadata() instanceof SPSSODescriptor) {
680 SPSSODescriptor ssoDescriptor = (SPSSODescriptor) requestContext.getPeerEntityRoleMetadata();
681 if (ssoDescriptor.getWantAssertionsSigned() != null) {
682 signAssertion = ssoDescriptor.getWantAssertionsSigned().booleanValue();
683 log.debug("Entity metadata for relying party '{} 'indicates to sign assertions: {}", requestContext
684 .getInboundMessageIssuer(), signAssertion);
685 }
686 }
687
688 return signAssertion;
689 } catch (MessageEncodingException e) {
690 log.error("Unable to determine if outbound encoding '{}' provides message integrity protection",
691 encoder.getBindingURI());
692 throw new ProfileException("Unable to determine if outbound assertion should be signed");
693 }
694 }
695
696
697
698
699
700
701 protected void writeAuditLogEntry(BaseSAMLProfileRequestContext context) {
702 SAML1AuditLogEntry auditLogEntry = new SAML1AuditLogEntry();
703 auditLogEntry.setSAMLResponse((Response) context.getOutboundSAMLMessage());
704 auditLogEntry.setMessageProfile(getProfileId());
705 auditLogEntry.setPrincipalAuthenticationMethod(context.getPrincipalAuthenticationMethod());
706 auditLogEntry.setPrincipalName(context.getPrincipalName());
707 auditLogEntry.setAssertingPartyId(context.getLocalEntityId());
708 auditLogEntry.setRelyingPartyId(context.getInboundMessageIssuer());
709 auditLogEntry.setRequestBinding(context.getMessageDecoder().getBindingURI());
710 auditLogEntry.setRequestId(context.getInboundSAMLMessageId());
711 auditLogEntry.setResponseBinding(context.getMessageEncoder().getBindingURI());
712 auditLogEntry.setResponseId(context.getOutboundSAMLMessageId());
713 if (context.getReleasedAttributes() != null) {
714 auditLogEntry.getReleasedAttributes().addAll(context.getReleasedAttributes());
715 }
716
717 getAduitLog().info(auditLogEntry.toString());
718 }
719
720
721 protected class SAML1AuditLogEntry extends AuditLogEntry {
722
723
724 private Response samlResponse;
725
726
727
728
729
730
731 public Response getSAMLResponse() {
732 return samlResponse;
733 }
734
735
736
737
738
739
740 public void setSAMLResponse(Response response) {
741 samlResponse = response;
742 }
743
744
745 public String toString() {
746 StringBuilder entryString = new StringBuilder(super.toString());
747
748 NameIdentifier nameIdentifier = null;
749 StringBuilder assertionIds = new StringBuilder();
750 List<Assertion> assertions = samlResponse.getAssertions();
751 if (assertions != null && !assertions.isEmpty()) {
752 for (Assertion assertion : assertions) {
753 assertionIds.append(assertion.getID());
754 assertionIds.append(",");
755
756 if (nameIdentifier == null) {
757 List<Statement> statements = assertion.getStatements();
758 if (statements != null && !statements.isEmpty()) {
759 for (Statement statement : statements) {
760 if (statement instanceof SubjectStatement) {
761 if (((SubjectStatement) statement).getSubject() != null) {
762 nameIdentifier = ((SubjectStatement) statement).getSubject()
763 .getNameIdentifier();
764 }
765 }
766 }
767 }
768 }
769 }
770 }
771
772 if (nameIdentifier != null) {
773 entryString.append(nameIdentifier.getNameIdentifier());
774 }
775 entryString.append("|");
776
777 entryString.append(assertionIds.toString());
778 entryString.append("|");
779
780 return entryString.toString();
781 }
782 }
783 }