From 099f6c2a2b356d31f88f727e0e6f9abae76e8be2 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Tue, 1 Aug 2006 04:16:10 +0000 Subject: [PATCH] SAML 1.x artifact bits --- .cdtproject | 4 +- saml/Makefile.am | 8 +- saml/SAMLArtifact.cpp | 114 +++++++++++++++++++ saml/SAMLArtifact.h | 158 ++++++++++++++++++++++++++ saml/SAMLConfig.cpp | 41 ++++++- saml/SAMLConfig.h | 18 ++- saml/internal.h | 1 + saml/saml.vcproj | 36 ++++++ saml/saml1/core/SAMLArtifactType0001.h | 87 ++++++++++++++ saml/saml1/core/SAMLArtifactType0002.h | 84 ++++++++++++++ saml/saml1/core/impl/SAMLArtifactType0001.cpp | 77 +++++++++++++ saml/saml1/core/impl/SAMLArtifactType0002.cpp | 76 +++++++++++++ 12 files changed, 698 insertions(+), 6 deletions(-) create mode 100644 saml/SAMLArtifact.cpp create mode 100644 saml/SAMLArtifact.h create mode 100644 saml/saml1/core/SAMLArtifactType0001.h create mode 100644 saml/saml1/core/SAMLArtifactType0002.h create mode 100644 saml/saml1/core/impl/SAMLArtifactType0001.cpp create mode 100644 saml/saml1/core/impl/SAMLArtifactType0002.cpp diff --git a/.cdtproject b/.cdtproject index 0a9b7ac..00d9ac0 100644 --- a/.cdtproject +++ b/.cdtproject @@ -60,9 +60,11 @@ - + + + diff --git a/saml/Makefile.am b/saml/Makefile.am index 3a215c0..97ea7b1 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -20,6 +20,7 @@ libsamlinclude_HEADERS = \ base.h \ exceptions.h \ version.h \ + SAMLArtifact.h \ SAMLConfig.h encinclude_HEADERS = \ @@ -35,7 +36,9 @@ utilinclude_HEADERS = \ saml1coreinclude_HEADERS = \ saml1/core/Assertions.h \ - saml1/core/Protocols.h + saml1/core/Protocols.h \ + saml1/core/SAMLArtifactType0001.h \ + saml1/core/SAMLArtifactType0002.h saml2coreinclude_HEADERS = \ saml2/core/Assertions.h \ @@ -50,12 +53,15 @@ noinst_HEADERS = \ internal.h libsaml_la_SOURCES = \ + SAMLArtifact.h \ SAMLConfig.cpp \ encryption/EncryptedKeyResolver.cpp \ saml1/core/impl/AssertionsImpl.cpp \ saml1/core/impl/AssertionsSchemaValidators.cpp \ saml1/core/impl/ProtocolsImpl.cpp \ saml1/core/impl/ProtocolsSchemaValidators.cpp \ + saml1/core/impl/SAMLArtifactType0001.cpp \ + saml1/core/impl/SAMLArtifactType0002.cpp \ saml2/core/impl/Assertions20Impl.cpp \ saml2/core/impl/Assertions20SchemaValidators.cpp \ saml2/core/impl/Protocols20Impl.cpp \ diff --git a/saml/SAMLArtifact.cpp b/saml/SAMLArtifact.cpp new file mode 100644 index 0000000..1f1bead --- /dev/null +++ b/saml/SAMLArtifact.cpp @@ -0,0 +1,114 @@ +/* + * 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. + */ + +/** + * SAMLArtifact.cpp + * + * Base class for SAML 1.x and 2.0 artifacts + */ + +#include "internal.h" +#include "SAMLArtifact.h" + +#include + +using namespace opensaml; +using namespace xmltooling; +using namespace std; + +namespace opensaml { + namespace saml1p { + SAML_DLLLOCAL PluginManager::Factory SAMLArtifactType0001Factory; + SAML_DLLLOCAL PluginManager::Factory SAMLArtifactType0002Factory; + }; + + namespace saml2p { + //SAML_DLLLOCAL PluginManager::Factory SAMLArtifactType0004Factory; + }; +}; + +void SAML_API opensaml::registerSAMLArtifacts() +{ + SAMLConfig& conf=SAMLConfig::getConfig(); + + string typecode; + typecode+=(char)0x0; + typecode+=(char)0x1; + conf.SAMLArtifactManager.registerFactory(typecode, saml1p::SAMLArtifactType0001Factory); + typecode[1]=(char)0x2; + conf.SAMLArtifactManager.registerFactory(typecode, saml1p::SAMLArtifactType0002Factory); + //typecode[1]=(char)0x4; + //conf.SAMLArtifactManager.registerFactory(typecode, saml2p::SAMLArtifactType0004Factory); +} + +const unsigned int SAMLArtifact::TYPECODE_LENGTH = 2; + +// Basic constructor just decodes the string and saves it off. +// Subclasses will handle pulling it apart. + +SAMLArtifact::SAMLArtifact(const char* s) +{ + unsigned int len=0; + XMLByte* decoded=Base64::decode(reinterpret_cast(s),&len); + if (!decoded) + throw ArtifactException("Unable to decode base64 artifact."); + XMLByte* ptr=decoded; + while (len--) + m_raw+= *ptr++; + XMLString::release(&decoded); +} + +string SAMLArtifact::encode() const +{ + unsigned int len=0; + XMLByte* out=Base64::encode(reinterpret_cast(m_raw.data()),m_raw.size(),&len); + if (out) { + string ret(reinterpret_cast(out),len); + XMLString::release(&out); + return ret; + } + return string(); +} + +SAMLArtifact* SAMLArtifact::parse(const char* s) +{ + // Decode and extract the type code first. + unsigned int len=0; + XMLByte* decoded=Base64::decode(reinterpret_cast(s),&len); + if (!decoded) + throw ArtifactException("Artifact parser unable to decode base64-encoded artifact."); + + string type; + type+= decoded[0]; + type+= decoded[1]; + XMLString::release(&decoded); + + return SAMLConfig::getConfig().SAMLArtifactManager.newPlugin(type,s); +} + +string SAMLArtifact::toHex(const string& s) +{ + static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + string::size_type len = s.length(); + string ret; + + // two characters form the hex value. + for (string::size_type i=0; i < len; i++) { + ret+=(DIGITS[((unsigned char)(0xF0 & s[i])) >> 4 ]); + ret+=(DIGITS[0x0F & s[i]]); + } + return ret; +} diff --git a/saml/SAMLArtifact.h b/saml/SAMLArtifact.h new file mode 100644 index 0000000..5281205 --- /dev/null +++ b/saml/SAMLArtifact.h @@ -0,0 +1,158 @@ +/* + * 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 saml/SAMLArtifact.h + * + * Base class for SAML 1.x and 2.0 artifacts + */ + +#ifndef __saml_artifact_h__ +#define __saml_artifact_h__ + +#include + +#include +#include + +namespace opensaml { + + /** + * Base class for SAML 1.x and 2.0 artifacts. + */ + class SAML_API SAMLArtifact + { + SAMLArtifact& operator=(const SAMLArtifact& src); + public: + virtual ~SAMLArtifact() {} + + /** + * Returns artifact encoded into null-terminated base64 for transmission. + */ + virtual std::string encode() const; + + /** + * Builds a duplicate, independent artifact of the same type. + * + * @return the new artifact + */ + virtual SAMLArtifact* clone() const=0; + + /** + * Returns all of the raw binary data that makes up the artifact. + * The result is NOT null-terminated. + * + * @return the binary artifact data + */ + virtual std::string getBytes() const { + return m_raw; + } + + /** + * Returns the binary type code of the artifact. + * The result is NOT null-terminated. + * + * @return the binary type code + */ + virtual std::string getTypeCode() const { + return m_raw.substr(0,TYPECODE_LENGTH); + } + + /** + * Returns the binary artifact data following the type code. + * The result is NOT null-terminated. + * + * @return the binary artifact data + */ + virtual std::string getRemainingArtifact() const { + return m_raw.substr(TYPECODE_LENGTH); + } + + /** + * Returns the binary data that identifies the source of the artifact. + * The exact form this takes depends on the type. + * The result is NOT null-terminated. + * + * @return the binary source data + */ + virtual std::string getSource() const=0; + + /** + * Returns the binary data that references the message (2.0) or assertion (1.x) + * The exact form this takes depends on the type. + * The result is NOT null-terminated. + * + * @return the binary reference data + */ + virtual std::string getMessageHandle() const=0; + + /** Length of type code */ + static const unsigned int TYPECODE_LENGTH; + + /** + * Parses a base64-encoded null-terminated string into an artifact, + * if the type is known. + * + * @param s base64-encoded artifact + * @return the decoded artifact + */ + static SAMLArtifact* parse(const char* s); + + /** + * Parses a base64-encoded null-terminated string into an artifact, + * if the type is known. + * + * @param s base64-encoded artifact + * @return the decoded artifact + */ + static SAMLArtifact* parse(const XMLCh* s) { + xmltooling::auto_ptr_char temp(s); + return parse(temp.get()); + } + + /** + * Converts binary data to hex notation. + * + * @param s the bytes to convert + * @return the data in hex form, 2 characters per byte + */ + static std::string toHex(const std::string& s); + + protected: + SAMLArtifact() {} + + /** + * Decodes a base64-encoded artifact into its raw form. + * + * @param s NULL-terminated base64-encoded string + */ + SAMLArtifact(const char* s); + + SAMLArtifact(const SAMLArtifact& src) : m_raw(src.m_raw) {} + + /** Raw binary data that makes up an artifact. */ + std::string m_raw; + }; + + DECL_XMLTOOLING_EXCEPTION(ArtifactException,SAML_EXCEPTIONAPI(SAML_API),opensaml,xmltooling::XMLToolingException,Exceptions related to artifact parsing); + + /** + * Registers SAMLArtifact subclasses into the runtime. + */ + void SAML_API registerSAMLArtifacts(); +}; + +#endif /* __saml_artifact_h__ */ diff --git a/saml/SAMLConfig.cpp b/saml/SAMLConfig.cpp index ad8a6df..695964a 100644 --- a/saml/SAMLConfig.cpp +++ b/saml/SAMLConfig.cpp @@ -20,10 +20,9 @@ * Library configuration */ -#define SAML_DECLARE_VALIDATORS - #include "internal.h" #include "exceptions.h" +#include "SAMLArtifact.h" #include "SAMLConfig.h" #include "saml1/core/Assertions.h" #include "saml1/core/Protocols.h" @@ -38,15 +37,18 @@ #include #include +#include #include + using namespace opensaml; using namespace xmlsignature; using namespace xmltooling; using namespace log4cpp; using namespace std; -//DECL_EXCEPTION_FACTORY(XMLParserException,xmltooling); +DECL_EXCEPTION_FACTORY(ArtifactException,opensaml); +DECL_EXCEPTION_FACTORY(MetadataFilterException,opensaml::saml2md); namespace opensaml { SAMLInternalConfig g_config; @@ -73,6 +75,10 @@ bool SAMLInternalConfig::init() XMLToolingConfig::getConfig().init(); log.debug("XMLTooling library initialized"); + REGISTER_EXCEPTION_FACTORY(ArtifactException,opensaml); + REGISTER_EXCEPTION_FACTORY(MetadataFilterException,opensaml::saml2md); + + registerSAMLArtifacts(); saml1::registerAssertionClasses(); saml1p::registerProtocolClasses(); saml2::registerAssertionClasses(); @@ -96,6 +102,7 @@ void SAMLInternalConfig::term() saml2::AssertionSchemaValidators.destroyValidators(); saml2md::MetadataSchemaValidators.destroyValidators(); + SAMLArtifactManager.deregisterFactories(); MetadataFilterManager.deregisterFactories(); MetadataProviderManager.deregisterFactories(); @@ -135,3 +142,31 @@ XMLCh* SAMLInternalConfig::generateIdentifier() hexform[33]=0; return XMLString::transcode(hexform); } + +string SAMLInternalConfig::hashSHA1(const char* s, bool toHex) +{ + static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + auto_ptr hasher(XSECPlatformUtils::g_cryptoProvider->hashSHA1()); + if (hasher.get()) { + auto_ptr dup(strdup(s)); + unsigned char buf[21]; + hasher->hash(reinterpret_cast(dup.get()),strlen(dup.get())); + if (hasher->finish(buf,20)==20) { + string ret; + if (toHex) { + for (unsigned int i=0; i<20; i++) { + ret+=(DIGITS[((unsigned char)(0xF0 & buf[i])) >> 4 ]); + ret+=(DIGITS[0x0F & buf[i]]); + } + } + else { + for (unsigned int i=0; i<20; i++) { + ret+=buf[i]; + } + } + return ret; + } + } + throw XMLSecurityException("Unable to generate SHA-1 hash."); +} diff --git a/saml/SAMLConfig.h b/saml/SAMLConfig.h index dca8f15..0c2f7be 100644 --- a/saml/SAMLConfig.h +++ b/saml/SAMLConfig.h @@ -26,7 +26,6 @@ #include #include -#include #include #include @@ -37,6 +36,8 @@ */ namespace opensaml { + class SAML_API SAMLArtifact; + namespace saml2md { class SAML_API MetadataProvider; class SAML_API MetadataFilter; @@ -106,6 +107,16 @@ namespace opensaml { virtual XMLCh* generateIdentifier()=0; /** + * Generate the SHA-1 hash of a string + * + * @param s NULL-terminated string to hash + * @param toHex true iff the result should be encoded in hexadecimal form or left as raw bytes + * + * @return SHA-1 hash of the data + */ + virtual std::string hashSHA1(const char* s, bool toHex=false)=0; + + /** * Manages factories for MetadataProvider plugins. */ xmltooling::PluginManager MetadataProviderManager; @@ -115,6 +126,11 @@ namespace opensaml { */ xmltooling::PluginManager MetadataFilterManager; + /** + * Manages factories for SAMLArtifact plugins. + */ + xmltooling::PluginManager SAMLArtifactManager; + protected: SAMLConfig() {} }; diff --git a/saml/internal.h b/saml/internal.h index 0877395..675a5e7 100644 --- a/saml/internal.h +++ b/saml/internal.h @@ -95,6 +95,7 @@ namespace opensaml { void generateRandomBytes(void* buf, unsigned int len); void generateRandomBytes(std::string& buf, unsigned int len); XMLCh* generateIdentifier(); + std::string hashSHA1(const char* data, bool toHex=false); private: }; /// @endcond diff --git a/saml/saml.vcproj b/saml/saml.vcproj index 0a61744..80c81c0 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -182,6 +182,10 @@ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + @@ -218,6 +222,22 @@ RelativePath=".\saml1\core\impl\ProtocolsSchemaValidators.cpp" > + + + + + + + + @@ -320,6 +340,10 @@ > + + @@ -349,6 +373,18 @@ RelativePath=".\saml1\core\Protocols.h" > + + + + + + + +namespace opensaml { + namespace saml1p { + + /** + * Type 0x0001 SAML 1.x artifact class + */ + class SAML_API SAMLArtifactType0001 : public SAMLArtifact + { + SAMLArtifactType0001& operator=(const SAMLArtifactType0001& src); + public: + /** + * Decodes a base64-encoded type 0x0001 artifact + * + * @param s NULL-terminated base64-encoded string + */ + SAMLArtifactType0001(const char* s); + + /** + * Constructs an artifact with the specified source ID, but a random assertion handle. + * + * @param sourceid SOURCEID_LENGTH bytes of binary data + */ + SAMLArtifactType0001(const std::string& sourceid); + + /** + * Constructs an artifact with the specified source ID and assertion handle. + * + * @param sourceid SOURCEID_LENGTH bytes of binary data + * @param handle HANDLE_LENGTH bytes of binary data + */ + SAMLArtifactType0001(const std::string& sourceid, const std::string& handle); + + virtual ~SAMLArtifactType0001() {} + + virtual SAMLArtifactType0001* clone() const { + return new SAMLArtifactType0001(*this); + } + + virtual std::string getSource() const { + return m_raw.substr(TYPECODE_LENGTH,SOURCEID_LENGTH); // bytes 3-22 + } + + virtual std::string getMessageHandle() const { + return m_raw.substr(TYPECODE_LENGTH+SOURCEID_LENGTH, HANDLE_LENGTH); // bytes 23-42 + } + + /** Length of source ID */ + static const unsigned int SOURCEID_LENGTH; + + /** Length of assertion handle */ + static const unsigned int HANDLE_LENGTH; + + protected: + SAMLArtifactType0001(const SAMLArtifact& src) : SAMLArtifact(src) {} + }; + + }; +}; + +#endif /* __saml_artifacttype0001_h__ */ diff --git a/saml/saml1/core/SAMLArtifactType0002.h b/saml/saml1/core/SAMLArtifactType0002.h new file mode 100644 index 0000000..ffcbd78 --- /dev/null +++ b/saml/saml1/core/SAMLArtifactType0002.h @@ -0,0 +1,84 @@ +/* + * 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 saml/saml1/core/SAMLArtifactType0002.h + * + * Type 0x0002 SAML 1.x artifact class + */ + +#ifndef __saml_artifacttype0002_h__ +#define __saml_artifacttype0002_h__ + +#include + +namespace opensaml { + namespace saml1p { + + /** + * Type 0x0002 SAML 1.x artifact class + */ + class SAML_API SAMLArtifactType0002 : public SAMLArtifact + { + SAMLArtifactType0002& operator=(const SAMLArtifactType0002& src); + public: + /** + * Decodes a base64-encoded type 0x0002 artifact + * + * @param s NULL-terminated base64-encoded string + */ + SAMLArtifactType0002(const char* s); + + /** + * Constructs an artifact with the specified source URL, but a random assertion handle. + * + * @param sourceLocation source URL + */ + SAMLArtifactType0002(const std::string& sourceLocation); + + /** + * Constructs an artifact with the specified source URL and assertion handle. + * + * @param sourceLocation source URL + * @param handle HANDLE_LENGTH bytes of binary data + */ + SAMLArtifactType0002(const std::string& sourceLocation, const std::string& handle); + + virtual ~SAMLArtifactType0002() {} + + virtual SAMLArtifactType0002* clone() const { + return new SAMLArtifactType0002(*this); + } + + virtual std::string getMessageHandle() const { + return m_raw.substr(TYPECODE_LENGTH, HANDLE_LENGTH); // bytes 3-22 + } + + virtual std::string getSource() const { + return m_raw.c_str() + TYPECODE_LENGTH + HANDLE_LENGTH; // bytes 23-terminating null + } + + /** Length of assertion handle */ + static const unsigned int HANDLE_LENGTH; + + protected: + SAMLArtifactType0002(const SAMLArtifact& src) : SAMLArtifact(src) {} + }; + + }; +}; + +#endif /* __saml_artifacttype0002_h__ */ diff --git a/saml/saml1/core/impl/SAMLArtifactType0001.cpp b/saml/saml1/core/impl/SAMLArtifactType0001.cpp new file mode 100644 index 0000000..393d7d8 --- /dev/null +++ b/saml/saml1/core/impl/SAMLArtifactType0001.cpp @@ -0,0 +1,77 @@ +/* + * 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. + */ + +/** + * SAMLArtifactType0001.cpp + * + * Type 0x0001 SAML 1.x artifact class + */ + +#include "internal.h" +#include "saml1/core/SAMLArtifactType0001.h" + +using namespace opensaml::saml1p; +using namespace opensaml; +using namespace xmltooling; +using namespace std; + +namespace opensaml { + namespace saml1p { + SAMLArtifact* SAML_DLLLOCAL SAMLArtifactType0001Factory(const char* const & s) + { + return new SAMLArtifactType0001(s); + } + } +}; + +const unsigned int SAMLArtifactType0001::SOURCEID_LENGTH = 20; +const unsigned int SAMLArtifactType0001::HANDLE_LENGTH = 20; + +SAMLArtifactType0001::SAMLArtifactType0001(const char* s) : SAMLArtifact(s) +{ + // The base class does the work, we just do the checking. + if (m_raw.size() != TYPECODE_LENGTH + SOURCEID_LENGTH + HANDLE_LENGTH) + throw ArtifactException("Type 0x0001 artifact is of incorrect length."); + else if (m_raw[0] != 0x0 || m_raw[1] != 0x1) + throw ArtifactException( + string("Type 0x0001 artifact given an artifact of invalid type (") + toHex(getTypeCode()) + ")." + ); +} + +SAMLArtifactType0001::SAMLArtifactType0001(const string& sourceid) +{ + if (sourceid.size()!=SOURCEID_LENGTH) + throw ArtifactException("Type 0x0001 artifact sourceid of incorrect length."); + m_raw+=(char)0x0; + m_raw+=(char)0x1; + m_raw.append(sourceid,0,SOURCEID_LENGTH); + char buf[HANDLE_LENGTH]; + SAMLConfig::getConfig().generateRandomBytes(buf,HANDLE_LENGTH); + for (int i=0; i