-rw-r--r-- | include/opkele/basic_op.h | 119 | ||||
-rw-r--r-- | include/opkele/verify_op.h | 2 | ||||
-rw-r--r-- | lib/basic_op.cc | 38 | ||||
-rw-r--r-- | lib/verify_op.cc | 2 | ||||
-rw-r--r-- | test/OP.cc | 2 |
5 files changed, 134 insertions, 29 deletions
diff --git a/include/opkele/basic_op.h b/include/opkele/basic_op.h index 5bba1bf..4daed02 100644 --- a/include/opkele/basic_op.h +++ b/include/opkele/basic_op.h @@ -5,13 +5,13 @@ #include <opkele/types.h> #include <opkele/extension.h> namespace opkele { using std::string; - class basic_op { + class basic_OP { public: mode_t mode; assoc_t assoc; bool openid2; string return_to; string realm; @@ -32,38 +32,143 @@ namespace opkele { bool is_id_select() const; void select_identity(const string& c,const string& i); void set_claimed_id(const string& c); + /** @name OpenID operations + * @{ + */ + /** + * Establish association with RP + * @param oum reply message + * @param inm request message + */ basic_openid_message& associate( basic_openid_message& oum, const basic_openid_message& inm); + /** + * Parse the checkid_* request. The function parses input message, + * retrieves the information needed for further processing, + * verifies what can be verified at this stage. + * @param inm incoming OpenID message + * @param ext extension/chain of extensions supported + */ void checkid_(const basic_openid_message& inm,extension_t *ext=0); + /** + * Build and sign a positive assertion message + * @param om outpu OpenID message + * @param ext extension/chain of extensions supported + * @return reference to om + */ basic_openid_message& id_res(basic_openid_message& om, extension_t *ext=0); + /** + * Build a 'cancel' negative assertion + * @param om output OpenID message + * @return reference to om + */ basic_openid_message& cancel(basic_openid_message& om); + /** + * Build an 'error' reply + * @param om output OpenID message + * @param error a human-readable message indicating the cause + * @param contact contact address for the server administrator (can be empty) + * @param reference a reference token (can be empty) + * @return reference to om + */ basic_openid_message& error(basic_openid_message& om, const string& error,const string& contact, const string& reference ); + /** + * Build a setup_needed reply to checkid_immediate request + * @param oum output OpenID message + * @param inm incoming OpenID request being processed + * @return reference to oum + */ basic_openid_message& setup_needed( basic_openid_message& oum,const basic_openid_message& inm); + /** + * Process check_authentication request + * @param oum output OpenID message + * @param inm incoming request + * @return reference to oum + */ basic_openid_message& check_authentication( basic_openid_message& oum,const basic_openid_message& inm); - + /** + * @} + */ + + /** + * Verify return_to url. The default implementation checks whether + * return_to URI matches the realm + * @throw bad_realm in case of invalid realm + * @throw bad_return_to if return_to doesn't match the realm + * @see verify_op::verify_return_to() + */ virtual void verify_return_to(); - virtual assoc_t alloc_assoc(const string& t,size_t kl,bool sl) = 0; - virtual assoc_t retrieve_assoc(const string& h) = 0; - - virtual string& alloc_nonce(string& nonce,bool sl) = 0; + /** + * @name Global persistent store API + * These functions are related to the associations with RPs storage + * and retrieval and nonce management. + * @{ + */ + /** + * Allocate association. + * @param type association type + * @param kl association key length + * @param sl true if the association is stateless + * @return association object + */ + virtual assoc_t alloc_assoc(const string& type,size_t kl,bool sl) = 0; + /** + * Retrieve valid unexpired association + * @param handle association handle + * @return association object + */ + virtual assoc_t retrieve_assoc(const string& handle) = 0; + /** + * Allocate nonce. + * @param nonce input-output parameter containing timestamp part of + * the nonce on input + * @param sl true if the nonce is + * @return reference to nonce + * @throw failed_lookup if no such valid unexpired association + * could be retrieved + */ + virtual string& alloc_nonce(string& nonce) = 0; + /** + * Check nonce validity + * @param nonce nonce to check + * @return true if nonce found and isn't yet invalidated + */ virtual bool check_nonce(const string& nonce) = 0; + /** + * Invalidate nonce + * @param nonce nonce to check + */ virtual void invalidate_nonce(const string& nonce) = 0; - + /** + * @} + */ + + /** + * @name Site particulars API + * @{ + */ + /** + * Query the absolute URL of the op endpoint + * @return fully qualified url of the OP endpoint + */ virtual const string get_op_endpoint() const = 0; + /** + * @} + */ }; } #endif /* __OPKELE_BASIC_OP_H */ diff --git a/include/opkele/verify_op.h b/include/opkele/verify_op.h index f5c97b2..6c3c386 100644 --- a/include/opkele/verify_op.h +++ b/include/opkele/verify_op.h @@ -2,13 +2,13 @@ #define __OPKELE_VERIFY_OP_H #include <opkele/basic_op.h> namespace opkele { - class verify_op : public basic_op { + class verify_op : public basic_OP { public: void verify_return_to(); }; } diff --git a/lib/basic_op.cc b/lib/basic_op.cc index 7a2dbd2..18446dc 100644 --- a/lib/basic_op.cc +++ b/lib/basic_op.cc @@ -7,61 +7,61 @@ #include <opkele/exception.h> #include <opkele/util.h> #include <opkele/uris.h> namespace opkele { - void basic_op::reset_vars() { + void basic_OP::reset_vars() { assoc.reset(); return_to.clear(); realm.clear(); claimed_id.clear(); identity.clear(); invalidate_handle.clear(); } - bool basic_op::has_return_to() const { + bool basic_OP::has_return_to() const { return !return_to.empty(); } - const string& basic_op::get_return_to() const { + const string& basic_OP::get_return_to() const { if(return_to.empty()) throw no_return_to(OPKELE_CP_ "No return_to URL provided with request"); return return_to; } - const string& basic_op::get_realm() const { + const string& basic_OP::get_realm() const { assert(!realm.empty()); return realm; } - bool basic_op::has_identity() const { + bool basic_OP::has_identity() const { return !identity.empty(); } - const string& basic_op::get_claimed_id() const { + const string& basic_OP::get_claimed_id() const { if(claimed_id.empty()) throw non_identity(OPKELE_CP_ "attempting to retrieve claimed_id of non-identity related request"); assert(!identity.empty()); return claimed_id; } - const string& basic_op::get_identity() const { + const string& basic_OP::get_identity() const { if(identity.empty()) throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related request"); assert(!claimed_id.empty()); return identity; } - bool basic_op::is_id_select() const { + bool basic_OP::is_id_select() const { return identity==IDURI_SELECT20; } - void basic_op::select_identity(const string& c,const string& i) { + void basic_OP::select_identity(const string& c,const string& i) { claimed_id = c; identity = i; } - void basic_op::set_claimed_id(const string& c) { + void basic_OP::set_claimed_id(const string& c) { claimed_id = c; } - basic_openid_message& basic_op::associate( + basic_openid_message& basic_OP::associate( basic_openid_message& oum, const basic_openid_message& inm) try { assert(inm.get_field("mode")=="associate"); util::dh_t dh; util::bignum_t c_pub; unsigned char key_digest[SHA256_DIGEST_LENGTH]; @@ -128,13 +128,13 @@ namespace opkele { oum.set_field("error_code","unsupported-type"); oum.set_field("session_type","DH-SHA256"); oum.set_field("assoc_type","HMAC-SHA256"); return oum; } - void basic_op::checkid_(const basic_openid_message& inm, + void basic_OP::checkid_(const basic_openid_message& inm, extension_t *ext) { reset_vars(); string mode = inm.get_field("mode"); if(mode=="checkid_setup") mode = mode_checkid_setup; else if(mode=="checkid_immediate") @@ -190,13 +190,13 @@ namespace opkele { "claimed_id and identity must be either both present or both absent"); } verify_return_to(); if(ext) ext->op_checkid_hook(inm); } - basic_openid_message& basic_op::id_res(basic_openid_message& om, + basic_openid_message& basic_OP::id_res(basic_openid_message& om, extension_t *ext) { assert(!return_to.empty()); assert(!is_id_select()); if(!assoc) { assoc = alloc_assoc("HMAC-SHA256",SHA256_DIGEST_LENGTH,true); } @@ -215,44 +215,44 @@ namespace opkele { om.set_field("identity",identity); om.set_field("claimed_id",claimed_id); ats += ",identity,claimed_id"; } om.set_field("return_to",return_to); string nonce = w3timestr; - om.set_field("response_nonce",alloc_nonce(nonce,assoc->stateless())); + om.set_field("response_nonce",alloc_nonce(nonce)); if(!invalidate_handle.empty()) { om.set_field("invalidate_handle",invalidate_handle); ats += ",invalidate_handle"; } om.set_field("assoc_handle",assoc->handle()); om.add_to_signed(ats); if(ext) ext->op_id_res_hook(om); om.set_field("sig",util::base64_signature(assoc,om)); return om; } - basic_openid_message& basic_op::cancel(basic_openid_message& om) { + basic_openid_message& basic_OP::cancel(basic_openid_message& om) { assert(!return_to.empty()); om.set_field("ns",OIURI_OPENID20); om.set_field("mode","cancel"); return om; } - basic_openid_message& basic_op::error(basic_openid_message& om, + basic_openid_message& basic_OP::error(basic_openid_message& om, const string& error,const string& contact, const string& reference ) { assert(!return_to.empty()); om.set_field("ns",OIURI_OPENID20); om.set_field("mode","error"); om.set_field("error",error); om.set_field("contact",contact); om.set_field("reference",reference); return om; } - basic_openid_message& basic_op::setup_needed( + basic_openid_message& basic_OP::setup_needed( basic_openid_message& oum,const basic_openid_message& inm) { assert(mode==mode_checkid_immediate); assert(!return_to.empty()); if(openid2) { oum.set_field("ns",OIURI_OPENID20); oum.set_field("mode","setup_needed"); @@ -263,13 +263,13 @@ namespace opkele { util::change_mode_message_proxy(inm,setupmode) .append_query(get_op_endpoint())); } return oum; } - basic_openid_message& basic_op::check_authentication( + basic_openid_message& basic_OP::check_authentication( basic_openid_message& oum, const basic_openid_message& inm) try { assert(inm.get_field("mode")=="check_authentication"); oum.reset_fields(); oum.set_field("ns",OIURI_OPENID20); bool o2; @@ -317,13 +317,13 @@ namespace opkele { return oum; }catch(failed_check_authentication& ) { oum.set_field("is_valid","false"); return oum; } - void basic_op::verify_return_to() { + void basic_OP::verify_return_to() { if(realm.find('#')!=string::npos) throw opkele::bad_realm(OPKELE_CP_ "authentication realm contains URI fragment"); if(!util::uri_matches_realm(return_to,realm)) throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match realm"); } diff --git a/lib/verify_op.cc b/lib/verify_op.cc index e7c26b5..0beca2d 100644 --- a/lib/verify_op.cc +++ b/lib/verify_op.cc @@ -30,13 +30,13 @@ namespace opkele { RP_verifier& operator++() { ++seen; return *this; } RP_verifier& operator++(int) { +seen; return *this; } }; void verify_op::verify_return_to() { - basic_op::verify_return_to(); + basic_OP::verify_return_to(); try { RP_verifier rpv(return_to); string drealm = realm; string::size_type csss = drealm.find("://*."); if(csss==4 || csss==5) drealm.replace(csss+3,1,"www"); @@ -158,13 +158,13 @@ class example_op_t : public opkele::verify_op { return opkele::assoc_t(new opkele::association( "", h, T.get(1,1,nc), secret, strtol(T.get(1,4,nc),0,0), strtol(T.get(1,3,nc),0,0) )); } - string& alloc_nonce(string& nonce,bool stateless) { + string& alloc_nonce(string& nonce) { uuid_t uuid; uuid_generate(uuid); nonce += opkele::util::encode_base64(uuid,sizeof(uuid)); sqlite3_mem_t<char*> S = sqlite3_mprintf( "INSERT INTO nonces" " (n_once) VALUES (%Q)", |