-rw-r--r-- | include/opkele/basic_rp.h | 218 | ||||
-rw-r--r-- | include/opkele/discovery.h | 88 | ||||
-rw-r--r-- | include/opkele/exception.h | 19 | ||||
-rw-r--r-- | include/opkele/extension.h | 7 | ||||
-rw-r--r-- | include/opkele/extension_chain.h | 6 | ||||
-rw-r--r-- | include/opkele/prequeue_rp.h | 81 | ||||
-rw-r--r-- | include/opkele/sreg.h | 8 | ||||
-rw-r--r-- | include/opkele/types.h | 169 | ||||
-rw-r--r-- | include/opkele/util.h | 8 |
9 files changed, 478 insertions, 126 deletions
diff --git a/include/opkele/basic_rp.h b/include/opkele/basic_rp.h new file mode 100644 index 0000000..3f17fd9 --- a/dev/null +++ b/include/opkele/basic_rp.h @@ -0,0 +1,218 @@ +#ifndef __OPKELE_BASIC_RP_H +#define __OPKELE_BASIC_RP_H + +#include <cstring> +#include <string> +#include <opkele/types.h> +#include <opkele/extension.h> + +namespace opkele { + using std::string; + + struct openid_endpoint_t { + string uri; + string claimed_id; + string local_id; + + openid_endpoint_t() { } + openid_endpoint_t(const string& u,const string& cid,const string& lid) + : uri(u), claimed_id(cid), local_id(lid) { } + + bool operator==(const openid_endpoint_t& x) const { + return uri==x.uri && local_id==x.local_id; } + bool operator<(const openid_endpoint_t& x) const { + int c; + return (c=strcmp(uri.c_str(),x.uri.c_str())) + ? (c<0) : (strcmp(local_id.c_str(),x.local_id.c_str())<0); } + }; + + class basic_RP { + public: + + virtual ~basic_RP() { } + + /** + * @name Global persistent store API + * These are functions related to the associations with OP storage + * and retrieval and nonce records. They provide an interface to + * the persistent storage which is shared by all sessions. If the + * implementor prefers the dumb mode instead, the function should + * throw dumb_RP exception instead. + * @see opkele::dumb_RP + * @{ + */ + /** + * Store association and return allocated association object. + * @param OP OP endpoint + * @param handle association handle + * @param type association type + * @param secret association secret + * @params expires_in the number of seconds association expires in + * @return the association object + * @throw dumb_RP for dumb RP + */ + virtual assoc_t store_assoc( + const string& OP,const string& handle, + const string& type,const secret_t& secret, + int expires_in) = 0; + /** + * Find valid unexpired association with an OP. + * @param OP OP endpoint URL + * @return association found + * @throw failed_lookup if no association found + * @throw dumb_RP for dumb RP + */ + virtual assoc_t find_assoc( + const string& OP) = 0; + /** + * Retrieve valid association handle for an OP by handle. + * @param OP OP endpoint URL + * @param handle association handle + * @return association found + * @throw failed_lookup if no association found + * @throw dumb_RP for dumb RP + */ + virtual assoc_t retrieve_assoc( + const string& OP,const string& handle) = 0; + /** + * Invalidate association with OP + * @param OP OP endpoint URL + * @param handle association handle + * @throw dumb_RP for dumb RP + */ + virtual void invalidate_assoc(const string& OP,const string& handle) = 0; + + /** + * Check the nonce validity. That is, check that we haven't + * accepted request with this nonce from this OP, yet. May involve + * cutting off by the timestamp and checking the rest against the + * store of seen nonces. + * @param OP OP endpoint URL + * @param nonce nonce value + * @throw id_res_bad_nonce if the nonce is not to be accepted, i.e. + * either too old or seen. + */ + virtual void check_nonce(const string& OP,const string& nonce) = 0; + /** + * @} + */ + + /** + * @name Session persistent store API + * @{ + */ + /** + * Retrieve OpenID endpoint being currently used for + * authentication. If there is no endpoint available, throw a + * no_endpoint exception. + * @return reference to the service endpoint object + * @see next_endpoint + * @throw no_endpoint if no endpoint available + */ + virtual const openid_endpoint_t& get_endpoint() const = 0; + /** + * Advance to the next endpoint to try. + * @see get_endpoint() + * @throw no_endpoint if there are no more endpoints + */ + virtual void next_endpoint() = 0; + /** + * @} + */ + + /** + * @name Site particulars API + * @{ + */ + /** + * Return an absolute URL of the page being processed, includining + * query parameters. It is used to validate return_to URL on + * positive assertions. + * @return fully qualified url of the page being processed. + */ + virtual const string get_this_url() const = 0; + /** + * @} + */ + + /** + * @name OpenID actions + * @{ + */ + /** + * Initiates authentication session, doing discovery, normalization + * and whatever implementor wants to do at this point. + * @param usi User-supplied identity + */ + virtual void initiate(const string& usi) = 0; + /** + * Prepare checkid_request. + * @param rv reference to the openid message to prepare + * @param mode checkid_setup or checkid_immediate + * @param return_to the URL OP should redirect to after completion + * @param realm authentication realm to pass to OP + * @param ext pointer to extension to use in request preparation + * @return reference to the openid message + */ + basic_openid_message& checkid_( + basic_openid_message& rv, + mode_t mode, + const string& return_to,const string& realm, + extension_t *ext=0); + /** + * Verify assertion at the end of round-trip. + * @param om incoming openid message + * @param ext pointer to extention to use in parsing assertion + * @throw id_res_setup if checkid_immediate request could not be + * completed + * @throw id_res_cancel if authentication request was canceled + * @throw id_res_mismatch in case of signature mismatch + * @throw id_res_bad_return_to if return_to url seems to be + * tampered with + * @throw id_res_unauthorized if OP is not authorized to make + * assertions regarding the identity + */ + void id_res(const basic_openid_message& om,extension_t *ext=0); + + /** + * Establish association with OP + * @param OP OP to establish association with + * @throw dumb_RP if for a dumb RP + */ + virtual assoc_t associate(const string& OP); + /** + * Check authentication with OP and invalidate handle if requested + * and confirmed + * @param OP OP to check with + * @param om message to check + * @throw failed_check_authentication if OP fails to confirm + * authenticity of the assertion + */ + void check_authentication(const string& OP,const basic_openid_message& om); + /** + * @} + */ + + /** + * @name Miscellanea + * @{ + */ + /** + * Verify OP authority. Return normally if OP is authorized to make + * an assertion, throw an exception otherwise. + * @param OP OP endpoint + * @param claimed_id claimed identity + * @param identity OP-Local identifier + * @throw id_res_unauthorized if OP is not authorized to make + * assertion regarding this identity. + */ + virtual void verify_OP(const string& OP, + const string& claimed_id,const string& identity) const = 0; + /** + * @} + */ + }; + +} + +#endif /* __OPKELE_BASIC_RP_H */ diff --git a/include/opkele/discovery.h b/include/opkele/discovery.h index af4aa29..ab4b9d9 100644 --- a/include/opkele/discovery.h +++ b/include/opkele/discovery.h @@ -1,40 +1,104 @@ #ifndef __OPKELE_DISCOVERY_H #define __OPKELE_DISCOVERY_H #include <string> #include <opkele/types.h> +#include <opkele/basic_rp.h> namespace opkele { using std::string; - struct idiscovery_t; + namespace xrd { - void idiscover(idiscovery_t& result,const string& identity); + struct priority_compare { + inline bool operator()(long a,long b) const { + return (a<0) ? false : (b<0) ? true : (a<b); + } + }; + + template <typename _DT> + class priority_map : public multimap<long,_DT,priority_compare> { + typedef multimap<long,_DT,priority_compare> map_type; + public: + + inline _DT& add(long priority,const _DT& d) { + return insert(typename map_type::value_type(priority,d))->second; + } + + bool has_value(const _DT& d) const { + for(typename map_type::const_iterator i=this->begin();i!=this->end();++i) + if(i->second==d) return true; + return false; + } + }; + + typedef priority_map<string> canonical_ids_t; + typedef priority_map<string> local_ids_t; + typedef set<string> types_t; + typedef priority_map<string> uris_t; + + class service_t { + public: + types_t types; + uris_t uris; + local_ids_t local_ids; + string provider_id; + + void clear() { + types.clear(); + uris.clear(); local_ids.clear(); + provider_id.clear(); + } + }; + typedef priority_map<service_t> services_t; + + class XRD_t { + public: + time_t expires; + + canonical_ids_t canonical_ids; + local_ids_t local_ids; + services_t services; + string provider_id; + + void clear() { + expires = 0; + canonical_ids.clear(); local_ids.clear(); + services.clear(); + provider_id.clear(); + } + bool empty() const { + return + canonical_ids.empty() + && local_ids.empty() + && services.empty(); + } + + }; + + } + + typedef util::output_iterator_proxy<openid_endpoint_t> + endpoint_discovery_iterator; + + string idiscover( + endpoint_discovery_iterator oi, + const string& identity); struct idiscovery_t { bool xri_identity; string normalized_id; string canonicalized_id; xrd::XRD_t xrd; idiscovery_t() { } - idiscovery_t(const string& i) { - idiscover(*this,i); - } - idiscovery_t(const char *i) { - idiscover(*this,i); - } void clear() { normalized_id.clear(); canonicalized_id.clear(); xrd.clear(); } - idiscovery_t& operator=(const string& i) { - idiscover(*this,i); return *this; } - idiscovery_t& operator=(const char *i) { - idiscover(*this,i); return *this; } }; } #endif /* __OPKELE_DISCOVERY_H */ diff --git a/include/opkele/exception.h b/include/opkele/exception.h index a8c3339..ccb39d9 100644 --- a/include/opkele/exception.h +++ b/include/opkele/exception.h @@ -1,316 +1,335 @@ #ifndef __OPKELE_EXCEPTION_H #define __OPKELE_EXCEPTION_H /** * @file * @brief opkele exceptions */ #include <curl/curl.h> #include <opkele/opkele-config.h> #ifdef OPKELE_HAVE_KONFORKA # include <konforka/exception.h> /** * the exception parameters declaration */ # define OPKELE_E_PARS const string& fi,const string&fu,int l,const string& w /** * the exception parameters list to pass to constructor */ # define OPKELE_E_CONS_ fi,fu,l, /** * the exception codepoint specification */ # define OPKELE_CP_ CODEPOINT, /** * open function-try-block */ # define OPKELE_FUNC_TRY try /** * the simple rethrow of konforka-based exception */ # define OPKELE_RETHROW catch(konforka::exception& e) { e.see(CODEPOINT); throw; } #else /* OPKELE_HAVE_KONFORKA */ # include <exception> # include <string> /** * the exception parameter declaration */ # define OPKELE_E_PARS const string& w /** * the dummy prefix for exception parameters list to prepend in the absence of * konforka library */ # define OPKELE_E_CONS_ /** * the dummy placeholder for konforka exception codepoint specification */ # define OPKELE_CP_ /** * the dummy define for the opening function-try-block */ # define OPKELE_FUNC_TRY /** * the dummy define for the konforka-based rethrow of exception */ # define OPKELE_RETHROW #endif /* OPKELE_HAVE_KONFORKA */ /** * the exception parameters list to pass to constructor */ # define OPKELE_E_CONS OPKELE_E_CONS_ w namespace opkele { using std::string; /** * the base opkele exception class */ class exception : public # ifdef OPKELE_HAVE_KONFORKA konforka::exception # else std::exception # endif { public: # ifdef OPKELE_HAVE_KONFORKA explicit exception(const string& fi,const string& fu,int l,const string& w); # else /* OPKELE_HAVE_KONFORKA */ string _what; explicit exception(const string& w); virtual ~exception() throw(); virtual const char * what() const throw(); # endif /* OPKELE_HAVE_KONFORKA */ }; /** * thrown in case of failed conversion */ class failed_conversion : public exception { public: failed_conversion(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown in case of failed lookup (either parameter or persistent store) */ class failed_lookup : public exception { public: failed_lookup(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown in case of bad input (either local or network) */ class bad_input : public exception { public: bad_input(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown on failed assertion */ class failed_assertion : public exception { public: failed_assertion(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown if the handle being retrieved is invalid */ class invalid_handle : public exception { public: invalid_handle(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown if the handle passed to check_authentication request is not * stateless */ class stateful_handle : public exception { public: stateful_handle(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown if check_authentication request fails */ class failed_check_authentication : public exception { public: failed_check_authentication(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown if the id_res request result is negative */ class id_res_failed : public exception { 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) { } }; /** * thown when the user cancelled authentication process. */ class id_res_cancel : public id_res_failed { public: id_res_cancel(OPKELE_E_PARS) : id_res_failed(OPKELE_E_CONS) { } }; /** * thrown in case of nonce reuse or otherwise imperfect nonce. */ class id_res_bad_nonce : public id_res_failed { public: id_res_bad_nonce(OPKELE_E_PARS) : id_res_failed(OPKELE_E_CONS) { } }; /** * thrown if return_to didn't pass verification */ class id_res_bad_return_to : public id_res_failed { public: id_res_bad_return_to(OPKELE_E_PARS) : id_res_failed(OPKELE_E_CONS) { } }; /** * thrown if OP isn't authorized to make an assertion */ class id_res_unauthorized : public id_res_failed { public: id_res_unauthorized(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 { public: CURLcode _error; string _curl_string; exception_curl(OPKELE_E_PARS); exception_curl(OPKELE_E_PARS,CURLcode e); ~exception_curl() throw() { } }; /** * htmltidy related error occured */ class exception_tidy : public exception { public: int _rc; exception_tidy(OPKELE_E_PARS); exception_tidy(OPKELE_E_PARS,int r); ~exception_tidy() throw() { } }; /** * exception thrown in case of failed discovery */ class failed_discovery : public exception { public: failed_discovery(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * unsuccessfull xri resolution */ class failed_xri_resolution : public failed_discovery { public: long _code; failed_xri_resolution(OPKELE_E_PARS,long _c=-1) : failed_discovery(OPKELE_E_CONS), _code(_c) { } }; /** * not implemented (think pure virtual) member function executed, signfies * programmer error */ class not_implemented : public exception { public: not_implemented(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * internal error, indicates internal libopkele problem */ class internal_error : public exception { public: internal_error(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown in case of unsupported parameter encountered (e.g. unsupported * association type). */ class unsupported : public exception { public: unsupported(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; + /** + * thrown by associations store related functions in case of dumb RP. + */ + class dumb_RP : public exception { + public: + dumb_RP(OPKELE_E_PARS) + : exception(OPKELE_E_CONS) { } + }; + + /** + * thrown by endpoint-queue related function if endpoint is being + * accessed but there's no endpoint available. + */ + class no_endpoint : public exception { + public: + no_endpoint(OPKELE_E_PARS) + : exception(OPKELE_E_CONS) { } + }; + } #endif /* __OPKELE_EXCEPTION_H */ diff --git a/include/opkele/extension.h b/include/opkele/extension.h index 513672f..3ee25ee 100644 --- a/include/opkele/extension.h +++ b/include/opkele/extension.h @@ -1,65 +1,66 @@ #ifndef __OPKELE_EXTENSION_H #define __OPKELE_EXTENSION_H /** * @file * @brief extensions framework basics */ #include <opkele/types.h> namespace opkele { /** * OpenID extension hooks base class */ class extension_t { public: virtual ~extension_t() { } + /** * hook called by consumer before submitting data to OpenID server. * It is supposed to manipulate parameters list. * @param p parameters about to be submitted to server * @param identity identity being verified. It may differ from the * one available in parameters list in case of delegation * @see consumer_t::checkid_ * @see consumer_t::checkid_immediate * @see consumer_t::checkid_setup */ - virtual void checkid_hook(params_t& p,const string& identity); + virtual void checkid_hook(basic_openid_message& om); /** * hook called by consumer after identity information received from * OpenID server is verified. * @param p parameters received from server * @param sp signed parameters received from server with 'openid.' * leader stripped * @param identity identity confirmed. May differ from the one * available in parameters list in case of delegation. May also be * empty which means - extract one from parameters * @see consumer_t::id_res */ - virtual void id_res_hook(const params_t& p,const params_t& sp,const string& identity); + virtual void id_res_hook(const basic_openid_message& om,const basic_openid_message& sp); /** * hook called by server before returning information to consumer. * The hook may manipulate output parameters. It is important to * note that modified pout["signed"] is used for signing response. * @param pin request parameters list with "openid." prefix * @param pout response parameters list without "openid." prefix * @see server_t::checkid_ * @see server_t::checkid_immediate * @see server_t::checkid_setup */ - virtual void checkid_hook(const params_t& pin,params_t& pout); + virtual void checkid_hook(const basic_openid_message& inm,basic_openid_message& oum); /** * Casts the object to pointer to itself. For convenient passing * of pointer. */ operator extension_t*(void) { return this; } }; } #endif /* __OPKELE_EXTENSION_H */ diff --git a/include/opkele/extension_chain.h b/include/opkele/extension_chain.h index f0eea94..fb9bc84 100644 --- a/include/opkele/extension_chain.h +++ b/include/opkele/extension_chain.h @@ -1,38 +1,38 @@ #ifndef __OPKELE_EXTENSION_CHAIN_H #define __OPKELE_EXTENSION_CHAIN_H /** * @file * @brief extension chain extension */ #include <list> #include <opkele/extension.h> namespace opkele { using std::list; /** * OpenID extensions chain used to combine extensions, it is actually an * stl list of pointers to extensions. */ class extension_chain_t : public extension_t, public list<extension_t*> { public: /** * Default constructor creates an empty chain */ extension_chain_t() { } /** * Create extension chain with a single extension in it */ extension_chain_t(extension_t *e) { push_back(e); } - virtual void checkid_hook(params_t& p,const string& identity); - virtual void id_res_hook(const params_t& p,const params_t& sp,const string& identity); - virtual void checkid_hook(const params_t& pin,params_t& pout); + virtual void checkid_hook(basic_openid_message& om); + virtual void id_res_hook(const basic_openid_message& om,const basic_openid_message& sp); + virtual void checkid_hook(const basic_openid_message& inm,basic_openid_message& oum); }; } #endif /* __OPKELE_EXTENSION_CHAIN_H */ diff --git a/include/opkele/prequeue_rp.h b/include/opkele/prequeue_rp.h new file mode 100644 index 0000000..b98dd5a --- a/dev/null +++ b/include/opkele/prequeue_rp.h @@ -0,0 +1,81 @@ +#ifndef __OPKELE_RP_H +#define __OPKELE_RP_H + +#include <string> +#include <set> +#include <iterator> +#include <opkele/basic_rp.h> + +namespace opkele { + using std::string; + using std::set; + using std::iterator; + using std::output_iterator_tag; + + class prequeue_RP : public basic_RP { + public: + /** + * @name Session persistent store API + * @{ + */ + /** + * Called before queueing discovered endpoints. Typically happens + * while initiating authentication session. + * @see queue_endpoint() + * @see end_queueing() + */ + virtual void begin_queueing() { } + /** + * Used to queue discovered endpoint. It is implementors + * responsibility to store the endpoint wherever he choses to store + * it. + * @param oep the endpoint to queue + * @see begin_queueing() + * @see end_queueing() + */ + virtual void queue_endpoint(const openid_endpoint_t& oep) = 0; + /** + * Called after all discovered endpoints were queued. Implementor + * may chose to use this virtual to commit endpoints queue to + * persistent store. + * @see begin_queueing() + * @see queue_endpoint() + */ + virtual void end_queueing() { } + + /** + * Used to store normalized id when initiating request. + * The default implementation does nothing, because implementor + * doesn't have to care. + * @param nid normalized id + * @see get_normalzied_id() + */ + virtual void set_normalized_id(const string& nid); + /** + * Return the normalized id previously set by set_normalized_id(). + * Provided for the sake of completeness because default + * implementation doesn't use it. + * @return the normalized identity + */ + virtual const string get_normalized_id() const; + /** + * @} + */ + + /** + * @name Actions + * @{ + */ + void initiate(const string& usi); + + /** + * @} + */ + + void verify_OP(const string& OP, + const string& claimed_id,const string& identity) const; + }; + +} + +#endif /* __OPKELE_RP_H */ diff --git a/include/opkele/sreg.h b/include/opkele/sreg.h index df37a86..24cb315 100644 --- a/include/opkele/sreg.h +++ b/include/opkele/sreg.h @@ -1,203 +1,203 @@ #ifndef __OPKELE_SREG_H #define __OPKELE_SREG_H /** * @file * @brief Simple registration extension */ #include <opkele/extension.h> namespace opkele { using std::map; /** * OpenID simple registration extension implementation * http://openid.net/specs/openid-simple-registration-extension-1_0.html */ class sreg_t : public extension_t { public: /** * sreg fields enumeration */ enum fieldbit_t { /** * Any UTF-8 string that the End User wants to use as a nickname. */ field_nickname = 1, /** * The email address of the End User as specified in section 3.4.1 of [RFC2822] */ field_email = 2, /** * UTF-8 string free text representation of the End User's full name. */ field_fullname = 4, /** * The End User's date of birth as YYYY-MM-DD. Any values whose * representation uses fewer than the specified number of * digits should be zero-padded. The length of this value MUST * always be 10. If the End User user does not want to reveal * any particular component of this value, it MUST be set to * zero. * * For instance, if a End User wants to specify that his date * of birth is in 1980, but not the month or day, the value * returned SHALL be "1980-00-00". */ field_dob = 8, /** * Alias to field_dob */ field_birthdate = field_dob, /** * The End User's gender, "M" for male, "F" for female. */ field_gender = 16, /** * Alias to field_gender */ field_sex = field_gender, /** * UTF-8 string free text that SHOULD conform to the End User's * country's postal system. */ field_postcode = 32, /** * The End User's country of residence as specified by ISO3166 */ field_country = 64, /** * End User's preferred language as specified by ISO639 */ field_language = 128, /** * ASCII string from TimeZone database * * For example, "Europe/Paris" or "America/Los_Angeles". */ field_timezone = 256, /** * All fields bits combined */ fields_ALL = 511, /** * No fields */ fields_NONE = 0 }; /** * Bitmask for fields which, if absent from the response, will * prevent the Consumer from completing the registration without * End User interation. */ long fields_required; /** * Bitmask for fields that will be used by the Consumer, but whose * absence will not prevent the registration from completing. */ long fields_optional; /** * A URL which the Consumer provides to give the End User a place * to read about the how the profile data will be used. The * Identity Provider SHOULD display this URL to the End User if it * is given. */ string policy_url; /** * Bitmask for fields present in response */ long has_fields; /** * Container type for response fields values */ typedef map<fieldbit_t,string> response_t; /** * Response contents */ response_t response; /** * Fields bitmask to send in response */ long fields_response; /** * Consumer constructor. * @param fr required fields * @see fields_required * @param fo optional fields * @see fields_optional * @param pu policy url * @see policy_url */ sreg_t(long fr=fields_NONE,long fo=fields_NONE,const string& pu="") : fields_required(fr), fields_optional(fo), policy_url(pu), has_fields(0) { } /** * Implementation of consumer's checkid hook */ - virtual void checkid_hook(params_t& p,const string& identity); + virtual void checkid_hook(basic_openid_message& om); /** * Implementation of consumer's id_res hook */ - virtual void id_res_hook(const params_t& p,const params_t& sp,const string& identity); + virtual void id_res_hook(const basic_openid_message& om,const basic_openid_message& sp); /** * Implementation of server's checkid_hook */ - virtual void checkid_hook(const params_t& pin,params_t& pout); + virtual void checkid_hook(const basic_openid_message& inm,basic_openid_message& oum); /** * Check and see if we have value for some particular field. * @param fb field in question * @see fieldbit_t * @return true if the value is available */ bool has_field(fieldbit_t fb) const { return has_fields&fb; } /** * Retrieve the value for a field. * @param fb field in question * @see fieldbit_t * @return field value * @throw failed_lookup if no data avaialble */ const string& get_field(fieldbit_t fb) const; /** * Set the value for a field. * @param fb field in question * @see fieldbit_t * @param fv field value */ void set_field(fieldbit_t fb,const string& fv); /** * Remove the value for a field. * @param fb field in question * @see fieldbit_t */ void reset_field(fieldbit_t fb); /** * Reset field data */ void clear(); /** * Function called after parsing sreg request to set up response * fields. The default implementation tries to send as much fields * as we have. The function is supposed to set the data and * fields_response. * @see fields_response * @param pin input request parameters with "openid." prefix * @param pout output request parameters without "openid." prefix. * @see checkid_hook(const params_t&,params_t&) */ - virtual void setup_response(const params_t& pin,params_t& pout); + virtual void setup_response(const basic_openid_message& inm,basic_openid_message& oum); }; } #endif /* __OPKELE_SREG_H */ diff --git a/include/opkele/types.h b/include/opkele/types.h index de44a5c..d5ad258 100644 --- a/include/opkele/types.h +++ b/include/opkele/types.h @@ -1,246 +1,207 @@ #ifndef __OPKELE_TYPES_H #define __OPKELE_TYPES_H /** * @file * @brief various types declarations */ #include <ostream> #include <vector> #include <string> #include <map> #include <set> +#include <list> +#include <opkele/iterator.h> #include <opkele/tr1-mem.h> namespace opkele { using std::vector; using std::string; using std::map; using std::ostream; using std::multimap; using std::set; + using std::list; + using std::iterator; + using std::forward_iterator_tag; /** * the OpenID operation mode */ typedef enum _mode_t { mode_associate, mode_checkid_immediate, mode_checkid_setup, mode_check_association } mode_t; /** * the association secret container */ class secret_t : public vector<unsigned char> { public: /** * xor the secret and hmac together and encode, using base64 * @param key_d pointer to the message digest * @param rv reference to the return value */ void enxor_to_base64(const unsigned char *key_d,string& rv) const; /** * decode base64-encoded secret and xor it with the message digest * @param key_d pointer to the message digest * @param b64 base64-encoded secret value */ void enxor_from_base64(const unsigned char *key_d,const string& b64); /** * plainly encode to base64 representation * @param rv reference to the return value */ void to_base64(string& rv) const; /** * decode cleartext secret from base64 * @param b64 base64-encoded representation of the secret value */ void from_base64(const string& b64); }; /** * Interface to the association. */ class association_t { public: virtual ~association_t() { } /** * retrieve the server with which association was established. * @return server name */ virtual string server() const = 0; /** * retrieve the association handle. * @return handle */ virtual string handle() const = 0; /** * retrieve the association type. * @return association type */ virtual string assoc_type() const = 0; /** * retrieve the association secret. * @return association secret */ virtual secret_t secret() const = 0; /** * retrieve the number of seconds the association expires in. * @return seconds till expiration */ virtual int expires_in() const = 0; /** * check whether the association is stateless. * @return true if stateless */ virtual bool stateless() const = 0; /** * check whether the association is expired. * @return true if expired */ virtual bool is_expired() const = 0; }; /** * the shared_ptr<> for association_t object type */ typedef tr1mem::shared_ptr<association_t> assoc_t; + class basic_openid_message { + public: + typedef list<string> fields_t; + typedef util::forward_iterator_proxy< + string,const string&,const string* + > fields_iterator; + + basic_openid_message() { } + basic_openid_message(const basic_openid_message& x); + void copy_to(basic_openid_message& x) const; + + virtual bool has_field(const string& n) const = 0; + virtual const string& get_field(const string& n) const = 0; + + virtual bool has_ns(const string& uri) const; + virtual string get_ns(const string& uri) const; + + virtual fields_iterator fields_begin() const = 0; + virtual fields_iterator fields_end() const = 0; + + virtual string append_query(const string& url) const; + virtual string query_string() const; + + + virtual void reset_fields(); + virtual void set_field(const string& n,const string& v); + virtual void reset_field(const string& n); + + virtual void from_keyvalues(const string& kv); + + void add_to_signed(const string& fields); + string find_ns(const string& uri,const char *pfx) const; + string allocate_ns(const string& uri,const char *pfx); + }; + + class openid_message_t : public basic_openid_message, public map<string,string> { + public: + openid_message_t() { } + openid_message_t(const basic_openid_message& x) + : basic_openid_message(x) { } + + void copy_to(basic_openid_message& x) const; + + bool has_field(const string& n) const; + const string& get_field(const string& n) const; + virtual fields_iterator fields_begin() const; + virtual fields_iterator fields_end() const; + + void reset_fields(); + void set_field(const string& n,const string& v); + void reset_field(const string& n); + }; + /** * request/response parameters map */ - class params_t : public map<string,string> { + class params_t : public openid_message_t { public: /** * check whether the parameter is present. * @param n the parameter name * @return true if yes */ - bool has_param(const string& n) const; + bool has_param(const string& n) const { + return has_field(n); } /** * retrieve the parameter (const version) * @param n the parameter name * @return the parameter value * @throw failed_lookup if there is no such parameter */ - const string& get_param(const string& n) const; - /** - * retrieve the parameter. - * @param n the parameter name - * @return the parameter value - * @throw failed_lookup if there is no such parameter - */ - string& get_param(const string& n); + const string& get_param(const string& n) const { + return get_field(n); } /** * parse the OpenID key/value data. * @param kv the OpenID key/value data */ - void parse_keyvalues(const string& kv); - /** - * sign the fields. - * @param secret the secret used for signing - * @param sig reference to the string, containing base64-encoded - * result - * @param slist the comma-separated list of fields to sign - * @param prefix the string to prepend to parameter names - */ - void sign(secret_t secret,string& sig,const string& slist,const char *prefix=0) const; + void parse_keyvalues(const string& kv) { + from_keyvalues(kv); } - /** - * append parameters to the URL as a GET-request parameters. - * @param url the base URL - * @param prefix the string to prepend to parameter names - * @return the ready-to-use location - */ string append_query(const string& url,const char *prefix = "openid.") const; - /** - * make up a query string suitable for use in GET and POST - * requests. - * @param prefix string to prened to parameter names - * @return query string - */ - string query_string(const char *prefix = "openid.") const; - }; - - /** - * dump the key/value pairs for the parameters to the stream. - * @param o output stream - * @param p the parameters - */ - ostream& operator << (ostream& o,const params_t& p); - - namespace xrd { - - struct priority_compare { - inline bool operator()(long a,long b) const { - return (a<0) ? false : (b<0) ? true : (a<b); - } - }; - - template <typename _DT> - class priority_map : public multimap<long,_DT,priority_compare> { - typedef multimap<long,_DT,priority_compare> map_type; - public: - - inline _DT& add(long priority,const _DT& d) { - return insert(typename map_type::value_type(priority,d))->second; - } }; - typedef priority_map<string> canonical_ids_t; - typedef priority_map<string> local_ids_t; - typedef set<string> types_t; - typedef priority_map<string> uris_t; - - class service_t { - public: - types_t types; - uris_t uris; - local_ids_t local_ids; - string provider_id; - - void clear() { - types.clear(); - uris.clear(); local_ids.clear(); - provider_id.clear(); - } - }; - typedef priority_map<service_t> services_t; - - class XRD_t { - public: - time_t expires; - - canonical_ids_t canonical_ids; - local_ids_t local_ids; - services_t services; - string provider_id; - - void clear() { - expires = 0; - canonical_ids.clear(); local_ids.clear(); - services.clear(); - provider_id.clear(); - } - bool empty() const { - return - canonical_ids.empty() - && local_ids.empty() - && services.empty(); - } - - }; - - } - } #endif /* __OPKELE_TYPES_H */ diff --git a/include/opkele/util.h b/include/opkele/util.h index 085c9e6..e9176b0 100644 --- a/include/opkele/util.h +++ b/include/opkele/util.h @@ -1,143 +1,151 @@ #ifndef __OPKELE_UTIL_H #define __OPKELE_UTIL_H #include <time.h> #include <string> #include <vector> #include <openssl/bn.h> #include <openssl/dh.h> +#include <opkele/types.h> namespace opkele { using std::string; using std::vector; /** * @brief opkele utils namespace */ namespace util { /** * Convenience class encapsulating SSL BIGNUM object for the purpose of * automatical freeing. */ class bignum_t { public: BIGNUM *_bn; bignum_t() : _bn(0) { } bignum_t(BIGNUM *bn) : _bn(bn) { } ~bignum_t() throw() { if(_bn) BN_free(_bn); } bignum_t& operator=(BIGNUM *bn) { if(_bn) BN_free(_bn); _bn = bn; return *this; } operator const BIGNUM*(void) const { return _bn; } operator BIGNUM*(void) { return _bn; } }; /** * Convenience clas encapsulating SSL DH object for the purpose of * automatic freeing. */ class dh_t { public: DH *_dh; dh_t() : _dh(0) { } dh_t(DH *dh) : _dh(dh) { } ~dh_t() throw() { if(_dh) DH_free(_dh); } dh_t& operator=(DH *dh) { if(_dh) DH_free(_dh); _dh = dh; return *this; } operator const DH*(void) const { return _dh; } operator DH*(void) { return _dh; } DH* operator->() { return _dh; } const DH* operator->() const { return _dh; } }; /** * Convert base64-encoded SSL BIGNUM to internal representation. * @param b64 base64-encoded number * @return SSL BIGNUM * @throw failed_conversion in case of error */ BIGNUM *base64_to_bignum(const string& b64); /** * Convert decimal representation to SSL BIGNUM. * @param dec decimal representation * @return resulting BIGNUM * @throw failed_conversion in case of error */ BIGNUM *dec_to_bignum(const string& dec); /** * Convert SSL BIGNUM data to base64 encoded string. * @param bn BIGNUM * @return base64encoded string */ string bignum_to_base64(const BIGNUM *bn); /** * Convert internal time representation to w3c format * @param t internal representation * @return w3c time * @throw failed_conversion in case of error */ string time_to_w3c(time_t t); /** * Convert W3C time representation to internal time_t * @param w w3c representation * @return converted time * @throw failed_conversion in case of error */ time_t w3c_to_time(const string& w); /** * Encode string to the representation suitable for using in URL. * @param str string to encode * @return encoded string * @throw failed_conversion in case of failure */ string url_encode(const string& str); /** * Convert number to string * @param l number * @return string representation * @throw failed_conversion in case of failure */ string long_to_string(long l); /** * Convert string to number * @param s string, containing the number * @return the number * @throw failed_conversion in case of failure */ long string_to_long(const string& s); /** * Encode binary data using base64. * @param data pointer to binary data * @param length length of data * @return encoded data */ string encode_base64(const void *data,size_t length); /** * Decode binary data from base64 representation. * @param data base64-encoded data * @param rv container for decoded binary */ void decode_base64(const string& data,vector<unsigned char>& rv); /** * Normalize http(s) URI according to RFC3986, section 6. URI is * expected to have scheme: in front of it. * @param uri URI * @return normalized URI * @throw not_implemented in case of non-httpi(s) URI * @throw bad_input in case of malformed URI */ string rfc_3986_normalize_uri(const string& uri); + + string& strip_uri_fragment_part(string& uri); + + string abi_demangle(const char* mn); + + string base64_signature(const assoc_t& assoc,const basic_openid_message& om); + } } #endif /* __OPKELE_UTIL_H */ |