</sequence>
<attribute name="id" type="conf:string" fixed="default"/>
<attribute name="entityID" type="anyURI" use="required"/>
- <attribute name="policyId" type="conf:string"/>
<attributeGroup ref="conf:ApplicationGroup"/>
<attributeGroup ref="conf:RelyingPartyGroup"/>
<anyAttribute namespace="##other" processContents="lax"/>
</sequence>
<attribute name="id" type="conf:string" use="required"/>
<attribute name="entityID" type="anyURI"/>
- <attribute name="policyId" type="conf:string"/>
<attributeGroup ref="conf:ApplicationGroup"/>
<attributeGroup ref="conf:RelyingPartyGroup"/>
<anyAttribute namespace="##other" processContents="lax"/>
<attributeGroup name="ApplicationGroup">
<attribute name="homeURL" type="anyURI"/>
+ <attribute name="policyId" type="conf:string"/>
<attribute name="REMOTE_USER" type="conf:listOfStrings"/>
<attribute name="unsetHeaders" type="conf:listOfStrings"/>
<attribute name="metadataAttributePrefix" type="conf:string"/>
<attribute name="attributePrefix" type="conf:string"/>
+ <attribute name="requireAuthenticatedCipher" type="boolean"/>
</attributeGroup>
<attributeGroup name="RelyingPartyGroup">
m_log.warn("simple resolver only supports one assertion in the query response");
}
- CredentialResolver* cr=application.getCredentialResolver();
+ CredentialResolver* cr = application.getCredentialResolver();
if (!cr) {
m_log.warn("found encrypted assertion, but no CredentialResolver was available");
throw FatalProfileException("Assertion was encrypted, but no decryption credentials are available.");
}
+ // With this flag on, we block unauthenticated ciphertext when decrypting,
+ // unless the protocol was authenticated.
+ pair<bool,bool> authenticatedCipher = application.getBool("requireAuthenticatedCipher");
+ if (policy->isAuthenticated())
+ authenticatedCipher.second = false;
+
// Attempt to decrypt it.
try {
Locker credlocker(cr);
- auto_ptr<XMLObject> tokenwrapper(encassertions.front()->decrypt(*cr, relyingParty->getXMLString("entityID").second, &mcc));
+ auto_ptr<XMLObject> tokenwrapper(
+ encassertions.front()->decrypt(
+ *cr, relyingParty->getXMLString("entityID").second, &mcc, authenticatedCipher.first && authenticatedCipher.second
+ )
+ );
newtoken = dynamic_cast<saml2::Assertion*>(tokenwrapper.get());
if (newtoken) {
tokenwrapper.release();
throw FatalProfileException("Assertion was encrypted, but no decryption credentials are available.");
}
+ // With this flag on, we block unauthenticated ciphertext when decrypting,
+ // unless the protocol was authenticated.
+ pair<bool,bool> authenticatedCipher = application.getBool("requireAuthenticatedCipher");
+ if (policy->isAuthenticated())
+ authenticatedCipher.second = false;
+
// Attempt to decrypt it.
try {
Locker credlocker(cr);
- auto_ptr<XMLObject> tokenwrapper(encassertions.front()->decrypt(*cr, relyingParty->getXMLString("entityID").second, &mcc));
+ auto_ptr<XMLObject> tokenwrapper(
+ encassertions.front()->decrypt(
+ *cr, relyingParty->getXMLString("entityID").second, &mcc, authenticatedCipher.first && authenticatedCipher.second
+ )
+ );
newtoken = dynamic_cast<saml2::Assertion*>(tokenwrapper.get());
if (newtoken) {
tokenwrapper.release();
// And also track "owned" tokens that we decrypt here.
vector< boost::shared_ptr<saml2::Assertion> > ownedtokens;
+ // With this flag on, we block unauthenticated ciphertext when decrypting,
+ // unless the protocol was authenticated.
+ pair<bool,bool> requireAuthenticatedCipher = application.getBool("requireAuthenticatedCipher");
+ if (alreadySecured)
+ requireAuthenticatedCipher.second = false;
+
// With this flag on, we ignore any unsigned assertions.
const EntityDescriptor* entity = nullptr;
- pair<bool,bool> flag = make_pair(false,false);
+ pair<bool,bool> requireSignedAssertions = make_pair(false,false);
if (alreadySecured && policy.getIssuerMetadata()) {
entity = dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent());
- flag = application.getRelyingParty(entity)->getBool("requireSignedAssertions");
+ const PropertySet* rp = application.getRelyingParty(entity);
+ requireSignedAssertions = rp->getBool("requireSignedAssertions");
}
// authnskew allows rejection of SSO if AuthnInstant is too old.
a != make_indirect_iterator(assertions.end()); ++a) {
try {
// Skip unsigned assertion?
- if (!a->getSignature() && flag.first && flag.second)
+ if (!a->getSignature() && requireSignedAssertions.first && requireSignedAssertions.second)
throw SecurityPolicyException("The incoming assertion was unsigned, violating local security policy.");
// We clear the security flag, so we can tell whether the token was secured on its own.
// If we hadn't established Issuer yet, redo the signedAssertions check.
if (!entity && policy.getIssuerMetadata()) {
entity = dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent());
- flag = application.getRelyingParty(entity)->getBool("requireSignedAssertions");
- if (!a->getSignature() && flag.first && flag.second)
+ requireSignedAssertions = application.getRelyingParty(entity)->getBool("requireSignedAssertions");
+ if (!a->getSignature() && requireSignedAssertions.first && requireSignedAssertions.second)
throw SecurityPolicyException("The incoming assertion was unsigned, violating local security policy.");
}
}
// In case we need decryption...
- CredentialResolver* cr=application.getCredentialResolver();
+ CredentialResolver* cr = application.getCredentialResolver();
if (!cr && !encassertions.empty())
m_log.warn("found encrypted assertions, but no CredentialResolver was available");
scoped_ptr<MetadataCredentialCriteria> mcc(
policy.getIssuerMetadata() ? new MetadataCredentialCriteria(*policy.getIssuerMetadata()) : nullptr
);
- boost::shared_ptr<XMLObject> wrapper(ea->decrypt(*cr, application.getRelyingParty(entity)->getXMLString("entityID").second, mcc.get()));
+ boost::shared_ptr<XMLObject> wrapper(
+ ea->decrypt(
+ *cr,
+ application.getRelyingParty(entity)->getXMLString("entityID").second,
+ mcc.get(),
+ requireAuthenticatedCipher.first && requireAuthenticatedCipher.second
+ )
+ );
decrypted = dynamic_pointer_cast<saml2::Assertion>(wrapper);
if (decrypted) {
ownedtokens.push_back(decrypted);
continue;
try {
+ // Skip unsigned assertion?
+ if (!decrypted->getSignature() && requireSignedAssertions.first && requireSignedAssertions.second)
+ throw SecurityPolicyException("The incoming assertion was unsigned, violating local security policy.");
+
// We clear the security flag, so we can tell whether the token was secured on its own.
policy.setAuthenticated(false);
policy.reset(true);
// If we hadn't established Issuer yet, redo the signedAssertions check.
if (!entity && policy.getIssuerMetadata()) {
entity = dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent());
- flag = application.getRelyingParty(entity)->getBool("requireSignedAssertions");
- if (!decrypted->getSignature() && flag.first && flag.second)
+ requireSignedAssertions = application.getRelyingParty(entity)->getBool("requireSignedAssertions");
+ if (!decrypted->getSignature() && requireSignedAssertions.first && requireSignedAssertions.second)
throw SecurityPolicyException("The decrypted assertion was unsigned, violating local security policy.");
}