2 * Copyright 2001-2006 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * SAML1POSTEncoder.cpp
20 * SAML 1.x Artifact binding/profile message encoder
24 #include "exceptions.h"
25 #include "saml1/binding/SAML1POSTEncoder.h"
26 #include "saml1/core/Protocols.h"
28 #include <log4cpp/Category.hh>
29 #include <xercesc/util/Base64.hpp>
30 #include <xmltooling/util/NDC.h>
32 using namespace opensaml::saml1p;
33 using namespace opensaml;
34 using namespace xmlsignature;
35 using namespace xmltooling;
36 using namespace log4cpp;
41 MessageEncoder* SAML_DLLLOCAL SAML1POSTEncoderFactory(const DOMElement* const & e)
43 return new SAML1POSTEncoder(e);
46 class SAML_DLLLOCAL _addcert : public binary_function<X509Data*,XSECCryptoX509*,void> {
48 void operator()(X509Data* bag, XSECCryptoX509* cert) const {
49 safeBuffer& buf=cert->getDEREncodingSB();
50 X509Certificate* x=X509CertificateBuilder::buildX509Certificate();
51 x->setValue(buf.sbStrToXMLCh());
52 bag->getX509Certificates().push_back(x);
58 SAML1POSTEncoder::SAML1POSTEncoder(const DOMElement* e) {}
60 SAML1POSTEncoder::~SAML1POSTEncoder() {}
62 void SAML1POSTEncoder::encode(
63 map<string,string>& outputFields,
65 const char* recipientID,
66 const char* relayState,
67 const CredentialResolver* credResolver,
68 const XMLCh* sigAlgorithm
72 xmltooling::NDC ndc("encode");
74 Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML1POST");
75 log.debug("validating input");
78 if (xmlObject->getParent())
79 throw BindingException("Cannot encode XML content with parent.");
80 Response* response = dynamic_cast<Response*>(xmlObject);
82 throw BindingException("XML content for SAML 1.x POST Encoder must be a SAML 1.x <Response>.");
84 throw BindingException("SAML 1.x POST Encoder requires relay state (TARGET) value.");
86 DOMElement* rootElement = NULL;
88 // Signature based on native XML signing.
89 if (response->getSignature()) {
90 log.debug("response already signed, skipping signature operation");
93 log.debug("signing and marshalling the response");
95 // Append a Signature.
96 response->setSignature(SignatureBuilder::buildSignature());
97 response->getSignature()->setSigningKey(credResolver->getKey());
100 const vector<XSECCryptoX509*>& certs = credResolver->getCertificates();
101 if (!certs.empty()) {
102 KeyInfo* keyInfo=KeyInfoBuilder::buildKeyInfo();
103 X509Data* x509Data=X509DataBuilder::buildX509Data();
104 keyInfo->getX509Datas().push_back(x509Data);
105 for_each(certs.begin(),certs.end(),bind1st(_addcert(),x509Data));
106 response->getSignature()->setKeyInfo(keyInfo);
109 // Sign response while marshalling.
110 vector<Signature*> sigs(1,response->getSignature());
111 rootElement = response->marshall((DOMDocument*)NULL,&sigs);
115 log.debug("marshalling the response");
116 rootElement = response->marshall();
120 XMLHelper::serialize(rootElement, xmlbuf);
122 XMLByte* out=Base64::encode(reinterpret_cast<const XMLByte*>(xmlbuf.data()),xmlbuf.size(),&len);
125 xmlbuf.append(reinterpret_cast<char*>(out),len);
126 XMLString::release(&out);
129 throw BindingException("Base64 encoding of XML failed.");
132 // Pass back output fields.
133 outputFields["SAMLResponse"] = xmlbuf;
134 outputFields["TARGET"] = relayState;
136 // Cleanup by destroying XML.
139 log.debug("message encoded");