-rw-r--r-- | configure.ac | 10 | ||||
-rw-r--r-- | include/Makefile.am | 4 | ||||
-rw-r--r-- | include/opkele/consumer.h | 174 | ||||
-rw-r--r-- | include/opkele/server.h | 98 | ||||
-rw-r--r-- | include/opkele/xconsumer.h | 38 | ||||
-rw-r--r-- | include/opkele/xserver.h | 34 | ||||
-rw-r--r-- | lib/Makefile.am | 6 | ||||
-rw-r--r-- | lib/consumer.cc | 396 | ||||
-rw-r--r-- | lib/server.cc | 172 | ||||
-rw-r--r-- | libopkele.pc.in | 6 |
10 files changed, 5 insertions, 933 deletions
diff --git a/configure.ac b/configure.ac index 5fb6bec..7fa2f85 100644 --- a/configure.ac +++ b/configure.ac @@ -145,58 +145,48 @@ AC_CHECK_HEADER([expat.h],[ EXPAT_CFLAGS= AC_SUBST([EXPAT_LIBS]) AC_SUBST([EXPAT_CFLAGS]) ],[ AC_MSG_ERROR([no required expat library. get one from http://expat.sourceforge.net/]) ]) ],[ AC_MSG_ERROR([no required expat library. get one from http://expat.sourceforge.net/]) ]) AC_CHECK_HEADERS([tidy.h tidy/tidy.h],[ test -z "$TIDY_LIBS" && AC_CHECK_LIB([tidy],[tidyParseBuffer],[ TIDY_LIBS=-ltidy TIDY_CFLAGS= AC_SUBST([TIDY_LIBS]) AC_SUBST([TIDY_CFLAGS]) ],[ AC_MSG_ERROR([no required htmltidy library found. get one from http://tidy.sourceforge.net/]) ]) ],[ test -z "$TIDY_LIBS" -a "$ac_header" = "tidy/tidy.h" \ && AC_MSG_ERROR([no required htmltidy library found. get one from http://tidy.sourceforge.net/]) ]) -if test -n "$PCRE_LIBS" -a -n "$PCRE_CFLAGS" ; then - AC_SUBST([PCRE_CFLAGS]) - AC_SUBST([PCRE_LIBS]) - : -else - PKG_CHECK_MODULES([PCRE],[libpcre],,[ - AC_MSG_ERROR([no libpcre found, go get it at http://www.pcre.org/]) - ]) -fi - PKG_CHECK_MODULES([SQLITE3],[sqlite3],[have_sqlite3=true],[have_sqlite3=false]) AM_CONDITIONAL([HAVE_SQLITE3],[$have_sqlite3]) PKG_CHECK_MODULES([KINGATE],[kingate-plaincgi],[have_kingate=true],[have_kingate=false]) AM_CONDITIONAL([HAVE_KINGATE],[$have_kingate]) PKG_CHECK_MODULES([UUID],[uuid],[have_uuid=true],[have_uuid=false]) AM_CONDITIONAL([HAVE_UUID],[$have_uuid]) if $have_uuid ; then AC_DEFINE([HAVE_LIBUUID],,[defined in presence of libuuid]) AC_SUBST([UUID_UUID],[uuid]) fi curl_ssl_verify_host="true" AC_ARG_ENABLE([ssl-verify-host], AC_HELP_STRING([--disable-ssl-verify-host],[disable cURL cert/host relationships verification]), [ test "${enableval}" = "no" && curl_ssl_verify_host="false" ] ) ${curl_ssl_verify_host} || AC_DEFINE([DISABLE_CURL_SSL_VERIFYHOST],,[defined if cURL is not to verify cert/host]) curl_ssl_verify_peer="true" AC_ARG_ENABLE([ssl-verify-peer], AC_HELP_STRING([--disable-ssl-verify-peer],[disable cURL cert validity verification]), [ test "${enableval}" = "no" && curl_ssl_verify_peer="false" ] ) ${curl_ssl_verify_peer} || AC_DEFINE([DISABLE_CURL_SSL_VERIFYPEER],,[defined if cURL is not to verify cert validity]) diff --git a/include/Makefile.am b/include/Makefile.am index f842bb9..08df18e 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,33 +1,29 @@ NODIST_HEADERS_ = \ opkele/acconfig.h \ opkele/tr1-mem.h nobase_include_HEADERS = \ opkele/opkele-config.h \ opkele/types.h \ opkele/association.h \ opkele/exception.h \ - opkele/server.h \ - opkele/consumer.h \ opkele/extension.h \ opkele/sreg.h \ opkele/extension_chain.h \ - opkele/xconsumer.h \ - opkele/xserver.h \ opkele/uris.h \ opkele/tr1-mem.h \ opkele/basic_rp.h opkele/prequeue_rp.h \ opkele/iterator.h \ opkele/basic_op.h opkele/verify_op.h \ opkele/util.h \ ${NODIST_HEADERS_} noinst_HEADERS = \ opkele/data.h \ opkele/curl.h opkele/expat.h opkele/tidy.h \ opkele/util-internal.h \ opkele/debug.h \ opkele/discovery.h dist-hook: rm -f $(addprefix ${distdir}/,${NODIST_HEADERS_}) diff --git a/include/opkele/consumer.h b/include/opkele/consumer.h deleted file mode 100644 index 3c1d318..0000000 --- a/include/opkele/consumer.h +++ b/dev/null @@ -1,174 +0,0 @@ -#ifndef __OPKELE_CONSUMER_H -#define __OPKELE_CONSUMER_H - -#include <opkele/types.h> -#include <opkele/extension.h> - -/** - * @file - * @brief OpenID consumer-side functionality - */ - -namespace opkele { - - /** - * implementation of basic consumer functionality - * - * @note - * The consumer uses libcurl internally, which means that if you're using - * libopkele in multithreaded environment you should call curl_global_init - * yourself before spawning any threads. - */ - class consumer_t { - public: - - virtual ~consumer_t() { } - - /** - * store association. The function should be overridden in the real - * implementation to provide persistent associations store. - * @param server the OpenID server - * @param handle association handle - * @param secret the secret associated with the server and handle - * @param expires_in the number of seconds until the handle is expired - * @return the assoc_t for the newly allocated association_t object - */ - virtual assoc_t store_assoc(const string& server,const string& handle,const secret_t& secret,int expires_in) = 0; - /** - * retrieve stored association. The function should be overridden - * in the real implementation to provide persistent assocations - * store. - * - * @note - * The user is responsible for handling associations expiry and - * this function should never return an expired or invalidated - * association. - * - * @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 assoc_t 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 assoc_t for the newly allocated association_t - * object, representing established association - * @throw exception in case of error - */ - assoc_t associate(const string& server); - /** - * prepare the parameters for the checkid_immediate - * request. - * @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_immediate(const string& identity,const string& return_to,const string& trust_root="",extension_t *ext=0); - /** - * prepare the parameters for the checkid_setup - * request. - * @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_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); - - }; - -} - -#endif /* __OPKELE_CONSUMER_H */ diff --git a/include/opkele/server.h b/include/opkele/server.h deleted file mode 100644 index 3c25646..0000000 --- a/include/opkele/server.h +++ b/dev/null @@ -1,98 +0,0 @@ -#ifndef __OPKELE_SERVER_H -#define __OPKELE_SERVER_H - -/** - * @file - * @brief OpenID server-side functionality - */ - -#include <opkele/types.h> -#include <opkele/extension.h> - -namespace opkele { - - /** - * implementation of basic server functionality - */ - class server_t { - public: - - virtual ~server_t() { } - - /** - * allocate the new association. The function should be overridden - * in the real implementation to provide persistent assocations - * store. - * @param mode the mode of request being processed to base the - * statelessness of the association upon - * @return the assoc_t for the newly allocated association_t object - */ - virtual assoc_t alloc_assoc(mode_t mode) = 0; - /** - * retrieve the association. The function should be overridden in - * the reqal implementation to provide persistent assocations - * store. - * @param h association handle - * @return the assoc_t for the newly allocated association_t object - * @throw failed_lookup in case of failure - */ - virtual assoc_t retrieve_assoc(const string& h) = 0; - - /** - * validate the identity. - * @param assoc association object - * @param pin incoming request parameters - * @param identity being verified - * @param trust_root presented in the request - * @throw exception if identity can not be confirmed - */ - virtual void validate(const association_t& assoc,const params_t& pin,const string& identity,const string& trust_root) = 0; - - - /** - * process the associate request. - * @param pin the incoming request parameters - * @param pout the store for the response parameters - */ - void associate(const params_t& pin,params_t& pout); - /** - * process the checkid_immediate request. - * @param pin the incoming request parameters - * @param return_to reference to the object to store return_to url to - * @param pout the response parameters - * @param ext pointer to the extension hooks object - * @throw exception in case of errors or negative reply - */ - virtual void checkid_immediate(const params_t& pin,string& return_to,params_t& pout,extension_t *ext=0); - /** - * process the checkid_setup request. - * @param pin the incoming request parameters - * @param return_to reference to the object to store return_to url to - * @param pout the response parameters - * @param ext pointer to the extension hooks object - * @throw exception in case of errors or negative reply - */ - virtual void checkid_setup(const params_t& pin,string& return_to,params_t& pout,extension_t *ext=0); - /** - * the actual functionality behind checkid_immediate() and - * checkid_setup() - * @param mode the request being processed (either - * mode_checkid_immediate or mode_checkid_setup) - * @param pin the incoming request parameters - * @param return_to reference to the object to store return_to url to - * @param pout the response parameters - * @param ext pointer to the extension hooks object - * @throw exception in case of errors or negative reply - */ - virtual void checkid_(mode_t mode,const params_t& pin,string& return_to,params_t& pout,extension_t *ext=0); - /** - * process the check_authentication request. - * @param pin incoming request parameters - * @param pout response parameters - */ - void check_authentication(const params_t& pin,params_t& pout); - }; - -} - -#endif /* __OPKELE_SERVER_H */ diff --git a/include/opkele/xconsumer.h b/include/opkele/xconsumer.h deleted file mode 100644 index 42796c0..0000000 --- a/include/opkele/xconsumer.h +++ b/dev/null @@ -1,38 +0,0 @@ -#ifndef __OPKELE_XCONSUMER_H -#define __OPKELE_XCONSUMER_H - -/** - * @file - * @brief OpenID consumer with built-in extension chain - */ - -#include <opkele/extension_chain.h> -#include <opkele/consumer.h> - -namespace opkele { - - /** - * Extended OpenID consumer implementation with built in - * extensions chain. - */ - class xconsumer_t : public consumer_t, public extension_chain_t { - public: - - string checkid_immediate(const string& identity,const string& return_to,const string& trust_root="",extension_t *ext=0) { - return consumer_t::checkid_immediate(identity,return_to,trust_root,this); - } - string chekid_setup(const string& identity,const string& return_to,const string& trust_root="",extension_t *ext=0) { - return consumer_t::checkid_setup(identity,return_to,trust_root,this); - } - string checkid_(mode_t mode,const string& identity,const string& return_to,const string& trust_root="",extension_t *ext=0) { - return consumer_t::checkid_(mode,identity,return_to,trust_root,this); - } - void id_res(const params_t& pin,const string& identity="",extension_t *ext=0) { - consumer_t::id_res(pin,identity,this); - } - - }; - -} - -#endif /* __OPKELE_XCONSUMER_H */ diff --git a/include/opkele/xserver.h b/include/opkele/xserver.h deleted file mode 100644 index c645d56..0000000 --- a/include/opkele/xserver.h +++ b/dev/null @@ -1,34 +0,0 @@ -#ifndef __OPKELE_XSERVER_H -#define __OPKELE_XSERVER_H - -/** - * @file - * @brief OpenID server with built-in extension chain - */ - -#include <opkele/extension_chain.h> -#include <opkele/server.h> - -namespace opkele { - - /** - * Extended OpenID server implementationwith built in - * extensions chain. - */ - class xserver_t : public server_t, public extension_chain_t { - public: - - void checkid_immediate(const params_t& pin,string& return_to,params_t& pout,extension_t *ext=0) { - server_t::checkid_immediate(pin,return_to,pout,this); - } - void checkid_setup(const params_t& pin,string& return_to,params_t& pout,extension_t *ext=0) { - server_t::checkid_setup(pin,return_to,pout,this); - } - void checkid_(mode_t mode,const params_t& pin,string& return_to,params_t& pout,extension_t *ext=0) { - server_t::checkid_(mode,pin,return_to,pout,this); - } - }; - -} - -#endif /* __OPKELE_XSERVER_H */ diff --git a/lib/Makefile.am b/lib/Makefile.am index e76d7c0..8610597 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,34 +1,32 @@ lib_LTLIBRARIES = libopkele.la AM_CPPFLAGS = ${CPPFLAGS_DEBUG} DEFAULT_INCLUDES = -I${top_builddir} INCLUDES = \ -I${top_builddir}/include/ -I${top_srcdir}/include/ \ ${KONFORKA_CFLAGS} \ ${OPENSSL_CFLAGS} \ ${LIBCURL_CPPFLAGS} \ - ${PCRE_CFLAGS} ${EXPAT_CFLAGS} ${TIDY_CFLAGS} + ${EXPAT_CFLAGS} ${TIDY_CFLAGS} libopkele_la_LIBADD = \ ${LIBCURL} \ - ${PCRE_LIBS} ${EXPAT_LIBS} \ + ${EXPAT_LIBS} \ ${OPENSSL_LIBS} \ ${KONFORKA_LIBS} ${TIDY_LIBS} libopkele_la_SOURCES = \ params.cc \ util.cc \ - server.cc \ secret.cc \ data.cc \ - consumer.cc \ exception.cc \ extension.cc \ sreg.cc \ extension_chain.cc \ curl.cc expat.cc \ discovery.cc \ basic_rp.cc prequeue_rp.cc \ fields.cc message.cc \ basic_op.cc verify_op.cc libopkele_la_LDFLAGS = \ -version-info 3:0:0 diff --git a/lib/consumer.cc b/lib/consumer.cc deleted file mode 100644 index 801496e..0000000 --- a/lib/consumer.cc +++ b/dev/null @@ -1,396 +0,0 @@ -#include <algorithm> -#include <cassert> -#include <cstring> -#include <opkele/util.h> -#include <opkele/util-internal.h> -#include <opkele/curl.h> -#include <opkele/exception.h> -#include <opkele/data.h> -#include <opkele/consumer.h> -#include <openssl/sha.h> -#include <openssl/hmac.h> -#include <iostream> - -#include "config.h" - -#include <pcre.h> - -namespace opkele { - using namespace std; - using util::curl_t; - using util::curl_pick_t; - - class pcre_matches_t { - public: - int *_ov; - int _s; - - pcre_matches_t() : _ov(0), _s(0) { } - pcre_matches_t(int s) : _ov(0), _s(s) { - if(_s&1) ++_s; - _s += _s>>1; - _ov = new int[_s]; - } - ~pcre_matches_t() throw() { if(_ov) delete[] _ov; } - - int begin(int i) const { return _ov[i<<1]; } - int end(int i) const { return _ov[(i<<1)+1]; } - int length(int i) const { int t=i<<1; return _ov[t+1]-_ov[t]; } - }; - - class pcre_t { - public: - pcre *_p; - - pcre_t() : _p(0) { } - pcre_t(pcre *p) : _p(p) { } - pcre_t(const char *re,int opts) : _p(0) { - static const char *errptr; static int erroffset; - _p = pcre_compile(re,opts,&errptr,&erroffset,NULL); - if(!_p) - throw internal_error(OPKELE_CP_ string("Failed to compile regexp: ")+errptr); - } - ~pcre_t() throw() { if(_p) (*pcre_free)(_p); } - - pcre_t& operator=(pcre *p) { if(_p) (*pcre_free)(_p); _p=p; return *this; } - - operator const pcre*(void) const { return _p; } - operator pcre*(void) { return _p; } - - int exec(const string& s,pcre_matches_t& m) { - if(!_p) - throw internal_error(OPKELE_CP_ "Trying to execute absent regexp"); - return pcre_exec(_p,NULL,s.c_str(),s.length(),0,0,m._ov,m._s); - } - }; - - assoc_t consumer_t::associate(const string& server) { - util::dh_t dh = DH_new(); - if(!dh) - throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); - dh->p = util::dec_to_bignum(data::_default_p); - dh->g = util::dec_to_bignum(data::_default_g); - if(!DH_generate_key(dh)) - throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); - string request = - "openid.mode=associate" - "&openid.assoc_type=HMAC-SHA1" - "&openid.session_type=DH-SHA1" - "&openid.dh_consumer_public="; - request += util::url_encode(util::bignum_to_base64(dh->pub_key)); - curl_pick_t curl = curl_pick_t::easy_init(); - if(!curl) - throw exception_curl(OPKELE_CP_ "failed to initialize curl"); - CURLcode r; - (r=curl.misc_sets()) - || (r=curl.easy_setopt(CURLOPT_URL,server.c_str())) - || (r=curl.easy_setopt(CURLOPT_POST,1)) - || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data())) - || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length())) - || (r=curl.set_write()) - ; - if(r) - throw exception_curl(OPKELE_CP_ "failed to set curly options",r); - if( (r=curl.easy_perform()) ) - throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); - params_t p; p.parse_keyvalues(curl.response); - if(p.has_param("assoc_type") && p.get_param("assoc_type")!="HMAC-SHA1") - throw bad_input(OPKELE_CP_ "unsupported assoc_type"); - string st; - if(p.has_param("session_type")) st = p.get_param("session_type"); - if((!st.empty()) && st!="DH-SHA1") - throw bad_input(OPKELE_CP_ "unsupported session_type"); - secret_t secret; - if(st.empty()) { - secret.from_base64(p.get_param("mac_key")); - }else{ - util::bignum_t s_pub = util::base64_to_bignum(p.get_param("dh_server_public")); - vector<unsigned char> ck(DH_size(dh)+1); - unsigned char *ckptr = &(ck.front())+1; - int cklen = DH_compute_key(ckptr,s_pub,dh); - if(cklen<0) - throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); - if(cklen && (*ckptr)&0x80) { - (*(--ckptr)) = 0; ++cklen; - } - unsigned char key_sha1[SHA_DIGEST_LENGTH]; - SHA1(ckptr,cklen,key_sha1); - secret.enxor_from_base64(key_sha1,p.get_param("enc_mac_key")); - } - int expires_in = 0; - if(p.has_param("expires_in")) { - expires_in = util::string_to_long(p.get_param("expires_in")); - }else if(p.has_param("issued") && p.has_param("expiry")) { - expires_in = util::w3c_to_time(p.get_param("expiry"))-util::w3c_to_time(p.get_param("issued")); - }else - throw bad_input(OPKELE_CP_ "no expiration information"); - return store_assoc(server,p.get_param("assoc_handle"),secret,expires_in); - } - - string consumer_t::checkid_immediate(const string& identity,const string& return_to,const string& trust_root,extension_t *ext) { - return checkid_(mode_checkid_immediate,identity,return_to,trust_root,ext); - } - string consumer_t::checkid_setup(const string& identity,const string& return_to,const string& trust_root,extension_t *ext) { - return checkid_(mode_checkid_setup,identity,return_to,trust_root,ext); - } - string consumer_t::checkid_(mode_t mode,const string& identity,const string& return_to,const string& trust_root,extension_t *ext) { - params_t p; - if(mode==mode_checkid_immediate) - p["mode"]="checkid_immediate"; - else if(mode==mode_checkid_setup) - p["mode"]="checkid_setup"; - else - throw bad_input(OPKELE_CP_ "unknown checkid_* mode"); - string iurl = canonicalize(identity); - string server, delegate; - 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); - 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()) - 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) { - 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); - } - - 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_pick_t curl = curl_pick_t::easy_init(); - if(!curl) - throw exception_curl(OPKELE_CP_ "failed to initialize curl"); - CURLcode r; - (r=curl.misc_sets()) - || (r=curl.easy_setopt(CURLOPT_URL,server.c_str())) - || (r=curl.easy_setopt(CURLOPT_POST,1)) - || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data())) - || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length())) - || (r=curl.set_write()) - ; - if(r) - throw exception_curl(OPKELE_CP_ "failed to set curly options",r); - if( (r=curl.easy_perform()) ) - throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); - params_t pp; pp.parse_keyvalues(curl.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) { - server.erase(); - delegate.erase(); - curl_pick_t curl = curl_pick_t::easy_init(); - if(!curl) - throw exception_curl(OPKELE_CP_ "failed to initialize curl"); - string& html = curl.response; - CURLcode r; - (r=curl.misc_sets()) - || (r=curl.easy_setopt(CURLOPT_URL,url.c_str())) - || (r=curl.set_write()); - ; - if(r) - throw exception_curl(OPKELE_CP_ "failed to set curly options",r); - r = curl.easy_perform(); - if(r && r!=CURLE_WRITE_ERROR) - throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); - static const char *re_bre = "<\\s*body\\b", *re_hdre = "<\\s*head[^>]*>", - *re_lre = "<\\s*link\\b([^>]+)>", - *re_rre = "\\brel\\s*=\\s*['\"]([^'\"]+)['\"]", - *re_hre = "\\bhref\\s*=\\s*['\"]\\s*([^'\"\\s]+)\\s*['\"]"; - pcre_matches_t m1(3), m2(3); - pcre_t bre(re_bre,PCRE_CASELESS); - if(bre.exec(html,m1)>0) - html.erase(m1.begin(0)); - pcre_t hdre(re_hdre,PCRE_CASELESS); - if(hdre.exec(html,m1)<=0) - throw bad_input(OPKELE_CP_ "failed to find <head>"); - html.erase(0,m1.end(0)+1); - pcre_t lre(re_lre,PCRE_CASELESS), rre(re_rre,PCRE_CASELESS), hre(re_hre,PCRE_CASELESS); - bool gotit = false; - while( (!gotit) && lre.exec(html,m1)>=2 ) { - static const char *whitespace = " \t"; - string attrs(html,m1.begin(1),m1.length(1)); - html.erase(0,m1.end(0)+1); - if(!( rre.exec(attrs,m1)>=2 && hre.exec(attrs,m2)>=2 )) - continue; - string rels(attrs,m1.begin(1),m1.length(1)); - for(string::size_type ns = rels.find_first_not_of(whitespace); - ns!=string::npos; - ns=rels.find_first_not_of(whitespace,ns)) { - string::size_type s = rels.find_first_of(whitespace,ns); - string rel; - if(s==string::npos) { - rel.assign(rels,ns,string::npos); - ns=string::npos; - }else{ - rel.assign(rels,ns,s-ns); - ns=s; - } - if(rel=="openid.server") { - server.assign(attrs,m2.begin(1),m2.length(1)); - if(!delegate.empty()) { - gotit = true; - break; - } - }else if(rel=="openid.delegate") { - delegate.assign(attrs,m2.begin(1),m2.length(1)); - if(!server.empty()) { - gotit = true; - break; - } - } - } - } - if(server.empty()) - throw failed_assertion(OPKELE_CP_ "The location has no openid.server declaration"); - } - - 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); - curl_t curl = curl_t::easy_init(); - if(!curl) - throw exception_curl(OPKELE_CP_ "failed to initialize curl()"); - string html; - CURLcode r; - (r=curl.misc_sets()) - || (r=curl.easy_setopt(CURLOPT_URL,rv.c_str())) - || (r=curl.easy_setopt(CURLOPT_NOBODY,1)) - ; - if(r) - throw exception_curl(OPKELE_CP_ "failed to set curly options",r); - r = curl.easy_perform(); - if(r) - throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); - const char *eu = 0; - r = curl.easy_getinfo(CURLINFO_EFFECTIVE_URL,&eu); - if(r) - throw exception_curl(OPKELE_CP_ "failed to get CURLINFO_EFFECTIVE_URL",r); - rv = eu; - return normalize(rv); - } - -} diff --git a/lib/server.cc b/lib/server.cc deleted file mode 100644 index 0dea1eb..0000000 --- a/lib/server.cc +++ b/dev/null @@ -1,172 +0,0 @@ -#include <cstring> -#include <vector> -#include <openssl/sha.h> -#include <openssl/hmac.h> -#include <opkele/util.h> -#include <opkele/util-internal.h> -#include <opkele/exception.h> -#include <opkele/server.h> -#include <opkele/data.h> - -namespace opkele { - using namespace std; - - void server_t::associate(const params_t& pin,params_t& pout) { - util::dh_t dh; - util::bignum_t c_pub; - unsigned char key_sha1[SHA_DIGEST_LENGTH]; - enum { - sess_cleartext, - sess_dh_sha1 - } st = sess_cleartext; - if( - pin.has_param("openid.session_type") - && pin.get_param("openid.session_type")=="DH-SHA1" ) { - /* TODO: fallback to cleartext in case of exceptions here? */ - if(!(dh = DH_new())) - throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); - c_pub = util::base64_to_bignum(pin.get_param("openid.dh_consumer_public")); - if(pin.has_param("openid.dh_modulus")) - dh->p = util::base64_to_bignum(pin.get_param("openid.dh_modulus")); - else - dh->p = util::dec_to_bignum(data::_default_p); - if(pin.has_param("openid.dh_gen")) - dh->g = util::base64_to_bignum(pin.get_param("openid.dh_gen")); - else - dh->g = util::dec_to_bignum(data::_default_g); - if(!DH_generate_key(dh)) - throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); - vector<unsigned char> ck(DH_size(dh)+1); - unsigned char *ckptr = &(ck.front())+1; - int cklen = DH_compute_key(ckptr,c_pub,dh); - if(cklen<0) - throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); - if(cklen && (*ckptr)&0x80) { - (*(--ckptr)) = 0; ++cklen; - } - SHA1(ckptr,cklen,key_sha1); - st = sess_dh_sha1; - } - assoc_t assoc = alloc_assoc(mode_associate); - time_t now = time(0); - pout.clear(); - pout["assoc_type"] = assoc->assoc_type(); - pout["assoc_handle"] = assoc->handle(); - /* TODO: eventually remove deprecated stuff */ - pout["issued"] = util::time_to_w3c(now); - pout["expiry"] = util::time_to_w3c(now+assoc->expires_in()); - pout["expires_in"] = util::long_to_string(assoc->expires_in()); - secret_t secret = assoc->secret(); - switch(st) { - case sess_dh_sha1: - pout["session_type"] = "DH-SHA1"; - pout["dh_server_public"] = util::bignum_to_base64(dh->pub_key); - secret.enxor_to_base64(key_sha1,pout["enc_mac_key"]); - break; - default: - secret.to_base64(pout["mac_key"]); - break; - } - } - - void server_t::checkid_immediate(const params_t& pin,string& return_to,params_t& pout,extension_t *ext) { - checkid_(mode_checkid_immediate,pin,return_to,pout,ext); - } - - void server_t::checkid_setup(const params_t& pin,string& return_to,params_t& pout,extension_t *ext) { - checkid_(mode_checkid_setup,pin,return_to,pout,ext); - } - - void server_t::checkid_(mode_t mode,const params_t& pin,string& return_to,params_t& pout,extension_t *ext) { - if(mode!=mode_checkid_immediate && mode!=mode_checkid_setup) - throw bad_input(OPKELE_CP_ "invalid checkid_* mode"); - pout.clear(); - assoc_t assoc; - try { - assoc = retrieve_assoc(pin.get_param("openid.assoc_handle")); - }catch(failed_lookup& fl) { - // no handle specified or no valid handle found, going dumb - assoc = alloc_assoc(mode_checkid_setup); - if(pin.has_param("openid.assoc_handle")) - pout["invalidate_handle"]=pin.get_param("openid.assoc_handle"); - } - string trust_root; - try { - trust_root = pin.get_param("openid.trust_root"); - }catch(failed_lookup& fl) { } - string identity = pin.get_param("openid.identity"); - return_to = pin.get_param("openid.return_to"); - validate(*assoc,pin,identity,trust_root); - pout["mode"] = "id_res"; - pout["assoc_handle"] = assoc->handle(); - if(pin.has_param("openid.assoc_handle") && assoc->stateless()) - pout["invalidate_handle"] = pin.get_param("openid.assoc_handle"); - pout["identity"] = identity; - pout["return_to"] = return_to; - /* TODO: eventually remove deprecated stuff */ - time_t now = time(0); - pout["issued"] = util::time_to_w3c(now); - pout["valid_to"] = util::time_to_w3c(now+120); - pout["exipres_in"] = "120"; - pout["signed"]="mode,identity,return_to"; - if(ext) ext->checkid_hook(pin,pout); - pout["sig"] = util::base64_signature(assoc,pout); - } - - void server_t::check_authentication(const params_t& pin,params_t& pout) { - vector<unsigned char> sig; - const string& sigenc = pin.get_param("openid.sig"); - util::decode_base64(sigenc,sig); - assoc_t assoc; - try { - assoc = retrieve_assoc(pin.get_param("openid.assoc_handle")); - }catch(failed_lookup& fl) { - throw failed_assertion(OPKELE_CP_ "invalid handle or handle not specified"); - } - if(!assoc->stateless()) - throw stateful_handle(OPKELE_CP_ "will not do check_authentication on a stateful handle"); - 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 += ':'; - if(f=="mode") - kv += "id_res"; - else { - f.insert(0,"openid."); - kv += pin.get_param(f); - } - kv += '\n'; - 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); - pout.clear(); - if(sig.size()==md_len && !memcmp(&(sig.front()),md,md_len)) { - pout["is_valid"]="true"; - pout["lifetime"]="60"; /* TODO: eventually remove deprecated stuff */ - }else{ - pout["is_valid"]="false"; - pout["lifetime"]="0"; /* TODO: eventually remove deprecated stuff */ - } - if(pin.has_param("openid.invalidate_handle")) { - string h = pin.get_param("openid.invalidate_handle"); - try { - assoc_t tmp = retrieve_assoc(h); - }catch(invalid_handle& ih) { - pout["invalidate_handle"] = h; - }catch(failed_lookup& fl) { } - } - } - -} diff --git a/libopkele.pc.in b/libopkele.pc.in index 2720a6a..268f998 100644 --- a/libopkele.pc.in +++ b/libopkele.pc.in @@ -1,11 +1,11 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libopkele Description: C++ implementation of OpenID protocol Version: @VERSION@ -Requires: openssl libpcre @KONFORKA_KONFORKA@ @UUID_UUID@ -Cflags: -I${includedir} @LIBCURL_CPPFLAGS@ @PCRE_CFLAGS@ @EXPAT_CFLAGS@ @TIDY_CFLAGS@ -Libs: -L${libdir} -lopkele @LIBCURL@ @PCRE_LIBS@ @EXPAT_LIBS@ @TIDY_LIBS@ +Requires: openssl @KONFORKA_KONFORKA@ @UUID_UUID@ +Cflags: -I${includedir} @LIBCURL_CPPFLAGS@ @EXPAT_CFLAGS@ @TIDY_CFLAGS@ +Libs: -L${libdir} -lopkele @LIBCURL@ @EXPAT_LIBS@ @TIDY_LIBS@ |