From: cantor Date: Sat, 29 Dec 2007 22:22:17 +0000 (+0000) Subject: Add regex support to acl plugin. X-Git-Tag: 2.4~601 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fsp.git;a=commitdiff_plain;h=0c8b6e8fa4a2ca0298ceb49f1d36a0d5dc9aca86 Add regex support to acl plugin. git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@2683 cb58f699-b61c-0410-a6fe-9272a202ed29 --- diff --git a/schemas/shibboleth-2.0-native-sp-config.xsd b/schemas/shibboleth-2.0-native-sp-config.xsd index fb2d538..54bdd2b 100644 --- a/schemas/shibboleth-2.0-native-sp-config.xsd +++ b/schemas/shibboleth-2.0-native-sp-config.xsd @@ -243,6 +243,7 @@ + @@ -251,6 +252,7 @@ + @@ -258,10 +260,21 @@ + + + + + + + + + + + diff --git a/shibsp/impl/XMLAccessControl.cpp b/shibsp/impl/XMLAccessControl.cpp index 331a434..939ea68 100644 --- a/shibsp/impl/XMLAccessControl.cpp +++ b/shibsp/impl/XMLAccessControl.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #ifndef HAVE_STRCASECMP # define strcasecmp _stricmp @@ -57,6 +58,25 @@ namespace { vector m_vals; }; + class RuleRegex : public AccessControl + { + public: + RuleRegex(const DOMElement* e); + ~RuleRegex() { + delete m_re; + } + + Lockable* lock() {return this;} + void unlock() {} + + aclresult_t authorized(const SPRequest& request, const Session* session) const; + + private: + string m_alias; + auto_arrayptr m_exp; + RegularExpression* m_re; + }; + class Operator : public AccessControl { public: @@ -108,12 +128,16 @@ namespace { return new XMLAccessControl(e); } - static const XMLCh _AccessControl[] = UNICODE_LITERAL_13(A,c,c,e,s,s,C,o,n,t,r,o,l); + static const XMLCh _AccessControl[] = UNICODE_LITERAL_13(A,c,c,e,s,s,C,o,n,t,r,o,l); + static const XMLCh ignoreCase[] = UNICODE_LITERAL_10(i,g,n,o,r,e,C,a,s,e); + static const XMLCh ignoreOption[] = UNICODE_LITERAL_1(i); + static const XMLCh _list[] = UNICODE_LITERAL_4(l,i,s,t); static const XMLCh require[] = UNICODE_LITERAL_7(r,e,q,u,i,r,e); static const XMLCh NOT[] = UNICODE_LITERAL_3(N,O,T); static const XMLCh AND[] = UNICODE_LITERAL_3(A,N,D); static const XMLCh OR[] = UNICODE_LITERAL_2(O,R); static const XMLCh _Rule[] = UNICODE_LITERAL_4(R,u,l,e); + static const XMLCh _RuleRegex[] = UNICODE_LITERAL_9(R,u,l,e,R,e,g,e,x); } void SHIBSP_API shibsp::registerAccessControls() @@ -125,12 +149,22 @@ void SHIBSP_API shibsp::registerAccessControls() Rule::Rule(const DOMElement* e) { - xmltooling::auto_ptr_char req(e->getAttributeNS(NULL,require)); + auto_ptr_char req(e->getAttributeNS(NULL,require)); if (!req.get() || !*req.get()) throw ConfigurationException("Access control rule missing require attribute"); m_alias=req.get(); + + auto_arrayptr vals(toUTF8(e->hasChildNodes() ? e->getFirstChild()->getNodeValue() : NULL)); + if (!vals.get()) + return; + + const XMLCh* flag = e->getAttributeNS(NULL,_list); + if (flag && (*flag == chLatin_f || *flag == chDigit_0)) { + if (*vals.get()) + m_vals.push_back(vals.get()); + return; + } - xmltooling::auto_ptr_char vals(e->hasChildNodes() ? e->getFirstChild()->getNodeValue() : NULL); #ifdef HAVE_STRTOK_R char* pos=NULL; const char* token=strtok_r(const_cast(vals.get())," ",&pos); @@ -221,6 +255,90 @@ AccessControl::aclresult_t Rule::authorized(const SPRequest& request, const Sess return shib_acl_false; } +RuleRegex::RuleRegex(const DOMElement* e) : m_exp(toUTF8(e->hasChildNodes() ? e->getFirstChild()->getNodeValue() : NULL)) +{ + auto_ptr_char req(e->getAttributeNS(NULL,require)); + if (!req.get() || !*req.get() || !m_exp.get() || !*m_exp.get()) + throw ConfigurationException("Access control rule missing require attribute or element content."); + m_alias=req.get(); + + const XMLCh* flag = e->getAttributeNS(NULL,ignoreCase); + bool ignore = (flag && (*flag == chLatin_t || *flag == chDigit_1)); + try { + m_re = new RegularExpression(e->getFirstChild()->getNodeValue(), (ignore ? ignoreOption : &chNull)); + } + catch (XMLException& ex) { + auto_ptr_char tmp(ex.getMessage()); + throw ConfigurationException("Caught exception while parsing RuleRegex regular expression: $1", params(1,tmp.get())); + } +} + +AccessControl::aclresult_t RuleRegex::authorized(const SPRequest& request, const Session* session) const +{ + // Map alias in rule to the attribute. + if (!session) { + request.log(SPRequest::SPWarn, "AccessControl plugin not given a valid session to evaluate, are you using lazy sessions?"); + return shib_acl_false; + } + + if (m_alias == "valid-user") { + if (session) { + request.log(SPRequest::SPDebug,"AccessControl plugin accepting valid-user based on active session"); + return shib_acl_true; + } + return shib_acl_false; + } + + try { + if (m_alias == "user") { + if (m_re->matches(request.getRemoteUser().c_str())) { + request.log(SPRequest::SPDebug, string("AccessControl plugin expecting REMOTE_USER (") + m_exp.get() + "), authz granted"); + return shib_acl_true; + } + return shib_acl_false; + } + else if (m_alias == "authnContextClassRef") { + if (session->getAuthnContextClassRef() && m_re->matches(session->getAuthnContextClassRef())) { + request.log(SPRequest::SPDebug, string("AccessControl plugin expecting authnContextClassRef (") + m_exp.get() + "), authz granted"); + return shib_acl_true; + } + return shib_acl_false; + } + else if (m_alias == "authnContextDeclRef") { + if (session->getAuthnContextDeclRef() && m_re->matches(session->getAuthnContextDeclRef())) { + request.log(SPRequest::SPDebug, string("AccessControl plugin expecting authnContextDeclRef (") + m_exp.get() + "), authz granted"); + return shib_acl_true; + } + return shib_acl_false; + } + + // Find the attribute(s) matching the require rule. + pair::const_iterator, multimap::const_iterator> attrs = + session->getIndexedAttributes().equal_range(m_alias); + if (attrs.first == attrs.second) { + request.log(SPRequest::SPWarn, string("rule requires attribute (") + m_alias + "), not found in session"); + return shib_acl_false; + } + + for (; attrs.first != attrs.second; ++attrs.first) { + // Now we have to intersect the attribute's values against the regular expression. + const vector& vals = attrs.first->second->getSerializedValues(); + for (vector::const_iterator j=vals.begin(); j!=vals.end(); ++j) { + if (m_re->matches(j->c_str())) { + request.log(SPRequest::SPDebug, string("AccessControl plugin expecting (") + m_exp.get() + "), authz granted"); + return shib_acl_true; + } + } + } + } + catch (XMLException& ex) { + auto_ptr_char tmp(ex.getMessage()); + request.log(SPRequest::SPError, string("caught exception while parsing RuleRegex regular expression: ") + tmp.get()); + } + + return shib_acl_false; +} + Operator::Operator(const DOMElement* e) { if (XMLString::equals(e->getLocalName(),NOT)) @@ -236,6 +354,8 @@ Operator::Operator(const DOMElement* e) e=XMLHelper::getFirstChildElement(e); if (XMLString::equals(e->getLocalName(),_Rule)) m_operands.push_back(new Rule(e)); + else if (XMLString::equals(e->getLocalName(),_RuleRegex)) + m_operands.push_back(new RuleRegex(e)); else m_operands.push_back(new Operator(e)); @@ -246,6 +366,8 @@ Operator::Operator(const DOMElement* e) while (e) { if (XMLString::equals(e->getLocalName(),_Rule)) m_operands.push_back(new Rule(e)); + else if (XMLString::equals(e->getLocalName(),_RuleRegex)) + m_operands.push_back(new RuleRegex(e)); else m_operands.push_back(new Operator(e)); e=XMLHelper::getNextSiblingElement(e); @@ -312,6 +434,8 @@ pair XMLAccessControl::load() AccessControl* authz; if (XMLString::equals(raw.second->getLocalName(),_Rule)) authz=new Rule(raw.second); + else if (XMLString::equals(raw.second->getLocalName(),_RuleRegex)) + authz=new RuleRegex(raw.second); else authz=new Operator(raw.second);