Added uni/multicast encrypting methods.
Moved decryption method to base class.
saml1/binding/impl/SAML1MessageRule.cpp \
saml1/profile/AssertionValidator.cpp \
saml1/profile/BrowserSSOProfileValidator.cpp \
+ saml2/core/impl/Assertions.cpp \
saml2/core/impl/Assertions20Impl.cpp \
saml2/core/impl/Assertions20SchemaValidators.cpp \
saml2/core/impl/Protocols20Impl.cpp \
virtual ~MessageEncoder() {}
/**
+ * Indicates whether the encoding format requires that messages be as compact as possible.
+ *
+ * @return true iff the encoding has size constraints
+ */
+ virtual bool isCompact() const {
+ return false;
+ }
+
+ /**
* Interface to caller-supplied artifact generation mechanism.
*
* Generating an artifact for storage and retrieval requires knowledge of
Name="impl"\r
>\r
<File\r
+ RelativePath=".\saml2\core\impl\Assertions.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\saml2\core\impl\Assertions20Impl.cpp"\r
>\r
</File>\r
public:
SAML2RedirectEncoder(const DOMElement* e) {}
virtual ~SAML2RedirectEncoder() {}
+
+ bool isCompact() const {
+ return true;
+ }
long encode(
GenericResponse& genericResponse,
namespace opensaml {
+ namespace saml2md {
+ class SAML_API MetadataProvider;
+ class SAML_API MetadataCredentialCriteria;
+ };
+
/**
* @namespace opensaml::saml2
* SAML 2.0 assertion namespace
// Forward references
class SAML_API Assertion;
class SAML_API EncryptedAssertion;
+
+ /**
+ * Marker interface for SAML types that can be encrypted.
+ */
+ class SAML_API EncryptableObject : public virtual xmltooling::XMLObject
+ {
+ protected:
+ EncryptableObject() {}
+ virtual ~EncryptableObject() {}
+ };
DECL_XMLOBJECT_SIMPLE(SAML_API,AssertionIDRef,AssertionID,SAML 2.0 AssertionIDRef element);
DECL_XMLOBJECT_SIMPLE(SAML_API,AssertionURIRef,AssertionURI,SAML 2.0 AssertionURIRef element);
static const XMLCh TYPE_NAME[];
/**
+ * Encrypts an object to a single recipient using this object as a container.
+ *
+ * @param xmlObject object to encrypt
+ * @param metadataProvider a locked MetadataProvider to supply encryption keys
+ * @param criteria metadata-based CredentialCriteria to use
+ * @param compact true iff compact KeyInfo should be used
+ * @param algorithm optionally specifies data encryption algorithm if none can be determined from metadata
+ * @return the encrypted object
+ */
+ virtual void encrypt(
+ const EncryptableObject& xmlObject,
+ const saml2md::MetadataProvider& metadataProvider,
+ saml2md::MetadataCredentialCriteria& criteria,
+ bool compact=false,
+ const XMLCh* algorithm=NULL
+ );
+
+ /**
+ * Encrypts an object to multiple recipients using this object as a container.
+ *
+ * @param recipients pairs containing a locked MetadataProvider to supply encryption keys,
+ * and a metadata-based CredentialCriteria to use
+ * @param compact true iff compact KeyInfo should be used
+ * @param algorithm optionally specifies data encryption algorithm if none can be determined from metadata
+ * @return the encrypted object
+ */
+ virtual void encrypt(
+ const EncryptableObject& xmlObject,
+ const std::vector< std::pair<const saml2md::MetadataProvider*, saml2md::MetadataCredentialCriteria*> >& recipients,
+ bool compact=false,
+ const XMLCh* algorithm=NULL
+ );
+
+ /**
* Decrypts the element using the supplied CredentialResolver.
*
* <p>The object returned will be unmarshalled around the decrypted DOM element in a
*/
virtual xmltooling::XMLObject* decrypt(
const xmltooling::CredentialResolver& credResolver, const XMLCh* recipient, xmltooling::CredentialCriteria* criteria=NULL
- ) const=0;
+ ) const;
END_XMLOBJECT;
BEGIN_XMLOBJECT(SAML_API,EncryptedID,EncryptedElementType,SAML 2.0 EncryptedID element);
END_XMLOBJECT;
- BEGIN_XMLOBJECT(SAML_API,BaseID,xmltooling::XMLObject,SAML 2.0 BaseID abstract element);
+ BEGIN_XMLOBJECT(SAML_API,BaseID,EncryptableObject,SAML 2.0 BaseID abstract element);
DECL_STRING_ATTRIB(NameQualifier,NAMEQUALIFIER);
DECL_STRING_ATTRIB(SPNameQualifier,SPNAMEQUALIFIER);
END_XMLOBJECT;
static const XMLCh TRANSIENT[];
END_XMLOBJECT;
- BEGIN_XMLOBJECT(SAML_API,NameID,NameIDType,SAML 2.0 NameID element);
+ BEGIN_XMLOBJECT2(SAML_API,NameID,NameIDType,EncryptableObject,SAML 2.0 NameID element);
END_XMLOBJECT;
BEGIN_XMLOBJECT(SAML_API,Issuer,NameIDType,SAML 2.0 Issuer element);
BEGIN_XMLOBJECT(SAML_API,AttributeValue,xmltooling::ElementProxy,SAML 2.0 AttributeValue element);
END_XMLOBJECT;
- BEGIN_XMLOBJECT(SAML_API,Attribute,xmltooling::AttributeExtensibleXMLObject,SAML 2.0 Attribute element);
+ BEGIN_XMLOBJECT2(SAML_API,Attribute,xmltooling::AttributeExtensibleXMLObject,EncryptableObject,SAML 2.0 Attribute element);
DECL_STRING_ATTRIB(Name,NAME);
DECL_STRING_ATTRIB(NameFormat,NAMEFORMAT);
DECL_STRING_ATTRIB(FriendlyName,FRIENDLYNAME);
virtual Issuer* getIssuer() const=0;
};
- BEGIN_XMLOBJECT2(SAML_API,Assertion,saml2::RootObject,opensaml::Assertion,SAML 2.0 Assertion element);
+ BEGIN_XMLOBJECT3(SAML_API,Assertion,saml2::RootObject,opensaml::Assertion,EncryptableObject,SAML 2.0 Assertion element);
DECL_INHERITED_STRING_ATTRIB(Version,VER);
DECL_INHERITED_STRING_ATTRIB(ID,ID);
DECL_INHERITED_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
throw xmltooling::XMLObjectException("Unable to obtain typed builder for KeyInfoConfirmationDataType.");
}
};
-
+
/**
* Registers builders and validators for SAML 2.0 Assertion classes into the runtime.
*/
--- /dev/null
+/*
+ * Copyright 2001-2007 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.
+ */
+
+/**
+ * Assertions.cpp
+ *
+ * Built-in behavior for SAML 2.0 Assertion interfaces.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "saml/encryption/EncryptedKeyResolver.h"
+#include "saml2/core/Assertions.h"
+#include "saml2/metadata/Metadata.h"
+#include "saml2/metadata/MetadataProvider.h"
+#include "saml2/metadata/MetadataCredentialContext.h"
+#include "saml2/metadata/MetadataCredentialCriteria.h"
+
+#include <log4cpp/Category.hh>
+#include <xmltooling/encryption/Encrypter.h>
+#include <xmltooling/encryption/Decrypter.h>
+
+using namespace opensaml::saml2md;
+using namespace opensaml::saml2;
+using namespace xmlencryption;
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace std;
+
+void EncryptedElementType::encrypt(
+ const EncryptableObject& xmlObject,
+ const MetadataProvider& metadataProvider,
+ MetadataCredentialCriteria& criteria,
+ bool compact,
+ const XMLCh* algorithm
+ )
+{
+ // With one recipient, we let the library generate the encryption key for us.
+ // Get the key encryption key to use.
+ criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
+ const Credential* KEK = metadataProvider.resolve(&criteria);
+ if (!KEK)
+ throw EncryptionException("No key encryption credential found.");
+
+ // Try and find EncryptionMethod information surrounding the credential.
+ const MetadataCredentialContext* metaCtx = dynamic_cast<const MetadataCredentialContext*>(KEK->getCredentalContext());
+ if (metaCtx) {
+ const vector<EncryptionMethod*> encMethods = metaCtx->getKeyDescriptor().getEncryptionMethods();
+ if (!encMethods.empty())
+ algorithm = encMethods.front()->getAlgorithm();
+ }
+
+ if (!algorithm || !*algorithm)
+ algorithm = DSIGConstants::s_unicodeStrURIAES256_CBC;
+
+ Encrypter encrypter;
+ Encrypter::EncryptionParams ep(algorithm, NULL, 0, NULL, compact);
+ Encrypter::KeyEncryptionParams kep(*KEK);
+ setEncryptedData(encrypter.encryptElement(xmlObject.getDOM(),ep,&kep));
+}
+
+void EncryptedElementType::encrypt(
+ const EncryptableObject& xmlObject,
+ const vector< pair<const MetadataProvider*, MetadataCredentialCriteria*> >& recipients,
+ bool compact,
+ const XMLCh* algorithm
+ )
+{
+ if (recipients.size()==1)
+ return encrypt(xmlObject, *recipients.front().first, *recipients.front().second, compact, algorithm);
+
+ // With multiple recipients, we have to generate an encryption key and then multicast it,
+ // so we need to split the encryption and key wrapping steps.
+ if (!algorithm || !*algorithm)
+ algorithm = DSIGConstants::s_unicodeStrURIAES256_CBC;
+
+ // Generate a random key.
+ unsigned char keyBuffer[32];
+ if (XSECPlatformUtils::g_cryptoProvider->getRandom(keyBuffer,32)<32)
+ throw EncryptionException("Unable to generate encryption key; was PRNG seeded?");
+ Encrypter encrypter;
+ Encrypter::EncryptionParams ep(algorithm, keyBuffer, 32, NULL, compact);
+ setEncryptedData(encrypter.encryptElement(xmlObject.getDOM(),ep));
+ getEncryptedData()->setId(SAMLConfig::getConfig().generateIdentifier());
+
+ // Generate a uniquely named KeyInfo.
+ KeyInfo* keyInfo = KeyInfoBuilder::buildKeyInfo();
+ getEncryptedData()->setKeyInfo(keyInfo);
+ KeyName* carriedName = KeyNameBuilder::buildKeyName();
+ keyInfo->getKeyNames().push_back(carriedName);
+ carriedName->setName(SAMLConfig::getConfig().generateIdentifier());
+
+ VectorOf(EncryptedKey) keys = getEncryptedKeys();
+
+ // Now we encrypt the key for each recipient.
+ for (vector< pair<const MetadataProvider*, MetadataCredentialCriteria*> >::const_iterator r = recipients.begin(); r!=recipients.end(); ++r) {
+ // Get key encryption key to use.
+ r->second->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
+ const Credential* KEK = r->first->resolve(r->second);
+ if (!KEK) {
+ auto_ptr_char name(dynamic_cast<const EntityDescriptor*>(r->second->getRole().getParent())->getEntityID());
+ log4cpp::Category::getInstance(SAML_LOGCAT".Encryption").warn("No key encryption credential found for (%s).", name.get());
+ continue;
+ }
+
+ // Encrypt the key and add it to the message.
+ Encrypter::KeyEncryptionParams kep(
+ *KEK, Encrypter::getKeyTransportAlgorithm(*KEK, algorithm),
+ dynamic_cast<const EntityDescriptor*>(r->second->getRole().getParent())->getEntityID()
+ );
+ EncryptedKey* encryptedKey = encrypter.encryptKey(keyBuffer, ep.m_keyBufferSize, kep, compact);
+ keys.push_back(encryptedKey);
+ if (keys.size()>1) {
+ // Copy details from the other key.
+ encryptedKey->setCarriedKeyName(keys.front()->getCarriedKeyName()->cloneCarriedKeyName());
+ encryptedKey->setReferenceList(keys.front()->getReferenceList()->cloneReferenceList());
+ }
+ else {
+ // Attach the carried key name.
+ CarriedKeyName* carried = CarriedKeyNameBuilder::buildCarriedKeyName();
+ carried->setName(carriedName->getName());
+ encryptedKey->setCarriedKeyName(carried);
+
+ // Attach a back-reference to the data.
+ ReferenceList* reflist = ReferenceListBuilder::buildReferenceList();
+ encryptedKey->setReferenceList(reflist);
+ DataReference* dataref = DataReferenceBuilder::buildDataReference();
+ reflist->getDataReferences().push_back(dataref);
+ XMLCh* uri = new XMLCh[XMLString::stringLen(getEncryptedData()->getId()) + 2];
+ *uri = chPound;
+ *(uri+1) = chNull;
+ XMLString::catString(uri, getEncryptedData()->getId());
+ dataref->setURI(uri);
+ delete[] uri;
+ }
+ }
+}
+
+XMLObject* EncryptedElementType::decrypt(const CredentialResolver& credResolver, const XMLCh* recipient, CredentialCriteria* criteria) const
+{
+ if (!getEncryptedData())
+ throw DecryptionException("No encrypted data present.");
+ EncryptedKeyResolver ekr(*this);
+ Decrypter decrypter(&credResolver, criteria, &ekr);
+ DOMDocumentFragment* frag = decrypter.decryptData(*getEncryptedData(), recipient);
+ if (frag->hasChildNodes() && frag->getFirstChild()==frag->getLastChild()) {
+ DOMNode* plaintext=frag->getFirstChild();
+ if (plaintext->getNodeType()==DOMNode::ELEMENT_NODE) {
+ // Import the tree into a new Document that we can bind to the unmarshalled object.
+ XercesJanitor<DOMDocument> newdoc(XMLToolingConfig::getConfig().getParser().newDocument());
+ DOMElement* treecopy = static_cast<DOMElement*>(newdoc->importNode(plaintext, true));
+ newdoc->appendChild(treecopy);
+ auto_ptr<XMLObject> ret(XMLObjectBuilder::buildOneFromElement(treecopy, true));
+ newdoc.release();
+ return ret.release();
+ }
+ }
+ frag->release();
+ throw DecryptionException("Decryption did not result in a single element.");
+}
#include <xmltooling/AbstractComplexElement.h>
#include <xmltooling/AbstractSimpleElement.h>
-#include <xmltooling/encryption/Decrypter.h>
#include <xmltooling/impl/AnyElement.h>
#include <xmltooling/io/AbstractXMLObjectMarshaller.h>
#include <xmltooling/io/AbstractXMLObjectUnmarshaller.h>
namespace opensaml {
namespace saml2 {
-
+
DECL_XMLOBJECTIMPL_SIMPLE(SAML_DLLLOCAL,AssertionIDRef);
DECL_XMLOBJECTIMPL_SIMPLE(SAML_DLLLOCAL,AssertionURIRef);
DECL_XMLOBJECTIMPL_SIMPLE(SAML_DLLLOCAL,Audience);
}
}
}
-
- XMLObject* decrypt(const CredentialResolver& credResolver, const XMLCh* recipient, CredentialCriteria* criteria) const
- {
- if (!m_EncryptedData)
- throw DecryptionException("No encrypted data present.");
- EncryptedKeyResolver ekr(*this);
- Decrypter decrypter(&credResolver, criteria, &ekr);
- DOMDocumentFragment* frag = decrypter.decryptData(*m_EncryptedData, recipient);
- if (frag->hasChildNodes() && frag->getFirstChild()==frag->getLastChild()) {
- DOMNode* plaintext=frag->getFirstChild();
- if (plaintext->getNodeType()==DOMNode::ELEMENT_NODE) {
- // Import the tree into a new Document that we can bind to the unmarshalled object.
- XercesJanitor<DOMDocument> newdoc(XMLToolingConfig::getConfig().getParser().newDocument());
- DOMElement* treecopy = static_cast<DOMElement*>(newdoc->importNode(plaintext, true));
- newdoc->appendChild(treecopy);
- auto_ptr<XMLObject> ret(XMLObjectBuilder::buildOneFromElement(treecopy, true));
- newdoc.release();
- return ret.release();
- }
- }
- frag->release();
- throw DecryptionException("Decryption did not result in a single element.");
- }
IMPL_XMLOBJECT_CLONE(EncryptedElementType);
IMPL_TYPED_FOREIGN_CHILD(EncryptedData,xmlencryption);
}
};
- //TODO unit test for this
class SAML_DLLLOCAL EncryptedIDImpl : public virtual EncryptedID, public EncryptedElementTypeImpl
{
public:
#include "internal.h"
#include "exceptions.h"
-#include "saml/encryption/EncryptedKeyResolver.h"
#include "saml2/core/Protocols.h"
#include <xmltooling/AbstractComplexElement.h>
#include <xmltooling/AbstractSimpleElement.h>
-#include <xmltooling/encryption/Decrypter.h>
#include <xmltooling/impl/AnyElement.h>
#include <xmltooling/io/AbstractXMLObjectMarshaller.h>
#include <xmltooling/io/AbstractXMLObjectUnmarshaller.h>
}
}
- XMLObject* decrypt(const CredentialResolver& credResolver, const XMLCh* recipient, CredentialCriteria* criteria) const
- {
- if (!m_EncryptedData)
- throw DecryptionException("No encrypted data present.");
- EncryptedKeyResolver ekr(*this);
- Decrypter decrypter(&credResolver, criteria, &ekr);
- DOMDocumentFragment* frag = decrypter.decryptData(*m_EncryptedData, recipient);
- if (frag->hasChildNodes() && frag->getFirstChild()==frag->getLastChild()) {
- DOMNode* plaintext=frag->getFirstChild();
- if (plaintext->getNodeType()==DOMNode::ELEMENT_NODE) {
- // Import the tree into a new Document that we can bind to the unmarshalled object.
- XercesJanitor<DOMDocument> newdoc(XMLToolingConfig::getConfig().getParser().newDocument());
- DOMElement* treecopy = static_cast<DOMElement*>(newdoc->importNode(plaintext, true));
- newdoc->appendChild(treecopy);
- auto_ptr<XMLObject> ret(XMLObjectBuilder::buildOneFromElement(treecopy, true));
- newdoc.release();
- return ret.release();
- }
- }
- frag->release();
- throw DecryptionException("Decryption did not result in a single element.");
- }
-
IMPL_XMLOBJECT_CLONE(NewEncryptedID);
EncryptedElementType* cloneEncryptedElementType() const {
return new NewEncryptedIDImpl(*this);