From: Scott Cantor Date: Thu, 18 May 2006 18:28:58 +0000 (+0000) Subject: Refactored signature handling. X-Git-Tag: 2.0-alpha1~250 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-opensaml.git;a=commitdiff_plain;h=bb6f92163780b968239c19fdfbe22c0a0a4cd35a Refactored signature handling. --- diff --git a/.cdtproject b/.cdtproject index c59f390..1acb183 100644 --- a/.cdtproject +++ b/.cdtproject @@ -3,7 +3,7 @@ - + diff --git a/saml/Makefile.am b/saml/Makefile.am index 6171f9f..4bf8fb3 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -15,8 +15,9 @@ libsamlinclude_HEADERS = \ SAMLConfig.h siginclude_HEADERS = \ - signature/SigningContext.h \ - signature/VerifyingContext.h + signature/ContentReference.h \ + signature/SignableObject.h \ + signature/SignatureProfileValidator.h utilinclude_HEADERS = \ util/SAMLConstants.h @@ -34,8 +35,8 @@ libsaml_la_SOURCES = \ saml1/core/impl/AssertionsSchemaValidators.cpp \ saml1/core/impl/ProtocolsImpl.cpp \ saml1/core/impl/ProtocolsSchemaValidators.cpp \ - signature/SigningContext.cpp \ - signature/VerifyingContext.cpp \ + signature/ContentReference.cpp \ + signature/SignatureProfileValidator.cpp \ util/SAMLConstants.cpp # this is different from the project version diff --git a/saml/saml.vcproj b/saml/saml.vcproj index 216d6a5..29d3479 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -225,11 +225,11 @@ Name="signature" > @@ -287,11 +287,15 @@ Name="signature" > + + diff --git a/saml/saml1/core/Assertions.h b/saml/saml1/core/Assertions.h index 28c417b..d7a1a35 100644 --- a/saml/saml1/core/Assertions.h +++ b/saml/saml1/core/Assertions.h @@ -24,7 +24,9 @@ #define __saml1_assertions_h__ #include +#include #include + #include #include #include @@ -216,7 +218,7 @@ namespace opensaml { static const XMLCh TYPE_NAME[]; END_XMLOBJECT; - BEGIN_XMLOBJECT(SAML_API,Assertion,xmltooling::XMLObject,SAML 1.x Assertion element); + BEGIN_XMLOBJECT(SAML_API,Assertion,SignableObject,SAML 1.x Assertion element); DECL_INTEGER_ATTRIB(MinorVersion,MINORVERSION); DECL_STRING_ATTRIB(AssertionID,ASSERTIONID); DECL_STRING_ATTRIB(Issuer,ISSUER); diff --git a/saml/saml1/core/Protocols.h b/saml/saml1/core/Protocols.h index 48413a8..7d694c5 100644 --- a/saml/saml1/core/Protocols.h +++ b/saml/saml1/core/Protocols.h @@ -70,7 +70,7 @@ namespace opensaml { static const XMLCh TYPE_NAME[]; END_XMLOBJECT; - BEGIN_XMLOBJECT(SAML_API,AbstractRequest,xmltooling::XMLObject,SAML 1.x RequestAbstractType base type); + BEGIN_XMLOBJECT(SAML_API,AbstractRequest,SignableObject,SAML 1.x RequestAbstractType base type); DECL_INTEGER_ATTRIB(MinorVersion,MINORVERSION); DECL_STRING_ATTRIB(RequestID,REQUESTID); DECL_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT); @@ -111,12 +111,38 @@ namespace opensaml { static const XMLCh TYPE_NAME[]; END_XMLOBJECT; + BEGIN_XMLOBJECT(SAML_API,Status,xmltooling::XMLObject,SAML 1.x Status element); + DECL_TYPED_CHILD(StatusCode); + DECL_TYPED_CHILD(StatusMessage); + DECL_TYPED_CHILD(StatusDetail); + /** StatusType local name */ + static const XMLCh TYPE_NAME[]; + END_XMLOBJECT; + + BEGIN_XMLOBJECT(SAML_API,AbstractResponse,SignableObject,SAML 1.x ResponseAbstractType base type); + DECL_INTEGER_ATTRIB(MinorVersion,MINORVERSION); + DECL_STRING_ATTRIB(ResponseID,RESPONSEID); + DECL_STRING_ATTRIB(InResponseTo,INRESPONSETO); + DECL_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT); + DECL_STRING_ATTRIB(Recipient,RECIPIENT); + DECL_TYPED_FOREIGN_CHILD(Signature,xmlsignature); + END_XMLOBJECT; + + BEGIN_XMLOBJECT(SAML_API,Response,AbstractResponse,SAML 1.x Response element); + DECL_TYPED_CHILD(Status); + DECL_TYPED_CHILDREN(Assertion); + /** ResponseType local name */ + static const XMLCh TYPE_NAME[]; + END_XMLOBJECT; + DECL_SAML1POBJECTBUILDER(AssertionArtifact); DECL_SAML1POBJECTBUILDER(AttributeQuery); DECL_SAML1POBJECTBUILDER(AuthenticationQuery); DECL_SAML1POBJECTBUILDER(AuthorizationDecisionQuery); DECL_SAML1POBJECTBUILDER(Request); DECL_SAML1POBJECTBUILDER(RespondWith); + DECL_SAML1POBJECTBUILDER(Response); + DECL_SAML1POBJECTBUILDER(Status); DECL_SAML1POBJECTBUILDER(StatusCode); DECL_SAML1POBJECTBUILDER(StatusDetail); DECL_SAML1POBJECTBUILDER(StatusMessage); diff --git a/saml/saml1/core/impl/AssertionsImpl.cpp b/saml/saml1/core/impl/AssertionsImpl.cpp index 8ada823..f73a271 100644 --- a/saml/saml1/core/impl/AssertionsImpl.cpp +++ b/saml/saml1/core/impl/AssertionsImpl.cpp @@ -945,6 +945,23 @@ namespace opensaml { public AbstractXMLObjectMarshaller, public AbstractXMLObjectUnmarshaller { + void init() { + m_MinorVersion=1; + m_AssertionID=NULL; + m_Issuer=NULL; + m_IssueInstant=NULL; + m_children.push_back(NULL); + m_children.push_back(NULL); + m_children.push_back(NULL); + m_Conditions=NULL; + m_Advice=NULL; + m_Signature=NULL; + m_pos_Conditions=m_children.begin(); + m_pos_Advice=m_pos_Conditions; + m_pos_Advice++; + m_pos_Signature=m_pos_Advice; + m_pos_Signature++; + } public: virtual ~AssertionImpl() { XMLString::release(&m_AssertionID); @@ -1007,22 +1024,26 @@ namespace opensaml { } } - void init() { - m_MinorVersion=1; - m_AssertionID=NULL; - m_Issuer=NULL; - m_IssueInstant=NULL; - m_children.push_back(NULL); - m_children.push_back(NULL); - m_children.push_back(NULL); - m_Conditions=NULL; - m_Advice=NULL; - m_Signature=NULL; - m_pos_Conditions=m_children.begin(); - m_pos_Advice=m_pos_Conditions; - m_pos_Advice++; - m_pos_Signature=m_pos_Advice; - m_pos_Signature++; + const XMLCh* getId() const { + return getAssertionID(); + } + + //IMPL_TYPED_CHILD(Signature); + // Need customized setter. + protected: + Signature* m_Signature; + list::iterator m_pos_Signature; + public: + Signature* getSignature() const { + return m_Signature; + } + + void setSignature(Signature* sig) { + prepareForAssignment(m_Signature,sig); + *m_pos_Signature=m_Signature=sig; + // Sync content reference back up. + if (m_Signature) + m_Signature->setContentReference(new opensaml::ContentReference(*this)); } IMPL_XMLOBJECT_CLONE(Assertion); @@ -1032,7 +1053,6 @@ namespace opensaml { IMPL_DATETIME_ATTRIB(IssueInstant); IMPL_TYPED_CHILD(Conditions); IMPL_TYPED_CHILD(Advice); - IMPL_TYPED_CHILD(Signature); IMPL_TYPED_CHILDREN(Statement, m_pos_Signature); IMPL_TYPED_CHILDREN(SubjectStatement, m_pos_Signature); IMPL_TYPED_CHILDREN(AuthenticationStatement, m_pos_Signature); diff --git a/saml/saml1/core/impl/ProtocolsImpl.cpp b/saml/saml1/core/impl/ProtocolsImpl.cpp index fbdd632..24317e4 100644 --- a/saml/saml1/core/impl/ProtocolsImpl.cpp +++ b/saml/saml1/core/impl/ProtocolsImpl.cpp @@ -344,11 +344,32 @@ namespace opensaml { } } + const XMLCh* getId() const { + return getRequestID(); + } + + //IMPL_TYPED_CHILD(Signature); + // Need customized setter. + protected: + Signature* m_Signature; + list::iterator m_pos_Signature; + public: + Signature* getSignature() const { + return m_Signature; + } + + void setSignature(Signature* sig) { + prepareForAssignment(m_Signature,sig); + *m_pos_Signature=m_Signature=sig; + // Sync content reference back up. + if (m_Signature) + m_Signature->setContentReference(new opensaml::ContentReference(*this)); + } + IMPL_INTEGER_ATTRIB(MinorVersion); IMPL_STRING_ATTRIB(RequestID); IMPL_DATETIME_ATTRIB(IssueInstant); IMPL_TYPED_CHILDREN(RespondWith,m_pos_Signature); - IMPL_TYPED_CHILD(Signature); protected: void marshallAttributes(DOMElement* domElement) const { @@ -544,6 +565,212 @@ namespace opensaml { } }; + class SAML_DLLLOCAL StatusImpl : public virtual Status, + public AbstractComplexElement, + public AbstractDOMCachingXMLObject, + public AbstractValidatingXMLObject, + public AbstractXMLObjectMarshaller, + public AbstractXMLObjectUnmarshaller + { + void init() { + m_children.push_back(NULL); + m_children.push_back(NULL); + m_children.push_back(NULL); + m_StatusCode=NULL; + m_pos_StatusCode=m_children.begin(); + m_StatusMessage=NULL; + m_pos_StatusMessage=m_pos_StatusCode; + m_pos_StatusMessage++; + m_StatusDetail=NULL; + m_pos_StatusDetail=m_pos_StatusMessage; + m_pos_StatusDetail++; + } + public: + virtual ~StatusImpl() {} + + StatusImpl(const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix, const QName* schemaType) + : AbstractXMLObject(nsURI, localName, prefix, schemaType) { + init(); + } + + StatusImpl(const StatusImpl& src) + : AbstractXMLObject(src), AbstractDOMCachingXMLObject(src), AbstractValidatingXMLObject(src) { + init(); + if (src.getStatusCode()) + setStatusCode(src.getStatusCode()->cloneStatusCode()); + if (src.getStatusMessage()) + setStatusMessage(src.getStatusMessage()->cloneStatusMessage()); + if (src.getStatusDetail()) + setStatusDetail(src.getStatusDetail()->cloneStatusDetail()); + } + + IMPL_XMLOBJECT_CLONE(Status); + IMPL_TYPED_CHILD(StatusCode); + IMPL_TYPED_CHILD(StatusMessage); + IMPL_TYPED_CHILD(StatusDetail); + + protected: + void processChildElement(XMLObject* childXMLObject, const DOMElement* root) { + PROC_TYPED_CHILD(StatusCode,SAMLConstants::SAML1P_NS,false); + PROC_TYPED_CHILD(StatusMessage,SAMLConstants::SAML1P_NS,false); + PROC_TYPED_CHILD(StatusDetail,SAMLConstants::SAML1P_NS,false); + AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root); + } + }; + + class SAML_DLLLOCAL AbstractResponseImpl : public virtual AbstractResponse, + public AbstractComplexElement, + public AbstractDOMCachingXMLObject, + public AbstractValidatingXMLObject, + public AbstractXMLObjectMarshaller, + public AbstractXMLObjectUnmarshaller + { + void init() { + m_MinorVersion=1; + m_ResponseID=NULL; + m_InResponseTo=NULL; + m_IssueInstant=NULL; + m_Recipient=NULL; + m_children.push_back(NULL); + m_Signature=NULL; + m_pos_Signature=m_children.begin(); + } + protected: + AbstractResponseImpl() {} + public: + virtual ~AbstractResponseImpl() { + XMLString::release(&m_ResponseID); + XMLString::release(&m_InResponseTo); + XMLString::release(&m_Recipient); + delete m_IssueInstant; + } + + AbstractResponseImpl(const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix, const QName* schemaType) + : AbstractXMLObject(nsURI, localName, prefix, schemaType) { + init(); + } + + AbstractResponseImpl(const AbstractResponseImpl& src) + : AbstractXMLObject(src), + AbstractDOMCachingXMLObject(src), + AbstractValidatingXMLObject(src) { + init(); + setMinorVersion(src.getMinorVersion()); + setResponseID(src.getResponseID()); + setInResponseTo(src.getInResponseTo()); + setIssueInstant(src.getIssueInstant()); + setRecipient(src.getRecipient()); + if (src.getSignature()) + setSignature(src.getSignature()->cloneSignature()); + } + + const XMLCh* getId() const { + return getResponseID(); + } + + //IMPL_TYPED_CHILD(Signature); + // Need customized setter. + protected: + Signature* m_Signature; + list::iterator m_pos_Signature; + public: + Signature* getSignature() const { + return m_Signature; + } + + void setSignature(Signature* sig) { + prepareForAssignment(m_Signature,sig); + *m_pos_Signature=m_Signature=sig; + // Sync content reference back up. + if (m_Signature) + m_Signature->setContentReference(new opensaml::ContentReference(*this)); + } + + IMPL_INTEGER_ATTRIB(MinorVersion); + IMPL_STRING_ATTRIB(ResponseID); + IMPL_STRING_ATTRIB(InResponseTo); + IMPL_DATETIME_ATTRIB(IssueInstant); + IMPL_STRING_ATTRIB(Recipient); + + protected: + void marshallAttributes(DOMElement* domElement) const { + static const XMLCh MAJORVERSION[] = UNICODE_LITERAL_12(M,a,j,o,r,V,e,r,s,i,o,n); + static const XMLCh ONE[] = { chDigit_1, chNull }; + domElement->setAttributeNS(NULL,MAJORVERSION,ONE); + MARSHALL_INTEGER_ATTRIB(MinorVersion,MINORVERSION,NULL); + if (!m_ResponseID) + const_cast(this)->m_ResponseID=SAMLConfig::getConfig().generateIdentifier(); + MARSHALL_ID_ATTRIB(ResponseID,RESPONSEID,NULL); + MARSHALL_STRING_ATTRIB(InResponseTo,INRESPONSETO,NULL); + if (!m_IssueInstant) + const_cast(this)->m_IssueInstant=new DateTime(time(NULL)); + MARSHALL_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT,NULL); + MARSHALL_STRING_ATTRIB(Recipient,RECIPIENT,NULL); + } + + void processChildElement(XMLObject* childXMLObject, const DOMElement* root) { + PROC_TYPED_CHILD(Signature,XMLConstants::XMLSIG_NS,false); + AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root); + } + + void processAttribute(const DOMAttr* attribute) { + static const XMLCh MAJORVERSION[] = UNICODE_LITERAL_12(M,a,j,o,r,V,e,r,s,i,o,n); + if (XMLHelper::isNodeNamed(attribute,NULL,MAJORVERSION)) { + if (XMLString::parseInt(attribute->getValue()) != 1) + throw UnmarshallingException("Response has invalid major version."); + } + PROC_INTEGER_ATTRIB(MinorVersion,MINORVERSION,NULL); + PROC_ID_ATTRIB(ResponseID,RESPONSEID,NULL); + PROC_STRING_ATTRIB(InResponseTo,INRESPONSETO,NULL); + PROC_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT,NULL); + PROC_STRING_ATTRIB(Recipient,RECIPIENT,NULL); + } + }; + + class SAML_DLLLOCAL ResponseImpl : public virtual Response, public AbstractResponseImpl + { + void init() { + m_children.push_back(NULL); + m_Status=NULL; + m_pos_Status=m_pos_Signature; + m_pos_Status++; + } + public: + virtual ~ResponseImpl() {} + + ResponseImpl(const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix, const QName* schemaType) + : AbstractXMLObject(nsURI, localName, prefix, schemaType) { + init(); + } + + ResponseImpl(const ResponseImpl& src) + : AbstractXMLObject(src), AbstractResponseImpl(src) { + init(); + if (src.getStatus()) + setStatus(src.getStatus()->cloneStatus()); + VectorOf(Assertion) v=getAssertions(); + for (vector::const_iterator i=src.m_Assertions.begin(); i!=src.m_Assertions.end(); i++) { + if (*i) { + v.push_back((*i)->cloneAssertion()); + } + } + } + + IMPL_XMLOBJECT_CLONE(Response); + AbstractResponse* cloneAbstractResponse() const { + return cloneResponse(); + } + IMPL_TYPED_CHILD(Status); + IMPL_TYPED_CHILDREN(Assertion, m_children.end()); + + protected: + void processChildElement(XMLObject* childXMLObject, const DOMElement* root) { + PROC_TYPED_CHILD(Status,SAMLConstants::SAML1P_NS,false); + PROC_TYPED_CHILDREN(Assertion,SAMLConstants::SAML1_NS,true); + AbstractResponseImpl::processChildElement(childXMLObject,root); + } + }; + }; }; @@ -559,6 +786,8 @@ IMPL_XMLOBJECTBUILDER(AuthenticationQuery); IMPL_XMLOBJECTBUILDER(AuthorizationDecisionQuery); IMPL_XMLOBJECTBUILDER(Request); IMPL_XMLOBJECTBUILDER(RespondWith); +IMPL_XMLOBJECTBUILDER(Response); +IMPL_XMLOBJECTBUILDER(Status); IMPL_XMLOBJECTBUILDER(StatusCode); IMPL_XMLOBJECTBUILDER(StatusDetail); IMPL_XMLOBJECTBUILDER(StatusMessage); @@ -567,6 +796,11 @@ IMPL_XMLOBJECTBUILDER(StatusMessage); const XMLCh AbstractRequest::MINORVERSION_ATTRIB_NAME[] = UNICODE_LITERAL_12(M,i,n,o,r,V,e,r,s,i,o,n); const XMLCh AbstractRequest::REQUESTID_ATTRIB_NAME[] = UNICODE_LITERAL_9(R,e,q,u,e,s,t,I,D); const XMLCh AbstractRequest::ISSUEINSTANT_ATTRIB_NAME[] = UNICODE_LITERAL_12(I,s,s,u,e,I,n,s,t,a,n,t); +const XMLCh AbstractResponse::MINORVERSION_ATTRIB_NAME[] = UNICODE_LITERAL_12(M,i,n,o,r,V,e,r,s,i,o,n); +const XMLCh AbstractResponse::RESPONSEID_ATTRIB_NAME[] = UNICODE_LITERAL_10(R,e,s,p,o,n,s,e,I,D); +const XMLCh AbstractResponse::ISSUEINSTANT_ATTRIB_NAME[] = UNICODE_LITERAL_12(I,s,s,u,e,I,n,s,t,a,n,t); +const XMLCh AbstractResponse::INRESPONSETO_ATTRIB_NAME[] = UNICODE_LITERAL_12(I,n,R,e,s,p,o,n,s,e,T,o); +const XMLCh AbstractResponse::RECIPIENT_ATTRIB_NAME[] = UNICODE_LITERAL_9(R,e,c,i,p,i,e,n,t); const XMLCh AssertionArtifact::LOCAL_NAME[] = UNICODE_LITERAL_17(A,s,s,e,r,t,i,o,n,A,r,t,i,f,a,c,t); const XMLCh AttributeQuery::LOCAL_NAME[] = UNICODE_LITERAL_14(A,t,t,r,i,b,u,t,e,Q,u,e,r,y); const XMLCh AttributeQuery::TYPE_NAME[] = UNICODE_LITERAL_18(A,t,t,r,i,b,u,t,e,Q,u,e,r,y,T,y,p,e); @@ -581,6 +815,10 @@ const XMLCh Query::LOCAL_NAME[] = UNICODE_LITERAL_5(Q, const XMLCh Request::LOCAL_NAME[] = UNICODE_LITERAL_7(R,e,q,u,e,s,t); const XMLCh Request::TYPE_NAME[] = UNICODE_LITERAL_11(R,e,q,u,e,s,t,T,y,p,e); const XMLCh RespondWith::LOCAL_NAME[] = UNICODE_LITERAL_11(R,e,s,p,o,n,d,W,i,t,h); +const XMLCh Response::LOCAL_NAME[] = UNICODE_LITERAL_8(R,e,s,p,o,n,s,e); +const XMLCh Response::TYPE_NAME[] = UNICODE_LITERAL_12(R,e,s,p,o,n,s,e,T,y,p,e); +const XMLCh Status::LOCAL_NAME[] = UNICODE_LITERAL_6(S,t,a,t,u,s); +const XMLCh Status::TYPE_NAME[] = UNICODE_LITERAL_10(S,t,a,t,u,s,T,y,p,e); const XMLCh StatusCode::LOCAL_NAME[] = UNICODE_LITERAL_10(S,t,a,t,u,s,C,o,d,e); const XMLCh StatusCode::TYPE_NAME[] = UNICODE_LITERAL_14(S,t,a,t,u,s,C,o,d,e,T,y,p,e); const XMLCh StatusCode::VALUE_ATTRIB_NAME[] = UNICODE_LITERAL_5(V,a,l,u,e); diff --git a/saml/saml1/core/impl/ProtocolsSchemaValidators.cpp b/saml/saml1/core/impl/ProtocolsSchemaValidators.cpp index d4b1bc2..1fe5041 100644 --- a/saml/saml1/core/impl/ProtocolsSchemaValidators.cpp +++ b/saml/saml1/core/impl/ProtocolsSchemaValidators.cpp @@ -71,6 +71,20 @@ namespace opensaml { BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,StatusCode); XMLOBJECTVALIDATOR_REQUIRE(StatusCode,Value); END_XMLOBJECTVALIDATOR; + + BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,Status); + XMLOBJECTVALIDATOR_REQUIRE(Status,StatusCode); + const QName* value=ptr->getStatusCode()->getValue(); + if (!value || (*value!=StatusCode::SUCCESS && *value!=StatusCode::REQUESTER && + *value!=StatusCode::RESPONDER && *value!=StatusCode::VERSIONMISMATCH)) + throw ValidationException("Top-level status code not one of the allowable values."); + END_XMLOBJECTVALIDATOR; + + BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,Response); + XMLOBJECTVALIDATOR_REQUIRE(Response,ResponseID); + XMLOBJECTVALIDATOR_REQUIRE(Response,IssueInstant); + XMLOBJECTVALIDATOR_REQUIRE(Response,Status); + END_XMLOBJECTVALIDATOR; }; }; @@ -100,6 +114,8 @@ void opensaml::saml1::registerProtocolClasses() { REGISTER_ELEMENT(AuthorizationDecisionQuery); REGISTER_ELEMENT(Request); REGISTER_ELEMENT(RespondWith); + REGISTER_ELEMENT(Response); + REGISTER_ELEMENT(Status); REGISTER_ELEMENT(StatusCode); REGISTER_ELEMENT_NOVAL(StatusDetail); REGISTER_ELEMENT(StatusMessage); @@ -107,6 +123,8 @@ void opensaml::saml1::registerProtocolClasses() { REGISTER_TYPE(AuthenticationQuery); REGISTER_TYPE(AuthorizationDecisionQuery); REGISTER_TYPE(Request); + REGISTER_TYPE(Response); + REGISTER_TYPE(Status); REGISTER_TYPE(StatusCode); REGISTER_TYPE_NOVAL(StatusDetail); } diff --git a/saml/signature/SigningContext.cpp b/saml/signature/ContentReference.cpp similarity index 71% rename from saml/signature/SigningContext.cpp rename to saml/signature/ContentReference.cpp index e77052b..1b452e8 100644 --- a/saml/signature/SigningContext.cpp +++ b/saml/signature/ContentReference.cpp @@ -15,14 +15,16 @@ */ /** - * SigningContext.cpp + * ContentReference.cpp * - * SAML-specific signature construction + * SAML-specific signature reference profile */ #include "internal.h" -#include "signature/SigningContext.h" +#include "signature/ContentReference.h" +#include "signature/SignableObject.h" +#include #include #include #include @@ -40,13 +42,17 @@ public: } }; -bool SigningContext::createSignature(DSIGSignature* sig) +void ContentReference::createReferences(DSIGSignature* sig) { + const XMLCh* id=m_signableObject.getId(); + if (!id || !*id) + throw xmlsignature::SignatureException("Cannot create Signature reference to SAML object without an identifier."); + DSIGReference* ref=NULL; - XMLCh* buf=new XMLCh[XMLString::stringLen(m_id) + 2]; + XMLCh* buf=new XMLCh[XMLString::stringLen(id) + 2]; buf[0]=chPound; buf[1]=chNull; - XMLString::catString(buf,m_id); + XMLString::catString(buf,id); try { ref=sig->createReference(buf); delete[] buf; @@ -58,6 +64,4 @@ bool SigningContext::createSignature(DSIGSignature* sig) ref->appendEnvelopedSignatureTransform(); DSIGTransformC14n* c14n=ref->appendCanonicalizationTransform(CANON_C14NE_NOC); for_each(m_prefixes.begin(), m_prefixes.end(), bind1st(_addprefix(),c14n)); - - return false; } diff --git a/saml/signature/ContentReference.h b/saml/signature/ContentReference.h new file mode 100644 index 0000000..fd7f0d8 --- /dev/null +++ b/saml/signature/ContentReference.h @@ -0,0 +1,78 @@ +/* + * Copyright 2001-2006 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file SigningContext.h + * + * SAML-specific signature reference profile + */ + +#ifndef __saml_sigref_h__ +#define __saml_sigref_h__ + +#include +#include + +namespace opensaml { + + class SAML_API SignableObject; + + /** + * SAML-specific signature reference profile. + */ + class SAML_API ContentReference : public virtual xmlsignature::ContentReference + { + public: + /** + * Constructor. + * + * @param signableObject reference to object being signed + */ + ContentReference(const SignableObject& signableObject) : m_signableObject(signableObject) { + } + + virtual ~ContentReference() {} + + /** + * Given a "blank" native signature, creates signature reference + * appropriate for the SAML object being signed. + * + * @param sig native signature interface + */ + virtual void createReferences(DSIGSignature* sig); + + /** + * Adds a namespace prefix for "inclusive" processing by the + * Exclusive C14N Transform applied to the object. + * An empty string will be transformed into "#default". + * + * @param prefix the prefix to add + */ + void addInclusivePrefix(const char* prefix) { + m_prefixes.push_back(prefix); + } + + protected: + /** Reference to object to sign. */ + const SignableObject& m_signableObject; + + /** Inclusive prefixes. */ + std::vector m_prefixes; + }; + +}; + +#endif /* __saml_sigref_h__ */ diff --git a/saml/signature/SignableObject.h b/saml/signature/SignableObject.h new file mode 100644 index 0000000..10cbb73 --- /dev/null +++ b/saml/signature/SignableObject.h @@ -0,0 +1,65 @@ +/* + * Copyright 2001-2006 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file SignableObject.h + * + * Base class for SAML objects that can be signed. + */ + +#ifndef __saml_signable_h__ +#define __saml_signable_h__ + +#include +#include +#include + +namespace opensaml { + + /** + * Base class for SAML objects that can be signed. + */ + class SAML_API SignableObject : public virtual xmltooling::XMLObject + { + public: + virtual ~SignableObject() {} + + /** + * Returns the XML ID for the object being signed, for input to the + * reference creation process. + * + * @return XML ID or NULL if not set yet + */ + virtual const XMLCh* getId() const=0; + + /** + * Gets a new ContentReference object bound to this object. + * It's lifetime must not outlast this object, so it should + * generally be set into a Signature owned by the object. + * + * @return a new ContentReference + */ + virtual ContentReference* getContentReference() const { + return new ContentReference(*this); + } + + protected: + SignableObject() {} + }; + +}; + +#endif /* __saml_signable_h__ */ diff --git a/saml/signature/VerifyingContext.cpp b/saml/signature/SignatureProfileValidator.cpp similarity index 66% rename from saml/signature/VerifyingContext.cpp rename to saml/signature/SignatureProfileValidator.cpp index def1f98..279f8ed 100644 --- a/saml/signature/VerifyingContext.cpp +++ b/saml/signature/SignatureProfileValidator.cpp @@ -21,7 +21,8 @@ */ #include "internal.h" -#include "signature/VerifyingContext.h" +#include "exceptions.h" +#include "signature/SignatureProfileValidator.h" #include @@ -31,18 +32,30 @@ #include using namespace opensaml; +using namespace xmlsignature; +using namespace xmltooling; using namespace std; -void VerifyingContext::verifySignature(DSIGSignature* sig) const +void SignatureProfileValidator::validate(const XMLObject* xmlObject) const { - bool valid=false; + const Signature* sigObj=dynamic_cast(xmlObject); + if (!sigObj) + throw ValidationException("Validator only applies to Signature objects."); + DSIGSignature* sig=sigObj->getXMLSignature(); + if (!sig) + throw ValidationException("Signature does not exist yet."); + const SignableObject* signableObj=dynamic_cast(sigObj->getParent()); + if (!signableObj) + throw ValidationException("Signature is not a child of a signable SAML object."); + + bool valid=false; DSIGReferenceList* refs=sig->getReferenceList(); if (refs && refs->getSize()==1) { DSIGReference* ref=refs->item(0); if (ref) { const XMLCh* URI=ref->getURI(); - if (URI==NULL || *URI==0 || (*URI==chPound && !XMLString::compareString(URI+1,m_id))) { + if (URI==NULL || *URI==0 || (*URI==chPound && !XMLString::compareString(URI+1,signableObj->getId()))) { DSIGTransformList* tlist=ref->getTransforms(); for (unsigned int i=0; tlist && igetSize(); i++) { if (tlist->item(i)->getTransformType()==TRANSFORM_ENVELOPED_SIGNATURE) @@ -58,5 +71,5 @@ void VerifyingContext::verifySignature(DSIGSignature* sig) const } if (!valid) - throw xmlsignature::SignatureException("Invalid signature profile for SAML object."); + throw ValidationException("Invalid signature profile for SAML object."); } diff --git a/saml/signature/SignatureProfileValidator.h b/saml/signature/SignatureProfileValidator.h new file mode 100644 index 0000000..3c96d32 --- /dev/null +++ b/saml/signature/SignatureProfileValidator.h @@ -0,0 +1,50 @@ +/* + * Copyright 2001-2006 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file SignatureProfileValidator.h + * + * SAML-specific signature profile validator + */ + +#ifndef __saml_sigval_h__ +#define __saml_sigval_h__ + +#include +#include +#include + +namespace opensaml { + + /** + * SAML-specific signature profile validator. + */ + class SAML_API SignatureProfileValidator : public virtual xmltooling::Validator + { + public: + SignatureProfileValidator() {} + virtual ~SignatureProfileValidator() {} + + void validate(const xmltooling::XMLObject* xmlObject) const; + + SignatureProfileValidator* clone() const { + return new SignatureProfileValidator(); + } + }; + +}; + +#endif /* __saml_sigval_h__ */ diff --git a/saml/signature/SigningContext.h b/saml/signature/SigningContext.h deleted file mode 100644 index f737bbc..0000000 --- a/saml/signature/SigningContext.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2001-2006 Internet2 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file SigningContext.h - * - * SAML-specific signature construction - */ - -#ifndef __saml_signctx_h__ -#define __saml_signctx_h__ - -#include -#include - -namespace opensaml { - - /** - * SAML-specific signature profile context. - * This is not a synchronized implementation. - */ - class SAML_API SigningContext : public virtual xmlsignature::SigningContext - { - public: - /** - * Constructor. - * - * @param id identifier of object being signed - * @param credentials resolver to signing key/certs to use - * @param keyInfo a complete KeyInfo object to attach, will be freed by context - */ - SigningContext(const XMLCh* id, xmltooling::CredentialResolver& creds, xmlsignature::KeyInfo* keyInfo=NULL) - : m_id(id), m_creds(creds), m_keyInfo(keyInfo) { - } - - virtual ~SigningContext() { - delete m_keyInfo; - } - - /** - * Given a "blank" native signature, creates signature content - * appropriate for the SAML assertion or message being signed. - * - * @param sig native signature interface - * @return indicator whether ds:KeyInfo was created by context - */ - virtual bool createSignature(DSIGSignature* sig); - - /** - * Gets a reference to the credential resolver supplied during construction. - * - * @return the resolver - */ - virtual xmltooling::CredentialResolver& getCredentialResolver() { - return m_creds; - } - - /** - * Gets a KeyInfo structure to embed. - * Ownership of the object MUST be transferred to the caller. - * This method will only be called if no certificates are returned from - * the getX509Certificates() method. - * - * @return pointer to a KeyInfo structure, will be freed by caller - */ - virtual xmlsignature::KeyInfo* getKeyInfo() { - xmlsignature::KeyInfo* ret=m_keyInfo; - m_keyInfo=NULL; - return ret; - } - - void addInclusivePrefix(const char* prefix) { - m_prefixes.push_back(prefix); - } - - protected: - /** Identifier of object to sign. */ - const XMLCh* m_id; - - /** Reference to credentials to sign with. */ - xmltooling::CredentialResolver& m_creds; - - /** Optional pointer to KeyInfo to embed. */ - mutable xmlsignature::KeyInfo* m_keyInfo; - - /** Inclusive prefixes. */ - std::vector m_prefixes; - }; - -}; - -#endif /* __saml_signctx_h__ */ diff --git a/saml/signature/VerifyingContext.h b/saml/signature/VerifyingContext.h deleted file mode 100644 index 261cfdf..0000000 --- a/saml/signature/VerifyingContext.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2001-2006 Internet2 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file VerifyingContext.h - * - * SAML-specific signature verification - */ - -#ifndef __saml_verctx_h__ -#define __saml_verctx_h__ - -#include -#include - -namespace opensaml { - - /** - * SAML-specific signature profile verification. - */ - class SAML_API VerifyingContext : public virtual xmlsignature::VerifyingContext - { - public: - /** - * Constructor. - * - * @param id identifier of object being verified - */ - VerifyingContext(const XMLCh* id) : m_id(id) {} - - virtual ~VerifyingContext() {} - - /** - * Given a native signature, verifies that the signature content - * is appropriate for the SAML assertion/message being verified. - * Does NOT perform actual cryptographic evaluation - * of the signature in the absence of policy. Subclasses should - * override this method with their policies, call the base class - * and then evaluate further. - * - * @param sig native signature object - * - * @throws SignatureException raised if signature is invalid - */ - virtual void verifySignature(DSIGSignature* sig) const; - - protected: - /** Identifier of object to verify. */ - const XMLCh* m_id; - }; - -}; - -#endif /* __saml_verctx_h__ */ diff --git a/samltest/data/signature/SAML1Assertion.xml b/samltest/data/signature/SAML1Assertion.xml index 25a29d9..7e0b127 100644 --- a/samltest/data/signature/SAML1Assertion.xml +++ b/samltest/data/signature/SAML1Assertion.xml @@ -18,9 +18,7 @@ AuthenticationMethod="method" AA5098JC4gfdAf2bvPQRZ9Ld/VehXAB3uhp0r4js4i6fMB3hGMs4VnE9iEJEsPDD 0Kj4cfewxHij/kHrWcxpKMMqIgGlqKYZhuQHfFt8GzDeeFIgu1R675jcN4uCOoWl 3aRVd9hgPRsXzf7/RkMiXHIsU/NjUPRKf7GjNt2jNT0= - - -MIICjzCCAfigAwIBAgIJAKk8t1hYcMkhMA0GCSqGSIb3DQEBBAUAMDoxCzAJBgNV +MIICjzCCAfigAwIBAgIJAKk8t1hYcMkhMA0GCSqGSIb3DQEBBAUAMDoxCzAJBgNV BAYTAlVTMRIwEAYDVQQKEwlJbnRlcm5ldDIxFzAVBgNVBAMTDnNwLmV4YW1wbGUu b3JnMB4XDTA1MDYyMDE1NDgzNFoXDTMyMTEwNTE1NDgzNFowOjELMAkGA1UEBhMC VVMxEjAQBgNVBAoTCUludGVybmV0MjEXMBUGA1UEAxMOc3AuZXhhbXBsZS5vcmcw @@ -33,8 +31,4 @@ CQYDVQQGEwJVUzESMBAGA1UEChMJSW50ZXJuZXQyMRcwFQYDVQQDEw5zcC5leGFt cGxlLm9yZ4IJAKk8t1hYcMkhMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQAD gYEAMFq/UeSQyngE0GpZueyD2UW0M358uhseYOgGEIfm+qXIFQF6MYwNoX7WFzhC LJZ2E6mEvZZFHCHUtl7mGDvsRwgZ85YCtRbvleEpqfgNQToto9pLYe+X6vvH9Z6p -gmYsTmak+kxO93JprrOd9xp8aZPMEprL7VCdrhbZEfyYER0= - - - - \ No newline at end of file +gmYsTmak+kxO93JprrOd9xp8aZPMEprL7VCdrhbZEfyYER0= \ No newline at end of file diff --git a/samltest/signature/SAML1AssertionTest.h b/samltest/signature/SAML1AssertionTest.h index cb07142..05cae8e 100644 --- a/samltest/signature/SAML1AssertionTest.h +++ b/samltest/signature/SAML1AssertionTest.h @@ -16,10 +16,9 @@ #include "internal.h" #include -#include -#include +#include -using namespace opensaml::saml1; +#include #include #include @@ -27,14 +26,59 @@ using namespace opensaml::saml1; #include #include #include -#include +#include +#include -class TestContext : public virtual CredentialResolver, public SigningContext, public VerifyingContext +using namespace opensaml::saml1; +using namespace xmlsignature; + +class TestValidator : public Validator { +public: + TestValidator() {} + virtual ~TestValidator() {} + + Validator* clone() const { + return new TestValidator(); + } + + void validate(const XMLObject* xmlObject) const { + DSIGSignature* sig=dynamic_cast(xmlObject)->getXMLSignature(); + if (!sig) + throw SignatureException("Only a marshalled Signature object can be verified."); + XSECKeyInfoResolverDefault resolver; + sig->setKeyInfoResolver(&resolver); // It will clone the resolver for us. + try { + if (!sig->verify()) + throw SignatureException("Signature did not verify."); + } + catch(XSECException& e) { + auto_ptr_char temp(e.getMsg()); + throw SignatureException(string("Caught an XMLSecurity exception verifying signature: ") + temp.get()); + } + catch(XSECCryptoException& e) { + throw SignatureException(string("Caught an XMLSecurity exception verifying signature: ") + e.getMsg()); + } + } +}; + +class _addcert : public std::binary_function { +public: + void operator()(X509Data* bag, XSECCryptoX509* cert) const { + safeBuffer& buf=cert->getDEREncodingSB(); + X509Certificate* x=X509CertificateBuilder::buildX509Certificate(); + x->setValue(buf.sbStrToXMLCh()); + bag->getX509Certificates().push_back(x); + } +}; + +class SAML1AssertionTest : public CxxTest::TestSuite, public SAMLObjectBaseTestCase { + XSECCryptoKey* m_key; vector m_certs; - OpenSSLCryptoKeyRSA* m_key; public: - TestContext(const XMLCh* uri) : VerifyingContext(uri), SigningContext(uri,*this), m_key(NULL) { + void setUp() { + childElementsFile = data_path + "signature/SAML1Assertion.xml"; + SAMLObjectBaseTestCase::setUp(); string keypath=data_path + "key.pem"; BIO* in=BIO_new(BIO_s_file_internal()); if (in && BIO_read_filename(in,keypath.c_str())>0) { @@ -59,38 +103,11 @@ public: if (in) BIO_free(in); TS_ASSERT(m_certs.size()>0); } - - virtual ~TestContext() { - delete m_key; - for_each(m_certs.begin(),m_certs.end(),xmltooling::cleanup()); - } - - void verifySignature(DSIGSignature* sig) const { - VerifyingContext::verifySignature(sig); - sig->setSigningKey(NULL); - XSECKeyInfoResolverDefault resolver; - sig->setKeyInfoResolver(&resolver); - sig->verify(); - } - - xmlsignature::KeyInfo* getKeyInfo() { return NULL; } - const char* getId() const { return "test"; } - const vector* getX509Certificates() { return &m_certs; } - XSECCryptoKey* getPublicKey() { return m_key; } - XSECCryptoKey* getPrivateKey() { return m_key; } - Lockable& lock() { return *this; } - void unlock() {} -}; - -class SAML1AssertionTest : public CxxTest::TestSuite, public SAMLObjectBaseTestCase { -public: - void setUp() { - childElementsFile = data_path + "signature/SAML1Assertion.xml"; - SAMLObjectBaseTestCase::setUp(); - } void tearDown() { SAMLObjectBaseTestCase::tearDown(); + delete m_key; + for_each(m_certs.begin(),m_certs.end(),xmltooling::cleanup()); } void testSignature() { @@ -117,13 +134,27 @@ public: assertion->getAuthenticationStatements().push_back(statement); // Append a Signature. - xmlsignature::Signature* sig=xmlsignature::SignatureBuilder::newSignature(); + Signature* sig=SignatureBuilder::buildSignature(); assertion->setSignature(sig); - - // Signing context for the assertion. - TestContext tc(id.get()); - MarshallingContext mctx(sig,&tc); - DOMElement* rootElement = assertion->marshall((DOMDocument*)NULL,&mctx); + sig->setSigningKey(m_key->clone()); + + // Build KeyInfo. + KeyInfo* keyInfo=KeyInfoBuilder::buildKeyInfo(); + X509Data* x509Data=X509DataBuilder::buildX509Data(); + keyInfo->getX509Datas().push_back(x509Data); + for_each(m_certs.begin(),m_certs.end(),bind1st(_addcert(),x509Data)); + sig->setKeyInfo(keyInfo); + + // Sign while marshalling. + vector sigs(1,sig); + DOMElement* rootElement = NULL; + try { + rootElement=assertion->marshall((DOMDocument*)NULL,&sigs); + } + catch (XMLToolingException& e) { + TS_TRACE(e.what()); + throw; + } string buf; XMLHelper::serialize(rootElement, buf); @@ -134,9 +165,11 @@ public: assertEquals(expectedChildElementsDOM, b->buildFromDocument(doc)); try { - assertion->getSignature()->verify(tc); + assertion->getSignature()->registerValidator(new SignatureProfileValidator()); + assertion->getSignature()->registerValidator(new TestValidator()); + assertion->getSignature()->validate(true); } - catch (xmlsignature::SignatureException& e) { + catch (XMLToolingException& e) { TS_TRACE(e.what()); throw; }