164913047b287015c4e865c870768130f67760f0
[shibboleth/cpp-opensaml.git] / saml / saml2 / profile / impl / BearerConfirmationRule.cpp
1 /**
2  * Licensed to the University Corporation for Advanced Internet
3  * Development, Inc. (UCAID) under one or more contributor license
4  * agreements. See the NOTICE file distributed with this work for
5  * additional information regarding copyright ownership.
6  *
7  * UCAID licenses this file to you under the Apache License,
8  * Version 2.0 (the "License"); you may not use this file except
9  * in compliance with the License. You may obtain a copy of the
10  * License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17  * either express or implied. See the License for the specific
18  * language governing permissions and limitations under the License.
19  */
20
21 /**
22  * BearerConfirmationRule.cpp
23  *
24  * SAML 2.0 Bearer SubjectConfirmation SecurityPolicyRule.
25  */
26
27 #include "internal.h"
28 #include "exceptions.h"
29 #include "binding/SecurityPolicyRule.h"
30 #include "saml2/core/Assertions.h"
31 #include "saml2/profile/SAML2AssertionPolicy.h"
32
33 #include <xercesc/util/XMLUniDefs.hpp>
34 #include <xmltooling/logging.h>
35 #include <xmltooling/XMLToolingConfig.h>
36 #include <xmltooling/io/HTTPRequest.h>
37
38 using namespace opensaml::saml2;
39 using namespace xmltooling;
40 using namespace std;
41
42 namespace opensaml {
43     namespace saml2 {
44
45         class SAML_DLLLOCAL BearerConfirmationRule : public opensaml::SecurityPolicyRule
46         {
47         public:
48             BearerConfirmationRule(const DOMElement* e);
49
50             virtual ~BearerConfirmationRule() {
51             }
52             const char* getType() const {
53                 return BEARER_POLICY_RULE;
54             }
55             bool evaluate(const XMLObject& message, const GenericRequest* request, opensaml::SecurityPolicy& policy) const;
56         
57         private:
58             bool m_validity, m_recipient, m_correlation, m_fatal;
59         };
60
61         opensaml::SecurityPolicyRule* SAML_DLLLOCAL BearerConfirmationRuleFactory(const DOMElement* const & e)
62         {
63             return new BearerConfirmationRule(e);
64         }
65         
66         static const XMLCh checkValidity[] =    UNICODE_LITERAL_13(c,h,e,c,k,V,a,l,i,d,i,t,y);
67         static const XMLCh checkRecipient[] =   UNICODE_LITERAL_14(c,h,e,c,k,R,e,c,i,p,i,e,n,t);
68         static const XMLCh checkCorrelation[] = UNICODE_LITERAL_16(c,h,e,c,k,C,o,r,r,e,l,a,t,i,o,n);
69         static const XMLCh missingFatal[] =     UNICODE_LITERAL_12(m,i,s,s,i,n,g,F,a,t,a,l);
70     };
71 };
72
73 BearerConfirmationRule::BearerConfirmationRule(const DOMElement* e)
74     : m_validity(XMLHelper::getAttrBool(e, true, checkValidity)),
75         m_recipient(XMLHelper::getAttrBool(e, true, checkRecipient)),
76         m_correlation(XMLHelper::getAttrBool(e, true, checkCorrelation)),
77         m_fatal(XMLHelper::getAttrBool(e, true, missingFatal))
78 {
79 }
80
81 bool BearerConfirmationRule::evaluate(const XMLObject& message, const GenericRequest* request, opensaml::SecurityPolicy& policy) const
82 {
83     const Assertion* a=dynamic_cast<const Assertion*>(&message);
84     if (!a)
85         return false;
86
87     logging::Category& log = logging::Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.BearerConfirmation");
88
89     const char* msg="assertion is missing bearer SubjectConfirmation";
90     const Subject* subject = a->getSubject();
91     if (subject) {
92         const vector<SubjectConfirmation*>& confs = subject->getSubjectConfirmations();
93         for (vector<SubjectConfirmation*>::const_iterator sc = confs.begin(); sc!=confs.end(); ++sc) {
94             if (XMLString::equals((*sc)->getMethod(), SubjectConfirmation::BEARER)) {
95
96                 const SubjectConfirmationDataType* data = dynamic_cast<const SubjectConfirmationDataType*>((*sc)->getSubjectConfirmationData());
97
98                 if (m_recipient) {
99                     const HTTPRequest* httpRequest = dynamic_cast<const HTTPRequest*>(request);
100                     if (httpRequest && httpRequest->getRequestURL()) {
101                         string dest = httpRequest->getRequestURL();
102                         auto_ptr_XMLCh destination(dest.substr(0,dest.find('?')).c_str());
103                         if (!XMLString::equals(destination.get(), data ? data->getRecipient() : nullptr)) {
104                             msg = "bearer confirmation failed with recipient mismatch";
105                             continue;
106                         }
107                     }
108                 }
109
110                 if (m_correlation && policy.getCorrelationID() && *(policy.getCorrelationID())) {
111                     if (!XMLString::equals(policy.getCorrelationID(), data ? data->getInResponseTo() : nullptr)) {
112                         msg = "bearer confirmation failed with request correlation mismatch";
113                         continue;
114                     }
115                 }
116
117                 if (m_validity) {
118                     if (!data || !data->getNotOnOrAfter()) {
119                         msg = "bearer SubjectConfirmationData missing NotOnOrAfter attribute";
120                         continue;
121                     }
122                     else if (data->getNotOnOrAfterEpoch() <= policy.getTime() - XMLToolingConfig::getConfig().clock_skew_secs) {
123                         msg = "bearer confirmation has expired";
124                         continue;
125                     }
126
127                     if (data && data->getNotBefore() && policy.getTime() + XMLToolingConfig::getConfig().clock_skew_secs < data->getNotBeforeEpoch()) {
128                         msg = "bearer confirmation not yet valid";
129                         continue;
130                     }
131                 }
132
133                 SAML2AssertionPolicy* saml2policy = dynamic_cast<SAML2AssertionPolicy*>(&policy);
134                 if (saml2policy)
135                     saml2policy->setSubjectConfirmation(*sc);
136                 log.debug("assertion satisfied bearer confirmation requirements");
137                 return true;
138             }
139         }
140     }
141
142     log.error(msg ? msg : "no error message");
143     if (m_fatal)
144         throw SecurityPolicyException("Unable to locate satisfiable bearer SubjectConfirmation in assertion.");
145     return false;
146 }