# include <shibsp/attribute/resolver/ResolutionContext.h>
# include <shibsp/metadata/MetadataProviderCriteria.h>
# include <saml/SAMLConfig.h>
+# include <saml/binding/SecurityPolicy.h>
# include <saml/saml1/core/Assertions.h>
-# include <saml/saml1/profile/AssertionValidator.h>
# include <saml/saml2/core/Assertions.h>
# include <saml/saml2/metadata/Metadata.h>
# include <saml/saml2/metadata/EndpointManager.h>
-# include <saml/saml2/profile/AssertionValidator.h>
+# include <xmltooling/XMLToolingConfig.h>
# include <xmltooling/impl/AnyElement.h>
# include <xmltooling/validation/ValidatorSuite.h>
using namespace opensaml::saml2md;
{
public:
ADFSSessionInitiator(const DOMElement* e, const char* appId)
- : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".SessionInitiator.ADFS")), m_appId(appId), m_binding(WSFED_NS) {
+ : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".SessionInitiator.ADFS"), NULL, &m_remapper), m_appId(appId), m_binding(WSFED_NS) {
// If Location isn't set, defer address registration until the setParent call.
pair<bool,const char*> loc = getString("Location");
if (loc.first) {
const Application& app=request.getApplication();
if (isHandler) {
+ option=request.getParameter("acsIndex");
+ if (option) {
+ ACS = app.getAssertionConsumerServiceByIndex(atoi(option));
+ if (!ACS)
+ request.log(SPRequest::SPWarn, "invalid acsIndex specified in request, using acsIndex property");
+ }
+
option = request.getParameter("target");
if (option)
target = option;
}
// Since we're not passing by index, we need to fully compute the return URL.
- // Get all the ADFS endpoints.
- const vector<const Handler*>& handlers = app.getAssertionConsumerServicesByBinding(m_binding.get());
-
- // Index comes from request, or default set in the handler, or we just pick the first endpoint.
- pair<bool,unsigned int> index(false,0);
- if (isHandler) {
- option = request.getParameter("acsIndex");
- if (option)
- index = pair<bool,unsigned int>(true, atoi(option));
- }
- if (!index.first)
- index = getUnsignedInt("defaultACSIndex");
- if (index.first) {
- for (vector<const Handler*>::const_iterator h = handlers.begin(); !ACS && h!=handlers.end(); ++h) {
- if (index.second == (*h)->getUnsignedInt("index").second)
- ACS = *h;
+ if (!ACS) {
+ pair<bool,unsigned int> index = getUnsignedInt("acsIndex");
+ if (index.first) {
+ ACS = app.getAssertionConsumerServiceByIndex(index.second);
+ if (!ACS)
+ request.log(SPRequest::SPWarn, "invalid acsIndex property, using default ACS location");
}
+ if (!ACS)
+ ACS = app.getDefaultAssertionConsumerService();
}
- else if (!handlers.empty()) {
- ACS = handlers.front();
+
+ // Validate the ACS for use with this protocol.
+ pair<bool,const XMLCh*> ACSbinding = ACS ? ACS->getXMLString("Binding") : pair<bool,const XMLCh*>(false,NULL);
+ if (ACSbinding.first) {
+ if (!XMLString::equals(ACSbinding.second, m_binding.get())) {
+ m_log.info("configured or requested ACS has non-ADFS binding");
+ return make_pair(false,0L);
+ }
}
- if (!ACS)
- throw ConfigurationException("Unable to locate ADFS response endpoint.");
// Compute the ACS URL. We add the ACS location to the base handlerURL.
string ACSloc=request.getHandlerURL(target.c_str());
throw MetadataException("Unable to locate metadata for identity provider ($entityID)", namedparams(1, "entityID", entityID));
}
else if (!entity.second) {
- m_log.warn("unable to locate ADFS-aware identity provider role for provider (%s)", entityID);
+ m_log.log(getParent() ? Priority::INFO : Priority::WARN, "unable to locate ADFS-aware identity provider role for provider (%s)", entityID);
if (getParent())
return make_pair(false,0L);
throw MetadataException("Unable to locate ADFS-aware identity provider role for provider ($entityID)", namedparams(1, "entityID", entityID));
throw BindingException("Decoded message was not of the appropriate type.");
}
- if (!policy.getValidating())
- SchemaValidators.validate(xmlObject.get());
+ SchemaValidators.validate(xmlObject.get());
// Skip policy step here, there's no security in the wrapper.
// policy.evaluate(*xmlObject.get(), &genericRequest);
// Extract message and issuer details from assertion.
extractMessageDetails(*token, m_protocol.get(), policy);
+ // Populate recipient as audience.
+ const EntityDescriptor* entity = policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL;
+ policy.getAudiences().push_back(application.getRelyingParty(entity)->getXMLString("entityID").second);
+
// Run the policy over the assertion. Handles replay, freshness, and
- // signature verification, assuming the relevant rules are configured.
+ // signature verification, assuming the relevant rules are configured,
+ // along with condition enforcement.
policy.evaluate(*token, &httpRequest);
// If no security is in place now, we kick it.
if (!policy.isAuthenticated())
throw SecurityPolicyException("Unable to establish security of incoming assertion.");
- time_t now = time(NULL);
-
- const PropertySet* sessionProps = application.getPropertySet("Sessions");
- const EntityDescriptor* entity = policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL;
-
saml1::NameIdentifier* saml1name=NULL;
saml2::NameID* saml2name=NULL;
const XMLCh* authMethod=NULL;
const XMLCh* authInstant=NULL;
- time_t sessionExp = 0;
+ time_t now = time(NULL), sessionExp = 0;
+ const PropertySet* sessionProps = application.getPropertySet("Sessions");
const saml1::Assertion* saml1token = dynamic_cast<const saml1::Assertion*>(token);
if (saml1token) {
- // Now do profile and core semantic validation to ensure we can use it for SSO.
- saml1::AssertionValidator ssoValidator(application.getRelyingParty(entity)->getXMLString("entityID").second, application.getAudiences(), now);
- ssoValidator.validateAssertion(*saml1token);
+ // Now do profile validation to ensure we can use it for SSO.
if (!saml1token->getConditions() || !saml1token->getConditions()->getNotBefore() || !saml1token->getConditions()->getNotOnOrAfter())
throw FatalProfileException("Assertion did not contain time conditions.");
else if (saml1token->getAuthenticationStatements().empty())
if (!saml2token)
throw FatalProfileException("Incoming message did not contain a recognized type of SAML assertion.");
- // Now do profile and core semantic validation to ensure we can use it for SSO.
- saml2::AssertionValidator ssoValidator(application.getRelyingParty(entity)->getXMLString("entityID").second, application.getAudiences(), now);
- ssoValidator.validateAssertion(*saml2token);
+ // Now do profile validation to ensure we can use it for SSO.
if (!saml2token->getConditions() || !saml2token->getConditions()->getNotBefore() || !saml2token->getConditions()->getNotOnOrAfter())
throw FatalProfileException("Assertion did not contain time conditions.");
else if (saml2token->getAuthnStatements().empty())