* Resolves one or more SAML 1.x artifacts into a response containing a set of
* resolved Assertions. The caller is responsible for the resulting Response.
*
- * @param authenticated output flag set to true iff the resolution channel was authenticated
+ * @param securityMech will be set to identifier of security mechanism that authenticated the resolution
* @param artifacts one or more SAML 1.x artifacts
* @param idpDescriptor reference to IdP role of artifact issuer
* @param trustEngine optional pointer to X509TrustEngine supplied to MessageDecoder
* @return the corresponding SAML Assertions wrapped in a Response.
*/
virtual saml1p::Response* resolve(
- bool& authenticated,
+ const XMLCh*& securityMech,
const std::vector<SAMLArtifact*>& artifacts,
const saml2md::IDPSSODescriptor& idpDescriptor,
const X509TrustEngine* trustEngine=NULL
* Resolves a SAML 2.0 artifact into the corresponding SAML protocol message.
* The caller is responsible for the resulting ArtifactResponse message.
*
- * @param authenticated output flag set to true iff the resolution channel was authenticated
+ * @param securityMech will be set to identifier of security mechanism that authenticated the resolution
* @param artifact reference to a SAML 2.0 artifact
* @param ssoDescriptor reference to SSO role of artifact issuer (may be SP or IdP)
* @param trustEngine optional pointer to X509TrustEngine supplied to MessageDecoder
* @return the corresponding SAML protocol message or NULL
*/
virtual saml2p::ArtifactResponse* resolve(
- bool& authenticated,
+ const XMLCh*& securityMech,
const saml2p::SAML2Artifact& artifact,
const saml2md::SSODescriptorType& ssoDescriptor,
const X509TrustEngine* trustEngine=NULL
* <p>In some cases, a message may be returned but not authenticated. The caller
* should examine the issuerTrusted output value to establish this.
*
- * @param relayState RelayState/TARGET value accompanying message
- * @param issuer role descriptor of issuing party
- * @param issuerTrusted output flag set to true iff the message was authenticated
- * (signed or obtained via secure backchannel)
+ * @param relayState will be set to RelayState/TARGET value accompanying message
+ * @param issuer will be set to role descriptor of issuing party, if known
+ * @param securityMech will be set to identifier of security mechanism that authenticates the message
* @param httpRequest reference to interface for accessing HTTP message to decode
* @param metadataProvider optional MetadataProvider instance to authenticate the message
* @param role optional, identifies the role (generally IdP or SP) of the peer who issued the message
virtual xmltooling::XMLObject* decode(
std::string& relayState,
const saml2md::RoleDescriptor*& issuer,
- bool& issuerTrusted,
+ const XMLCh*& securityMech,
const HTTPRequest& httpRequest,
const saml2md::MetadataProvider* metadataProvider=NULL,
const xmltooling::QName* role=NULL,
Response* decode(
std::string& relayState,
const saml2md::RoleDescriptor*& issuer,
- bool& issuerTrusted,
+ const XMLCh*& securityMech,
const HTTPRequest& httpRequest,
const saml2md::MetadataProvider* metadataProvider=NULL,
const xmltooling::QName* role=NULL,
Response* decode(
std::string& relayState,
const saml2md::RoleDescriptor*& issuer,
- bool& issuerTrusted,
+ const XMLCh*& securityMech,
const HTTPRequest& httpRequest,
const saml2md::MetadataProvider* metadataProvider=NULL,
const xmltooling::QName* role=NULL,
Response* SAML1ArtifactDecoder::decode(
string& relayState,
const RoleDescriptor*& issuer,
- bool& issuerTrusted,
+ const XMLCh*& securityMech,
const HTTPRequest& httpRequest,
const MetadataProvider* metadataProvider,
const QName* role,
}
issuer = NULL;
- issuerTrusted = false;
+ securityMech = false;
log.debug("attempting to determine source of artifact(s)...");
const EntityDescriptor* provider=metadataProvider->getEntityDescriptor(artifacts.front());
if (!provider) {
try {
auto_ptr<Response> response(
m_artifactResolver->resolve(
- issuerTrusted,
+ securityMech,
artifacts,
dynamic_cast<const IDPSSODescriptor&>(*issuer),
dynamic_cast<const X509TrustEngine*>(trustEngine)
);
if (trustEngine && response->getSignature()) {
- issuerTrusted = trustEngine->validate(*(response->getSignature()), *issuer, metadataProvider->getKeyResolver());
- if (!issuerTrusted) {
+ if (!trustEngine->validate(*(response->getSignature()), *issuer, metadataProvider->getKeyResolver())) {
log.error("unable to verify signature on message with supplied trust engine");
throw BindingException("Message signature failed verification.");
}
+ else if (!securityMech) {
+ securityMech = samlconstants::SAML1P_NS;
+ }
}
- else if (!issuerTrusted) {
- log.warn("unable to verify integrity of the message, leaving untrusted");
+ else if (!securityMech) {
+ log.warn("unable to authenticate the message, leaving untrusted");
}
for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
Response* SAML1POSTDecoder::decode(
string& relayState,
const RoleDescriptor*& issuer,
- bool& issuerTrusted,
+ const XMLCh*& securityMech,
const HTTPRequest& httpRequest,
const MetadataProvider* metadataProvider,
const QName* role,
* applied.
*/
issuer = NULL;
- issuerTrusted = false;
+ securityMech = NULL;
log.debug("attempting to establish issuer and integrity of message...");
const vector<Assertion*>& assertions=const_cast<const Response*>(response)->getAssertions();
if (!assertions.empty()) {
);
if (issuer) {
if (trustEngine && response->getSignature()) {
- issuerTrusted = trustEngine->validate(
- *(response->getSignature()), *issuer, metadataProvider->getKeyResolver()
- );
- if (!issuerTrusted) {
+ if (trustEngine->validate(*(response->getSignature()), *issuer, metadataProvider->getKeyResolver())) {
+ securityMech = samlconstants::SAML1P_NS;
+ }
+ else {
log.error("unable to verify signature on message with supplied trust engine");
throw BindingException("Message signature failed verification.");
}
}
else {
- log.warn("unable to verify integrity of the message, leaving untrusted");
+ log.warn("unable to authenticate the message, leaving untrusted");
}
}
else {
}
if (log.isDebugEnabled()) {
auto_ptr_char iname(assertions.front()->getIssuer());
- log.debug("message from (%s), integrity %sverified", iname.get(), issuerTrusted ? "" : "NOT ");
+ log.debug("message from (%s), integrity %sverified", iname.get(), securityMech ? "" : "NOT ");
}
}
else {
xmltooling::XMLObject* decode(
std::string& relayState,
const saml2md::RoleDescriptor*& issuer,
- bool& issuerTrusted,
+ const XMLCh*& securityMech,
const HTTPRequest& httpRequest,
const saml2md::MetadataProvider* metadataProvider=NULL,
const xmltooling::QName* role=NULL,
xmltooling::XMLObject* decode(
std::string& relayState,
const saml2md::RoleDescriptor*& issuer,
- bool& issuerTrusted,
+ const XMLCh*& securityMech,
const HTTPRequest& httpRequest,
const saml2md::MetadataProvider* metadataProvider=NULL,
const xmltooling::QName* role=NULL,
XMLObject* SAML2ArtifactDecoder::decode(
string& relayState,
const RoleDescriptor*& issuer,
- bool& issuerTrusted,
+ const XMLCh*& securityMech,
const HTTPRequest& httpRequest,
const MetadataProvider* metadataProvider,
const QName* role,
}
issuer = NULL;
- issuerTrusted = false;
+ securityMech = NULL;
log.debug("attempting to determine source of artifact...");
const EntityDescriptor* provider=metadataProvider->getEntityDescriptor(artifact);
if (!provider) {
try {
auto_ptr<ArtifactResponse> response(
m_artifactResolver->resolve(
- issuerTrusted,
+ securityMech,
*(artifact2.get()),
dynamic_cast<const SSODescriptorType&>(*issuer),
dynamic_cast<const X509TrustEngine*>(trustEngine)
// Check signatures.
if (trustEngine) {
if (response->getSignature()) {
- issuerTrusted = trustEngine->validate(*(response->getSignature()), *issuer, metadataProvider->getKeyResolver());
- if (!issuerTrusted) {
+ if (!trustEngine->validate(*(response->getSignature()), *issuer, metadataProvider->getKeyResolver())) {
log.error("unable to verify signature on ArtifactResponse message with supplied trust engine");
throw BindingException("Message signature failed verification.");
}
+ else if (!securityMech) {
+ securityMech = samlconstants::SAML20P_NS;
+ }
}
Signature* sig = (res ? res->getSignature() : req->getSignature());
if (sig) {
- issuerTrusted = trustEngine->validate(*sig, *issuer, metadataProvider->getKeyResolver());
- if (!issuerTrusted) {
+ if (!trustEngine->validate(*sig, *issuer, metadataProvider->getKeyResolver())) {
log.error("unable to verify signature on ArtifactResponse payload with supplied trust engine");
throw BindingException("Message signature failed verification.");
}
+ else if (!securityMech) {
+ securityMech = samlconstants::SAML20P_NS;
+ }
}
}
- if (!issuerTrusted) {
- log.warn("unable to verify integrity of ArtifactResponse message or payload, leaving untrusted");
+ if (!securityMech) {
+ log.warn("unable to authenticate ArtifactResponse message or payload, leaving untrusted");
}
// Return the payload only.
XMLObject* SAML2POSTDecoder::decode(
string& relayState,
const RoleDescriptor*& issuer,
- bool& issuerTrusted,
+ const XMLCh*& securityMech,
const HTTPRequest& httpRequest,
const MetadataProvider* metadataProvider,
const QName* role,
log.warn("replay cache was not provided, this is a serious security risk!");
issuer = NULL;
- issuerTrusted = false;
+ securityMech = false;
log.debug("attempting to establish issuer and integrity of message...");
// If we can't identify the issuer, we're done, since we can't lookup or verify anything.
issuer=provider->getRoleDescriptor(*role, samlconstants::SAML20P_NS);
if (issuer) {
if (trustEngine && signature) {
- issuerTrusted = trustEngine->validate(*signature, *issuer, metadataProvider->getKeyResolver());
- if (!issuerTrusted) {
+ if (!trustEngine->validate(*signature, *issuer, metadataProvider->getKeyResolver())) {
log.error("unable to verify signature on message with supplied trust engine");
throw BindingException("Message signature failed verification.");
}
+ else {
+ securityMech = samlconstants::SAML20P_NS;
+ }
}
else {
- log.warn("unable to verify integrity of the message, leaving untrusted");
+ log.warn("unable to authenticate the message, leaving untrusted");
}
}
else {
}
if (log.isDebugEnabled()) {
auto_ptr_char iname(provider->getEntityID());
- log.debug("message from (%s), integrity %sverified", iname.get(), issuerTrusted ? "" : "NOT ");
+ log.debug("message from (%s), integrity %sverified", iname.get(), securityMech ? "" : "NOT ");
}
}
else {
using namespace opensaml::saml1p;
using namespace opensaml::saml1;
+namespace {\r
+ class SAML_DLLLOCAL _addcert : public binary_function<X509Data*,XSECCryptoX509*,void> {\r
+ public:\r
+ void operator()(X509Data* bag, XSECCryptoX509* cert) const {\r
+ safeBuffer& buf=cert->getDEREncodingSB();\r
+ X509Certificate* x=X509CertificateBuilder::buildX509Certificate();\r
+ x->setValue(buf.sbStrToXMLCh());\r
+ bag->getX509Certificates().push_back(x);\r
+ }\r
+ };\r
+};\r
+
class SAML1ArtifactTest : public CxxTest::TestSuite,
public SAMLBindingBaseTestCase, public MessageEncoder::ArtifactGenerator, public MessageDecoder::ArtifactResolver {
public:
// Decode message.
string relayState;
const RoleDescriptor* issuer=NULL;
- bool trusted=false;
+ const XMLCh* securityMech=NULL;
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
auto_ptr<MessageDecoder> decoder(
SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML1_PROFILE_BROWSER_ARTIFACT, NULL)
Locker locker(m_metadata);
auto_ptr<Response> response(
dynamic_cast<Response*>(
- decoder->decode(relayState,issuer,trusted,*this,m_metadata,&idprole,m_trust)
+ decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust)
)
);
// Test the results.
TSM_ASSERT_EQUALS("TARGET was not the expected result.", relayState, "state");
TSM_ASSERT("SAML Response not decoded successfully.", response.get());
- TSM_ASSERT("Message was not verified.", issuer && trusted);
+ TSM_ASSERT("Message was not verified.", issuer && securityMech && securityMech==samlconstants::SAML1P_NS);
auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());
TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));
TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);
// Trigger a replay.
TSM_ASSERT_THROWS("Did not catch the replay.",
- decoder->decode(relayState,issuer,trusted,*this,m_metadata,&idprole,m_trust),
+ decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust),
BindingException);
}
catch (XMLToolingException& ex) {
throw BindingException("Not implemented.");
}
+ Signature* buildSignature(const CredentialResolver* credResolver) const\r
+ {\r
+ // Build a Signature.\r
+ Signature* sig = SignatureBuilder::buildSignature();\r
+ sig->setSigningKey(credResolver->getKey());\r
+\r
+ // Build KeyInfo.\r
+ const vector<XSECCryptoX509*>& certs = credResolver->getCertificates();\r
+ if (!certs.empty()) {\r
+ KeyInfo* keyInfo=KeyInfoBuilder::buildKeyInfo();\r
+ X509Data* x509Data=X509DataBuilder::buildX509Data();\r
+ keyInfo->getX509Datas().push_back(x509Data);\r
+ for_each(certs.begin(),certs.end(),bind1st(_addcert(),x509Data));\r
+ sig->setKeyInfo(keyInfo);\r
+ }\r
+ \r
+ return sig;\r
+ }\r
+
Response* resolve(
- bool& authenticated,
+ const XMLCh*& securityMech,
const vector<SAMLArtifact*>& artifacts,
const IDPSSODescriptor& idpDescriptor,
const X509TrustEngine* trustEngine=NULL
StatusCode* sc = StatusCodeBuilder::buildStatusCode();
status->setStatusCode(sc);
sc->setValue(&StatusCode::SUCCESS);
- response->marshall();
+ response->setSignature(buildSignature(m_creds));
+ vector<Signature*> sigs(1,response->getSignature());
+ response->marshall((DOMDocument*)NULL,&sigs);
SchemaValidators.validate(response.get());
- authenticated = true;
+ securityMech = NULL;
return response.release();
}
saml2p::ArtifactResponse* resolve(
- bool& authenticated,
+ const XMLCh*& securityMech,
const saml2p::SAML2Artifact& artifact,
const SSODescriptorType& ssoDescriptor,
const X509TrustEngine* trustEngine=NULL
// Decode message.
string relayState;
const RoleDescriptor* issuer=NULL;
- bool trusted=false;
+ const XMLCh* securityMech=NULL;
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
auto_ptr<MessageDecoder> decoder(
SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML1_PROFILE_BROWSER_POST, NULL)
Locker locker(m_metadata);
auto_ptr<Response> response(
dynamic_cast<Response*>(
- decoder->decode(relayState,issuer,trusted,*this,m_metadata,&idprole,m_trust)
+ decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust)
)
);
// Test the results.
TSM_ASSERT_EQUALS("TARGET was not the expected result.", relayState, "state");
TSM_ASSERT("SAML Response not decoded successfully.", response.get());
- TSM_ASSERT("Message was not verified.", issuer && trusted);
+ TSM_ASSERT("Message was not verified.", issuer && securityMech && securityMech==samlconstants::SAML1P_NS);
auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());
TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));
TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);
// Decode message.
string relayState;
const RoleDescriptor* issuer=NULL;
- bool trusted=false;
+ const XMLCh* securityMech=NULL;
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
auto_ptr<MessageDecoder> decoder(
SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML1_PROFILE_BROWSER_POST, NULL)
Locker locker(m_metadata);
auto_ptr<Response> response(
dynamic_cast<Response*>(
- decoder->decode(relayState,issuer,trusted,*this,m_metadata,&idprole)
+ decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole)
)
);
// Test the results.
TSM_ASSERT_EQUALS("TARGET was not the expected result.", relayState, "state");
TSM_ASSERT("SAML Response not decoded successfully.", response.get());
- TSM_ASSERT("Message was verified.", issuer && !trusted);
+ TSM_ASSERT("Message was verified.", issuer && !securityMech);
auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());
TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));
TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);
// Trigger a replay.
TSM_ASSERT_THROWS("Did not catch the replay.",
- decoder->decode(relayState,issuer,trusted,*this,m_metadata,&idprole,m_trust),
+ decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust),
BindingException);
}
catch (XMLToolingException& ex) {
// Decode message.
string relayState;
const RoleDescriptor* issuer=NULL;
- bool trusted=false;
+ const XMLCh* securityMech=NULL;
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
auto_ptr<MessageDecoder> decoder(
SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML20_BINDING_HTTP_ARTIFACT, NULL)
Locker locker(m_metadata);
auto_ptr<Response> response(
dynamic_cast<Response*>(
- decoder->decode(relayState,issuer,trusted,*this,m_metadata,&idprole,m_trust)
+ decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust)
)
);
// Test the results.
TSM_ASSERT_EQUALS("RelayState was not the expected result.", relayState, "state");
TSM_ASSERT("SAML Response not decoded successfully.", response.get());
- TSM_ASSERT("Message was not verified.", issuer && trusted);
+ TSM_ASSERT("Message was not verified.", issuer && securityMech && securityMech==samlconstants::SAML20P_NS);
auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());
TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));
TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);
// Trigger a replay.
TSM_ASSERT_THROWS("Did not catch the replay.",
- decoder->decode(relayState,issuer,trusted,*this,m_metadata,&idprole,m_trust),
+ decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust),
BindingException);
}
catch (XMLToolingException& ex) {
}
saml1p::Response* resolve(
- bool& authenticated,
+ const XMLCh*& securityMech,
const vector<SAMLArtifact*>& artifacts,
const IDPSSODescriptor& idpDescriptor,
const X509TrustEngine* trustEngine=NULL
}
ArtifactResponse* resolve(
- bool& authenticated,
+ const XMLCh*& securityMech,
const SAML2Artifact& artifact,
const SSODescriptorType& ssoDescriptor,
const X509TrustEngine* trustEngine=NULL
sc->setValue(StatusCode::SUCCESS);
response->marshall();
SchemaValidators.validate(response.get());
- authenticated = true;
+ securityMech = NULL;
return response.release();
}
};
// Decode message.
string relayState;
const RoleDescriptor* issuer=NULL;
- bool trusted=false;
+ const XMLCh* securityMech=NULL;
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
auto_ptr<MessageDecoder> decoder(
SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML20_BINDING_HTTP_POST, NULL)
Locker locker(m_metadata);
auto_ptr<Response> response(
dynamic_cast<Response*>(
- decoder->decode(relayState,issuer,trusted,*this,m_metadata,&idprole,m_trust)
+ decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust)
)
);
// Test the results.
TSM_ASSERT_EQUALS("RelayState was not the expected result.", relayState, "state");
TSM_ASSERT("SAML Response not decoded successfully.", response.get());
- TSM_ASSERT("Message was not verified.", issuer && trusted);
+ TSM_ASSERT("Message was not verified.", issuer && securityMech && securityMech==samlconstants::SAML20P_NS);
auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());
TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));
TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);
// Decode message.
string relayState;
const RoleDescriptor* issuer=NULL;
- bool trusted=false;
+ const XMLCh* securityMech=NULL;
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
auto_ptr<MessageDecoder> decoder(
SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML20_BINDING_HTTP_POST, NULL)
Locker locker(m_metadata);
auto_ptr<Response> response(
dynamic_cast<Response*>(
- decoder->decode(relayState,issuer,trusted,*this,m_metadata,&idprole)
+ decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole)
)
);
// Test the results.
TSM_ASSERT_EQUALS("RelayState was not the expected result.", relayState, "state");
TSM_ASSERT("SAML Response not decoded successfully.", response.get());
- TSM_ASSERT("Message was verified.", issuer && !trusted);
+ TSM_ASSERT("Message was verified.", issuer && !securityMech);
auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());
TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));
TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);
// Trigger a replay.
TSM_ASSERT_THROWS("Did not catch the replay.",
- decoder->decode(relayState,issuer,trusted,*this,m_metadata,&idprole,m_trust),
+ decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust),
BindingException);
}
catch (XMLToolingException& ex) {