91a263203d90b5196b65966a5d01d6a553bfaf06
[shibboleth/cpp-opensaml.git] / saml / saml2 / profile / impl / BearerConfirmationRule.cpp
1 /*
2  *  Copyright 2009 Internet2
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /**
18  * BearerConfirmationRule.cpp
19  *
20  * SAML 2.0 Bearer SubjectConfirmation SecurityPolicyRule
21  */
22
23 #include "internal.h"
24 #include "exceptions.h"
25 #include "binding/SecurityPolicyRule.h"
26 #include "saml2/core/Assertions.h"
27 #include "saml2/profile/SAML2AssertionPolicy.h"
28
29 #include <xmltooling/logging.h>
30 #include <xmltooling/io/HTTPRequest.h>
31
32 using namespace opensaml::saml2;
33 using namespace xmltooling;
34 using namespace std;
35
36 namespace opensaml {
37     namespace saml2 {
38
39         class SAML_DLLLOCAL BearerConfirmationRule : public opensaml::SecurityPolicyRule
40         {
41         public:
42             BearerConfirmationRule(const DOMElement* e);
43
44             virtual ~BearerConfirmationRule() {
45             }
46             const char* getType() const {
47                 return BEARER_POLICY_RULE;
48             }
49             bool evaluate(const XMLObject& message, const GenericRequest* request, opensaml::SecurityPolicy& policy) const;
50         
51         private:
52             bool m_validity, m_recipient, m_correlation, m_fatal;
53         };
54
55         opensaml::SecurityPolicyRule* SAML_DLLLOCAL BearerConfirmationRuleFactory(const DOMElement* const & e)
56         {
57             return new BearerConfirmationRule(e);
58         }
59         
60         static const XMLCh checkValidity[] =    UNICODE_LITERAL_13(c,h,e,c,k,V,a,l,i,d,i,t,y);
61         static const XMLCh checkRecipient[] =   UNICODE_LITERAL_14(c,h,e,c,k,R,e,c,i,p,i,e,n,t);
62         static const XMLCh checkCorrelation[] = UNICODE_LITERAL_16(c,h,e,c,k,C,o,r,r,e,l,a,t,i,o,n);
63         static const XMLCh missingFatal[] =     UNICODE_LITERAL_12(m,i,s,s,i,n,g,F,a,t,a,l);
64     };
65 };
66
67 BearerConfirmationRule::BearerConfirmationRule(const DOMElement* e) : m_validity(true), m_recipient(true), m_correlation(true), m_fatal(true)
68 {
69     const XMLCh* flag = e ? e->getAttributeNS(NULL, checkValidity) : NULL;
70     m_validity = (!flag || (*flag != chLatin_f && *flag != chDigit_0));
71     flag = e ? e->getAttributeNS(NULL, checkRecipient) : NULL;
72     m_recipient = (!flag || (*flag != chLatin_f && *flag != chDigit_0));
73     flag = e ? e->getAttributeNS(NULL, checkCorrelation) : NULL;
74     m_correlation = (!flag || (*flag != chLatin_f && *flag != chDigit_0));
75     flag = e ? e->getAttributeNS(NULL, missingFatal) : NULL;
76     m_fatal = (!flag || (*flag != chLatin_f && *flag != chDigit_0));
77 }
78
79 bool BearerConfirmationRule::evaluate(const XMLObject& message, const GenericRequest* request, opensaml::SecurityPolicy& policy) const
80 {
81     const Assertion* a=dynamic_cast<const Assertion*>(&message);
82     if (!a)
83         return false;
84
85     logging::Category& log = logging::Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.BearerConfirmation");
86
87     const char* msg="assertion is missing bearer SubjectConfirmation";
88     const Subject* subject = a->getSubject();
89     if (subject) {
90         const vector<SubjectConfirmation*>& confs = subject->getSubjectConfirmations();
91         for (vector<SubjectConfirmation*>::const_iterator sc = confs.begin(); sc!=confs.end(); ++sc) {
92             if (XMLString::equals((*sc)->getMethod(), SubjectConfirmation::BEARER)) {
93
94                 const SubjectConfirmationDataType* data = dynamic_cast<const SubjectConfirmationDataType*>((*sc)->getSubjectConfirmationData());
95
96                 if (m_recipient) {
97                     const HTTPRequest* httpRequest = dynamic_cast<const HTTPRequest*>(request);
98                     if (httpRequest && httpRequest->getRequestURL()) {
99                         string dest = httpRequest->getRequestURL();
100                         auto_ptr_XMLCh destination(dest.substr(0,dest.find('?')).c_str());
101                         if (!XMLString::equals(destination.get(), data ? data->getRecipient() : NULL)) {
102                             msg = "bearer confirmation failed with recipient mismatch";
103                             continue;
104                         }
105                     }
106                 }
107
108                 if (m_correlation && policy.getCorrelationID() && *(policy.getCorrelationID())) {
109                     if (!XMLString::equals(policy.getCorrelationID(), data ? data->getInResponseTo() : NULL)) {
110                         msg = "bearer confirmation failed with request correlation mismatch";
111                         continue;
112                     }
113                 }
114
115                 if (m_validity) {
116                     if (!data || !data->getNotOnOrAfter()) {
117                         msg = "bearer SubjectConfirmationData missing NotOnOrAfter attribute";
118                         continue;
119                     }
120                     else if (data->getNotOnOrAfterEpoch() <= policy.getTime() - XMLToolingConfig::getConfig().clock_skew_secs) {
121                         msg = "bearer confirmation has expired";
122                         continue;
123                     }
124
125                     if (data && data->getNotBefore() && policy.getTime() + XMLToolingConfig::getConfig().clock_skew_secs < data->getNotBeforeEpoch()) {
126                         msg = "bearer confirmation not yet valid";
127                         continue;
128                     }
129                 }
130
131                 SAML2AssertionPolicy* saml2policy = dynamic_cast<SAML2AssertionPolicy*>(&policy);
132                 if (saml2policy)
133                     saml2policy->setSubjectConfirmation(*sc);
134                 log.debug("assertion satisfied bearer confirmation requirements");
135                 return true;
136             }
137         }
138     }
139
140     log.error(msg ? msg : "no error message");
141     if (m_fatal)
142         throw SecurityPolicyException("Unable to locate satisfiable bearer SubjectConfirmation in assertion.");
143     return false;
144 }