author | Michael Krelin <hacker@klever.net> | 2007-12-09 22:10:49 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2007-12-09 22:10:49 (UTC) |
commit | 2e7bf3278c3e13baaa32c7ec8c2b3fdc4780a080 (patch) (side-by-side diff) | |
tree | d36530a517425d2507df8e9550fbcc48fba48c5f | |
parent | c34adc6e274c3dbb63af99ca566000e7d218244c (diff) | |
parent | 7a6a6fbcf7e20f0d7da5f625a73c865b361f16aa (diff) | |
download | libopkele-2e7bf3278c3e13baaa32c7ec8c2b3fdc4780a080.zip libopkele-2e7bf3278c3e13baaa32c7ec8c2b3fdc4780a080.tar.gz libopkele-2e7bf3278c3e13baaa32c7ec8c2b3fdc4780a080.tar.bz2 |
Merge branch 'next' into devel/xri
-rw-r--r-- | include/opkele/consumer.h | 6 | ||||
-rw-r--r-- | include/opkele/exception.h | 9 | ||||
-rw-r--r-- | lib/consumer.cc | 6 | ||||
-rw-r--r-- | lib/util.cc | 6 |
4 files changed, 21 insertions, 6 deletions
diff --git a/include/opkele/consumer.h b/include/opkele/consumer.h index 50ff692..c463787 100644 --- a/include/opkele/consumer.h +++ b/include/opkele/consumer.h @@ -46,48 +46,53 @@ namespace opkele { * * @param server the OpenID server * @param handle association handle * @return the autho_ptr<> for the newly allocated association_t object * @throw failed_lookup if no unexpired association found */ virtual assoc_t retrieve_assoc(const string& server,const string& handle) = 0; /** * invalidate stored association. The function should be overridden * in the real implementation of the consumer. * @param server the OpenID server * @param handle association handle */ virtual void invalidate_assoc(const string& server,const string& handle) = 0; /** * retrieve any unexpired association for the server. If the * function is not overridden in the real implementation, the new * association will be established for each request. * * @note * The user is responsible for handling associations and this * function should never return an expired or invalidated * association. * + * @note + * It may be a good idea to pre-expire associations shortly before + * their time is really up to avoid association expiry in the + * middle of negotiations. + * * @param server the OpenID server * @return the auto_ptr<> for the newly allocated association_t object * @throw failed_lookup in case of absence of the handle */ virtual assoc_t find_assoc(const string& server); /** * retrieve the metainformation contained in link tags from the * page pointed by url. the function may implement caching of the * information. * @param url url to harvest for link tags * @param server reference to the string object where to put * openid.server value * @param delegate reference to the string object where to put the * openid.delegate value (if any) */ virtual void retrieve_links(const string& url,string& server,string& delegate); /** * perform the associate request to OpenID server. * @param server the OpenID server * @return the auto_ptr<> for the newly allocated association_t * object, representing established association * @throw exception in case of error @@ -116,48 +121,49 @@ namespace opkele { */ virtual string checkid_setup(const string& identity,const string& return_to,const string& trust_root="",extension_t *ext=0); /** * the actual implementation behind checkid_immediate() and * checkid_setup() functions. * @param mode checkid_* mode - either mode_checkid_immediate or mode_checkid_setup * @param identity the identity to verify * @param return_to the return_to url to pass with the request * @param trust_root the trust root to advertise with the request * @param ext pointer to an extension(s) hooks object * @return the location string * @throw exception in case of error */ virtual string checkid_(mode_t mode,const string& identity,const string& return_to,const string& trust_root="",extension_t *ext=0); /** * verify the id_res response * @param pin the response parameters * @param identity the identity being checked (if not specified, * @param ext pointer to an extension(s) hooks object * extracted from the openid.identity parameter * @throw id_res_mismatch in case of signature mismatch * @throw id_res_setup in case of openid.user_setup_url failure * (supposedly checkid_immediate only) * @throw id_res_failed in case of failure + * @throw id_res_expired_on_delivery if the association expired before it could've been verified * @throw exception in case of other failures */ virtual void id_res(const params_t& pin,const string& identity="",extension_t *ext=0); /** * perform a check_authentication request. * @param server the OpenID server * @param p request parameters */ void check_authentication(const string& server,const params_t& p); /** * normalize URL by adding http:// and trailing slash if needed. * @param url * @return normalized url */ static string normalize(const string& url); /** * Canonicalize URL, by normalizing its appearance and following redirects. * @param url * @return canonicalized url */ virtual string canonicalize(const string& url); diff --git a/include/opkele/exception.h b/include/opkele/exception.h index a654d59..8913665 100644 --- a/include/opkele/exception.h +++ b/include/opkele/exception.h @@ -149,48 +149,57 @@ namespace opkele { public: id_res_failed(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown if the user_setup_url is provided with negative response */ class id_res_setup : public id_res_failed { public: string setup_url; id_res_setup(OPKELE_E_PARS,const string& su) : id_res_failed(OPKELE_E_CONS), setup_url(su) { } ~id_res_setup() throw() { } }; /** * thrown in case of signature mismatch */ class id_res_mismatch : public id_res_failed { public: id_res_mismatch(OPKELE_E_PARS) : id_res_failed(OPKELE_E_CONS) { } }; /** + * thrown if the association has expired before it could've been verified. + */ + class id_res_expired_on_delivery : public id_res_failed { + public: + id_res_expired_on_delivery(OPKELE_E_PARS) + : id_res_failed(OPKELE_E_CONS) { } + }; + + /** * openssl malfunction occured */ class exception_openssl : public exception { public: unsigned long _error; string _ssl_string; exception_openssl(OPKELE_E_PARS); ~exception_openssl() throw() { } }; /** * network operation related error occured */ class exception_network : public exception { public: exception_network(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * network operation related error occured, specifically, related to * libcurl */ class exception_curl : public exception_network { diff --git a/lib/consumer.cc b/lib/consumer.cc index 66db7dd..9f7530f 100644 --- a/lib/consumer.cc +++ b/lib/consumer.cc @@ -163,79 +163,79 @@ namespace opkele { retrieve_links(iurl,server,delegate); p["identity"] = delegate.empty()?iurl:delegate; if(!trust_root.empty()) p["trust_root"] = trust_root; p["return_to"] = return_to; try { string ah = find_assoc(server)->handle(); p["assoc_handle"] = ah; }catch(failed_lookup& fl) { string ah = associate(server)->handle(); p["assoc_handle"] = ah; } if(ext) ext->checkid_hook(p,identity); return p.append_query(server); } void consumer_t::id_res(const params_t& pin,const string& identity,extension_t *ext) { if(pin.has_param("openid.user_setup_url")) throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided",pin.get_param("openid.user_setup_url")); string server,delegate; retrieve_links(identity.empty()?pin.get_param("openid.identity"):canonicalize(identity),server,delegate); params_t ps; try { assoc_t assoc = retrieve_assoc(server,pin.get_param("openid.assoc_handle")); - if(assoc->is_expired()) /* TODO: or should I throw some other exception to force programmer fix his implementation? */ - throw failed_lookup(OPKELE_CP_ "retrieve_assoc() has returned expired handle"); + if(assoc->is_expired()) + throw id_res_expired_on_delivery(OPKELE_CP_ "retrieve_assoc() has returned expired handle"); const string& sigenc = pin.get_param("openid.sig"); vector<unsigned char> sig; util::decode_base64(sigenc,sig); const string& slist = pin.get_param("openid.signed"); string kv; string::size_type p = 0; while(true) { string::size_type co = slist.find(',',p); string f = (co==string::npos)?slist.substr(p):slist.substr(p,co-p); kv += f; kv += ':'; f.insert(0,"openid."); kv += pin.get_param(f); kv += '\n'; if(ext) ps[f.substr(sizeof("openid.")-1)] = pin.get_param(f); if(co==string::npos) break; p = co+1; } secret_t secret = assoc->secret(); unsigned int md_len = 0; 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? */ + }catch(failed_lookup& e) { 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()"); } diff --git a/lib/util.cc b/lib/util.cc index 83f0eef..4600576 100644 --- a/lib/util.cc +++ b/lib/util.cc @@ -200,51 +200,51 @@ namespace opkele { * xri? */ rv.append(uri,colon+1,ul-colon-1); return rv; } rv += "//"; string::size_type interesting = uri.find_first_of(":/#?",colon+3); if(interesting==string::npos) { transform( uri.begin()+colon+3,uri.begin()+ul, back_inserter(rv), ::tolower ); rv += '/'; return rv; } transform( uri.begin()+colon+3,uri.begin()+interesting, back_inserter(rv), ::tolower ); bool qf = false; char ic = uri[interesting]; if(ic==':') { string::size_type ni = uri.find_first_of("/#?%",interesting+1); const char *nptr = uri.data()+interesting+1; char *eptr = 0; long port = strtol(nptr,&eptr,10); if( (port>0) && (port<65535) && port!=(s?443:80) ) { - char tmp[6]; - snprintf(tmp,sizeof(tmp),"%ld",port); - rv += ':'; rv += tmp; + char tmp[8]; + snprintf(tmp,sizeof(tmp),":%ld",port); + rv += tmp; } if(ni==string::npos) { rv += '/'; return rv; } interesting = ni; }else if(ic!='/') { rv += '/'; rv += ic; qf = true; ++interesting; } string::size_type n = interesting; char tmp[3] = { 0,0,0 }; stack<string::size_type> psegs; psegs.push(rv.length()); string pseg; for(;n<ul;) { string::size_type unsafe = uri.find_first_of(qf?"%":"%/?#",n); if(unsafe==string::npos) { pseg.append(uri,n,ul-n-1); n = ul-1; }else{ pseg.append(uri,n,unsafe-n); n = unsafe; } char c = uri[n++]; if(c=='%') { |