author | Michael Krelin <hacker@klever.net> | 2007-09-14 22:52:21 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2007-09-14 22:52:21 (UTC) |
commit | 5f1d69ac7753243b93761944e9444f01d8a7e5dd (patch) (side-by-side diff) | |
tree | 43ded5d2da27a54f3fa806ddc6f054970d3cb6fc | |
parent | 429c48d3d08e6c2f6c385d8975f7b5bf5e67acf3 (diff) | |
download | libopkele-5f1d69ac7753243b93761944e9444f01d8a7e5dd.zip libopkele-5f1d69ac7753243b93761944e9444f01d8a7e5dd.tar.gz libopkele-5f1d69ac7753243b93761944e9444f01d8a7e5dd.tar.bz2 |
robustness improvements in link descovery mechanisms
accept stray spaces in link tags and inside relevant attribute values.
Thanks, Gen, for pointing it out.
Signed-off-by: Michael Krelin <hacker@klever.net>
-rw-r--r-- | lib/consumer.cc | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/lib/consumer.cc b/lib/consumer.cc index 299b3bc..ff5da91 100644 --- a/lib/consumer.cc +++ b/lib/consumer.cc @@ -194,196 +194,196 @@ namespace opkele { unsigned char *md = HMAC( EVP_sha1(), &(secret.front()),secret.size(), (const unsigned char *)kv.data(),kv.length(), 0,&md_len); if(sig.size()!=md_len || memcmp(&(sig.front()),md,md_len)) throw id_res_mismatch(OPKELE_CP_ "signature mismatch"); }catch(failed_lookup& e) { /* XXX: more specific? */ const string& slist = pin.get_param("openid.signed"); string::size_type pp = 0; params_t p; while(true) { string::size_type co = slist.find(',',pp); string f = "openid."; f += (co==string::npos)?slist.substr(pp):slist.substr(pp,co-pp); p[f] = pin.get_param(f); if(co==string::npos) break; pp = co+1; } p["openid.assoc_handle"] = pin.get_param("openid.assoc_handle"); p["openid.sig"] = pin.get_param("openid.sig"); p["openid.signed"] = pin.get_param("openid.signed"); try { string ih = pin.get_param("openid.invalidate_handle"); p["openid.invalidate_handle"] = ih; }catch(failed_lookup& fl) { } try { check_authentication(server,p); }catch(failed_check_authentication& fca) { throw id_res_failed(OPKELE_CP_ "failed to check_authentication()"); } } if(ext) ext->id_res_hook(pin,ps,identity); } void consumer_t::check_authentication(const string& server,const params_t& p) { string request = "openid.mode=check_authentication"; for(params_t::const_iterator i=p.begin();i!=p.end();++i) { if(i->first!="openid.mode") { request += '&'; request += i->first; request += '='; request += util::url_encode(i->second); } } curl_t curl = curl_easy_init(); if(!curl) throw exception_curl(OPKELE_CP_ "failed to curl_easy_init()"); string response; CURLcode r; (r=curl_misc_sets(curl)) || (r=curl_easy_setopt(curl,CURLOPT_URL,server.c_str())) || (r=curl_easy_setopt(curl,CURLOPT_POST,1)) || (r=curl_easy_setopt(curl,CURLOPT_POSTFIELDS,request.data())) || (r=curl_easy_setopt(curl,CURLOPT_POSTFIELDSIZE,request.length())) || (r=curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,_curl_tostring)) || (r=curl_easy_setopt(curl,CURLOPT_WRITEDATA,&response)) ; if(r) throw exception_curl(OPKELE_CP_ "failed to curl_easy_setopt()",r); if(r=curl_easy_perform(curl)) throw exception_curl(OPKELE_CP_ "failed to curl_easy_perform()",r); params_t pp; pp.parse_keyvalues(response); if(pp.has_param("invalidate_handle")) invalidate_assoc(server,pp.get_param("invalidate_handle")); if(pp.has_param("is_valid")) { if(pp.get_param("is_valid")=="true") return; }else if(pp.has_param("lifetime")) { if(util::string_to_long(pp.get_param("lifetime"))) return; } throw failed_check_authentication(OPKELE_CP_ "failed to verify response"); } void consumer_t::retrieve_links(const string& url,string& server,string& delegate) { #if defined(USE_LIBPCRECPP) || defined(USE_PCREPP) server.erase(); delegate.erase(); curl_t curl = curl_easy_init(); if(!curl) throw exception_curl(OPKELE_CP_ "failed to curl_easy_init()"); string html; CURLcode r; (r=curl_misc_sets(curl)) || (r=curl_easy_setopt(curl,CURLOPT_URL,url.c_str())) || (r=curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,_curl_tostring)) || (r=curl_easy_setopt(curl,CURLOPT_WRITEDATA,&html)) ; if(r) throw exception_curl(OPKELE_CP_ "failed to curl_easy_setopt()",r); r = curl_easy_perform(curl); if(r && r!=CURLE_WRITE_ERROR) throw exception_curl(OPKELE_CP_ "failed to curl_easy_perform()",r); // strip out everything past body - static const char *re_hdre = "<head[^>]*>", - *re_lre = "<link\\b([^>]+)>", - *re_rre = "\\brel=['\"]([^'\"]+)['\"]", - *re_hre = "\\bhref=['\"]([^'\"]+)['\"]"; + static const char *re_hdre = "<\\s*head[^>]*>", + *re_lre = "<\\s*link\\b([^>]+)>", + *re_rre = "\\brel\\s*=\\s*['\"]\\s*([^'\"\\s]+)\\s*['\"]", + *re_hre = "\\bhref\\s*=\\s*['\"]\\s*([^'\"\\s]+)\\s*['\"]"; #if defined(USE_LIBPCRECPP) static pcrecpp::RE_Options ro(PCRE_CASELESS|PCRE_DOTALL); static pcrecpp::RE bre("<body\\b.*",ro), hdre(re_hdre,ro), lre(re_lre,ro), rre(re_rre), hre(re_hre,ro); bre.Replace("",&html); pcrecpp::StringPiece hpiece(html); if(!hdre.FindAndConsume(&hpiece)) throw bad_input(OPKELE_CP_ "failed to find head"); string attrs; while(lre.FindAndConsume(&hpiece,&attrs)) { pcrecpp::StringPiece rel, href; if(!(rre.PartialMatch(attrs,&rel) && hre.PartialMatch(attrs,&href))) continue; if(rel=="openid.server") { href.CopyToString(&server); if(!delegate.empty()) break; }else if(rel=="openid.delegate") { href.CopyToString(&delegate); if(!server.empty()) break; } } #elif defined(USE_PCREPP) pcrepp::Pcre bre("<body\\b",PCRE_CASELESS); if(bre.search(html)) html.erase(bre.get_match_start()); pcrepp::Pcre hdre(re_hdre,PCRE_CASELESS); if(!hdre.search(html)) throw bad_input(OPKELE_CP_ "failed to find head"); html.erase(0,hdre.get_match_end()+1); pcrepp::Pcre lre(re_lre,PCRE_CASELESS), rre(re_rre,PCRE_CASELESS), hre(re_hre,PCRE_CASELESS); while(lre.search(html)) { string attrs = lre[0]; html.erase(0,lre.get_match_end()+1); if(!(rre.search(attrs)&&hre.search(attrs))) continue; if(rre[0]=="openid.server") { server = hre[0]; if(!delegate.empty()) break; }else if(rre[0]=="openid.delegate") { delegate = hre[0]; if(!server.empty()) break; } } #else #error "I must have gone crazy" #endif if(server.empty()) throw failed_assertion(OPKELE_CP_ "The location has no openid.server declaration"); #else /* none of the RE bindings enabled */ throw not_implemented(OPKELE_CP_ "No internal implementation of retrieve_links were provided at compile-time"); #endif } assoc_t consumer_t::find_assoc(const string& server) { throw failed_lookup(OPKELE_CP_ "no find_assoc() provided"); } string consumer_t::normalize(const string& url) { string rv = url; // strip leading and trailing spaces string::size_type i = rv.find_first_not_of(" \t\r\n"); if(i==string::npos) throw bad_input(OPKELE_CP_ "empty URL"); if(i) rv.erase(0,i); i = rv.find_last_not_of(" \t\r\n"); assert(i!=string::npos); if(i<(rv.length()-1)) rv.erase(i+1); // add missing http:// i = rv.find("://"); if(i==string::npos) { // primitive. but do we need more? rv.insert(0,"http://"); i = sizeof("http://")-1; }else{ i += sizeof("://")-1; } string::size_type qm = rv.find('?',i); string::size_type sl = rv.find('/',i); if(qm!=string::npos) { if(sl==string::npos || sl>qm) rv.insert(qm,1,'/'); }else{ if(sl==string::npos) rv += '/'; } return rv; } string consumer_t::canonicalize(const string& url) { string rv = normalize(url); |