import org.opensaml.saml1.core.Subject;
import org.opensaml.saml1.core.SubjectConfirmation;
import org.opensaml.saml1.core.SubjectStatement;
-import org.opensaml.saml2.metadata.RoleDescriptor;
import org.opensaml.saml2.metadata.SPSSODescriptor;
import org.opensaml.ws.message.encoder.MessageEncodingException;
import org.opensaml.xml.XMLObjectBuilder;
log.debug("Determining if SAML assertion to relying party '{}' should be signed", requestContext
.getInboundMessageIssuer());
- boolean signAssertion = false;
-
- RoleDescriptor relyingPartyRole = requestContext.getPeerEntityRoleMetadata();
- SAMLMessageEncoder encoder = getOutboundMessageEncoder(requestContext);
- AbstractSAML1ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
-
- try {
- if (profileConfig.getSignAssertions() == CryptoOperationRequirementLevel.always
- || (profileConfig.getSignAssertions() == CryptoOperationRequirementLevel.conditional && !encoder
- .providesMessageIntegrity(requestContext))) {
- signAssertion = true;
- log.debug("IdP relying party configuration '{}' indicates to sign assertions: {}", requestContext
- .getRelyingPartyConfiguration().getRelyingPartyId(), signAssertion);
- }
- } catch (MessageEncodingException e) {
- String msg = MessageFormatter.format(
- "Unable to determine if outbound encoding '{}' provides message integrity protection", encoder
- .getBindingURI());
- log.error(msg);
- throw new ProfileException(msg);
- }
-
- if (!signAssertion && relyingPartyRole instanceof SPSSODescriptor) {
- SPSSODescriptor ssoDescriptor = (SPSSODescriptor) relyingPartyRole;
- if (ssoDescriptor.getWantAssertionsSigned() != null) {
- signAssertion = ssoDescriptor.getWantAssertionsSigned().booleanValue();
- log.debug("Entity metadata for relying party '{}' indicates to sign assertions: {}", requestContext
- .getInboundMessageIssuer(), signAssertion);
- }
- }
+ boolean signAssertion = isSignAssertion(requestContext);
if (!signAssertion) {
return;
}
+ AbstractSAML1ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
+
log.debug("Determining credential to use to sign assertion to relying party '{}'", requestContext
.getInboundMessageIssuer());
Credential signatureCredential = profileConfig.getSigningCredential();
throw new ProfileException(msg, e);
}
}
+
+ /**
+ * Determine whether issued assertions should be signed.
+ *
+ * @param requestContext the current request context
+ * @return true if assertions should be signed, false otherwise
+ * @throws ProfileException if there is a problem determining whether assertions should be signed
+ */
+ protected boolean isSignAssertion(BaseSAML1ProfileRequestContext<?, ?, ?> requestContext) throws ProfileException {
+
+ SAMLMessageEncoder encoder = getOutboundMessageEncoder(requestContext);
+ AbstractSAML1ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
+
+ try {
+ boolean signAssertion = profileConfig.getSignAssertions() == CryptoOperationRequirementLevel.always
+ || (profileConfig.getSignAssertions() == CryptoOperationRequirementLevel.conditional
+ && !encoder.providesMessageIntegrity(requestContext));
+
+ log.debug("IdP relying party configuration '{}' indicates to sign assertions: {}", requestContext
+ .getRelyingPartyConfiguration().getRelyingPartyId(), signAssertion);
+
+ if (!signAssertion && requestContext.getPeerEntityRoleMetadata() instanceof SPSSODescriptor) {
+ SPSSODescriptor ssoDescriptor = (SPSSODescriptor) requestContext.getPeerEntityRoleMetadata();
+ if (ssoDescriptor.getWantAssertionsSigned() != null) {
+ signAssertion = ssoDescriptor.getWantAssertionsSigned().booleanValue();
+ log.debug("Entity metadata for relying party '{} 'indicates to sign assertions: {}", requestContext
+ .getInboundMessageIssuer(), signAssertion);
+ }
+ }
+
+ return signAssertion;
+ } catch (MessageEncodingException e) {
+ log.error("Unable to determine if outbound encoding '{}' provides message integrity protection",
+ encoder.getBindingURI());
+ throw new ProfileException("Unable to determine if outbound assertion should be signed");
+ }
+ }
/**
* Writes an audit log entry indicating the successful response to the attribute request.
signAssertion(requestContext, assertion);
- SAMLMessageEncoder encoder = getOutboundMessageEncoder(requestContext);
- try {
- if (requestContext.getProfileConfiguration().getEncryptAssertion() == CryptoOperationRequirementLevel.always
- || (requestContext.getProfileConfiguration().getEncryptAssertion() == CryptoOperationRequirementLevel.conditional && !encoder
- .providesMessageConfidentiality(requestContext))) {
- log.debug("Attempting to encrypt assertion to relying party '{}'", requestContext
- .getInboundMessageIssuer());
- try {
- Encrypter encrypter = getEncrypter(requestContext.getInboundMessageIssuer());
- samlResponse.getEncryptedAssertions().add(encrypter.encrypt(assertion));
- } catch (SecurityException e) {
- log.error("Unable to construct encrypter", e);
- requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null,
- "Unable to encrypt assertion"));
- throw new ProfileException("Unable to construct encrypter", e);
- } catch (EncryptionException e) {
- log.error("Unable to encrypt assertion", e);
- requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null,
- "Unable to encrypt assertion"));
- throw new ProfileException("Unable to encrypt assertion", e);
- }
- } else {
- samlResponse.getAssertions().add(assertion);
+ if (isEncryptAssertion(requestContext)) {
+ log.debug("Attempting to encrypt assertion to relying party '{}'", requestContext
+ .getInboundMessageIssuer());
+ try {
+ Encrypter encrypter = getEncrypter(requestContext.getInboundMessageIssuer());
+ samlResponse.getEncryptedAssertions().add(encrypter.encrypt(assertion));
+ } catch (SecurityException e) {
+ log.error("Unable to construct encrypter", e);
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null,
+ "Unable to encrypt assertion"));
+ throw new ProfileException("Unable to construct encrypter", e);
+ } catch (EncryptionException e) {
+ log.error("Unable to encrypt assertion", e);
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null,
+ "Unable to encrypt assertion"));
+ throw new ProfileException("Unable to encrypt assertion", e);
}
- } catch (MessageEncodingException e) {
- log.error("Unable to determine if outbound encoding '{}' can provide confidentiality", encoder
- .getBindingURI());
- throw new ProfileException("Unable to determine if assertions should be encrypted");
+ } else {
+ samlResponse.getAssertions().add(assertion);
}
}
}
/**
+ * Determine whether issued assertions should be encrypted.
+ *
+ * @param requestContext the current request context
+ * @return true if assertions should be encrypted, false otherwise
+ * @throws ProfileException if there is a problem determining whether assertions should be encrypted
+ */
+ protected boolean isEncryptAssertion(BaseSAML2ProfileRequestContext<?, ?, ?> requestContext)
+ throws ProfileException {
+
+ SAMLMessageEncoder encoder = getOutboundMessageEncoder(requestContext);
+ try {
+ return requestContext.getProfileConfiguration().getEncryptAssertion() == CryptoOperationRequirementLevel.always
+ || (requestContext.getProfileConfiguration().getEncryptAssertion() == CryptoOperationRequirementLevel.conditional
+ && !encoder.providesMessageConfidentiality(requestContext));
+ } catch (MessageEncodingException e) {
+ log.error("Unable to determine if outbound encoding '{}' can provide confidentiality", encoder
+ .getBindingURI());
+ throw new ProfileException("Unable to determine if assertions should be encrypted");
+ }
+ }
+
+ /**
* Extension point for for subclasses to post-process the Response before it is signed and encoded.
*
* @param requestContext the current request context
log.debug("Determining if SAML assertion to relying party '{}' should be signed", requestContext
.getInboundMessageIssuer());
- boolean signAssertion = false;
-
- SAMLMessageEncoder encoder = getOutboundMessageEncoder(requestContext);
- AbstractSAML2ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
- try {
- if (profileConfig.getSignAssertions() == CryptoOperationRequirementLevel.always
- || (profileConfig.getSignAssertions() == CryptoOperationRequirementLevel.conditional && !encoder
- .providesMessageIntegrity(requestContext))) {
- signAssertion = true;
- log.debug("IdP relying party configuration '{}' indicates to sign assertions: {}", requestContext
- .getRelyingPartyConfiguration().getRelyingPartyId(), signAssertion);
- }
- } catch (MessageEncodingException e) {
- log.error("Unable to determine if outbound encoding '{}' provides message integrity protection", encoder
- .getBindingURI());
- throw new ProfileException("Unable to determine if outbound message should be signed");
- }
-
- if (!signAssertion && requestContext.getPeerEntityRoleMetadata() instanceof SPSSODescriptor) {
- SPSSODescriptor ssoDescriptor = (SPSSODescriptor) requestContext.getPeerEntityRoleMetadata();
- if (ssoDescriptor.getWantAssertionsSigned() != null) {
- signAssertion = ssoDescriptor.getWantAssertionsSigned().booleanValue();
- log.debug("Entity metadata for relying party '{} 'indicates to sign assertions: {}", requestContext
- .getInboundMessageIssuer(), signAssertion);
- }
- }
+ boolean signAssertion = isSignAssertion(requestContext);
if (!signAssertion) {
return;
}
+
+ AbstractSAML2ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
log.debug("Determining signing credntial for assertion to relying party '{}'", requestContext
.getInboundMessageIssuer());
}
/**
+ * Determine whether issued assertions should be signed.
+ *
+ * @param requestContext the current request context
+ * @return true if assertions should be signed, false otherwise
+ * @throws ProfileException if there is a problem determining whether assertions should be signed
+ */
+ protected boolean isSignAssertion(BaseSAML2ProfileRequestContext<?, ?, ?> requestContext) throws ProfileException {
+
+ SAMLMessageEncoder encoder = getOutboundMessageEncoder(requestContext);
+ AbstractSAML2ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
+
+ try {
+ boolean signAssertion = profileConfig.getSignAssertions() == CryptoOperationRequirementLevel.always
+ || (profileConfig.getSignAssertions() == CryptoOperationRequirementLevel.conditional
+ && !encoder.providesMessageIntegrity(requestContext));
+
+ log.debug("IdP relying party configuration '{}' indicates to sign assertions: {}", requestContext
+ .getRelyingPartyConfiguration().getRelyingPartyId(), signAssertion);
+
+ if (!signAssertion && requestContext.getPeerEntityRoleMetadata() instanceof SPSSODescriptor) {
+ SPSSODescriptor ssoDescriptor = (SPSSODescriptor) requestContext.getPeerEntityRoleMetadata();
+ if (ssoDescriptor.getWantAssertionsSigned() != null) {
+ signAssertion = ssoDescriptor.getWantAssertionsSigned().booleanValue();
+ log.debug("Entity metadata for relying party '{} 'indicates to sign assertions: {}", requestContext
+ .getInboundMessageIssuer(), signAssertion);
+ }
+ }
+
+ return signAssertion;
+ } catch (MessageEncodingException e) {
+ log.error("Unable to determine if outbound encoding '{}' provides message integrity protection", encoder
+ .getBindingURI());
+ throw new ProfileException("Unable to determine if outbound assertion should be signed");
+ }
+ }
+
+ /**
* Build a status message, with an optional second-level failure message.
*
* @param topLevelCode The top-level status code. Should be from saml-core-2.0-os, sec. 3.2.2.2
}
requestContext.setSubjectNameIdentifier(nameID);
-
- boolean nameIdEncRequiredByAuthnRequest = false;
- if (requestContext.getInboundSAMLMessage() instanceof AuthnRequest) {
- AuthnRequest authnRequest = (AuthnRequest) requestContext.getInboundSAMLMessage();
- NameIDPolicy policy = authnRequest.getNameIDPolicy();
- if (policy != null && DatatypeHelper.safeEquals(policy.getFormat(), NameID.ENCRYPTED)) {
- nameIdEncRequiredByAuthnRequest = true;
+
+ if (isEncryptNameID(requestContext)) {
+ log.debug("Attempting to encrypt NameID to relying party '{}'", requestContext
+ .getInboundMessageIssuer());
+ try {
+ Encrypter encrypter = getEncrypter(requestContext.getInboundMessageIssuer());
+ subject.setEncryptedID(encrypter.encrypt(nameID));
+ } catch (SecurityException e) {
+ log.error("Unable to construct encrypter", e);
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null,
+ "Unable to encrypt NameID"));
+ throw new ProfileException("Unable to construct encrypter", e);
+ } catch (EncryptionException e) {
+ log.error("Unable to encrypt NameID", e);
+ requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null,
+ "Unable to encrypt NameID"));
+ throw new ProfileException("Unable to encrypt NameID", e);
}
+ } else {
+ subject.setNameID(nameID);
}
+
+ return subject;
+ }
+
+
+ /**
+ * Determine whether NameID's should be encrypted.
+ *
+ * @param requestContext the current request context
+ * @return true if NameID's should be encrypted, false otherwise
+ * @throws ProfileException if there is a problem determining whether NameID's should be encrypted
+ */
+ protected boolean isEncryptNameID(BaseSAML2ProfileRequestContext<?, ?, ?> requestContext)
+ throws ProfileException {
+
+ boolean nameIdEncRequiredByAuthnRequest = isRequestRequiresEncryptNameID(requestContext);
+
SAMLMessageEncoder encoder = getOutboundMessageEncoder(requestContext);
+ boolean nameIdEncRequiredByConfig = false;
try {
- if (nameIdEncRequiredByAuthnRequest
- || requestContext.getProfileConfiguration().getEncryptNameID() == CryptoOperationRequirementLevel.always
- || (requestContext.getProfileConfiguration().getEncryptNameID() == CryptoOperationRequirementLevel.conditional && !encoder
- .providesMessageConfidentiality(requestContext))) {
- log.debug("Attempting to encrypt NameID to relying party '{}'", requestContext
- .getInboundMessageIssuer());
- try {
- Encrypter encrypter = getEncrypter(requestContext.getInboundMessageIssuer());
- subject.setEncryptedID(encrypter.encrypt(nameID));
- } catch (SecurityException e) {
- log.error("Unable to construct encrypter", e);
- requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null,
- "Unable to encrypt NameID"));
- throw new ProfileException("Unable to construct encrypter", e);
- } catch (EncryptionException e) {
- log.error("Unable to encrypt NameID", e);
- requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, null,
- "Unable to encrypt NameID"));
- throw new ProfileException("Unable to encrypt NameID", e);
- }
- } else {
- subject.setNameID(nameID);
- }
+ nameIdEncRequiredByConfig =
+ requestContext.getProfileConfiguration().getEncryptNameID() == CryptoOperationRequirementLevel.always
+ || (requestContext.getProfileConfiguration().getEncryptNameID() == CryptoOperationRequirementLevel.conditional
+ && !encoder.providesMessageConfidentiality(requestContext));
} catch (MessageEncodingException e) {
String msg = MessageFormatter.format(
"Unable to determine if outbound encoding '{}' provides message confidentiality protection",
log.error(msg);
throw new ProfileException(msg);
}
+
+ return nameIdEncRequiredByAuthnRequest || nameIdEncRequiredByConfig;
+ }
- return subject;
+ /**
+ * Determine whether information in the SAML request requires the issued NameID to
+ * be encrypted.
+ *
+ * @param requestContext the current request context
+ * @return true if the request indicates NameID encryption is required, false otherwise
+ */
+ protected boolean isRequestRequiresEncryptNameID(BaseSAML2ProfileRequestContext<?, ?, ?> requestContext) {
+ boolean nameIdEncRequiredByAuthnRequest = false;
+ if (requestContext.getInboundSAMLMessage() instanceof AuthnRequest) {
+ AuthnRequest authnRequest = (AuthnRequest) requestContext.getInboundSAMLMessage();
+ NameIDPolicy policy = authnRequest.getNameIDPolicy();
+ if (policy != null && DatatypeHelper.safeEquals(policy.getFormat(), NameID.ENCRYPTED)) {
+ nameIdEncRequiredByAuthnRequest = true;
+ }
+ }
+ return nameIdEncRequiredByAuthnRequest;
}
/**