-rw-r--r-- | include/opkele/basic_op.h | 2 | ||||
-rw-r--r-- | include/opkele/expat.h | 16 | ||||
-rw-r--r-- | include/opkele/iterator.h | 19 | ||||
-rw-r--r-- | include/opkele/types.h | 1 | ||||
-rw-r--r-- | lib/basic_op.cc | 29 | ||||
-rw-r--r-- | lib/basic_rp.cc | 10 | ||||
-rw-r--r-- | lib/discovery.cc | 2 | ||||
-rw-r--r-- | lib/expat.cc | 1 | ||||
-rw-r--r-- | lib/extension.cc | 2 | ||||
-rw-r--r-- | lib/openid_message.cc | 32 | ||||
-rw-r--r-- | lib/prequeue_rp.cc | 4 | ||||
-rw-r--r-- | lib/sreg.cc | 6 | ||||
-rw-r--r-- | lib/verify_op.cc | 4 | ||||
-rw-r--r-- | test/OP.cc | 16 | ||||
-rw-r--r-- | test/RP.cc | 6 | ||||
-rw-r--r-- | test/kingate_openid_message.h | 4 |
16 files changed, 77 insertions, 77 deletions
diff --git a/include/opkele/basic_op.h b/include/opkele/basic_op.h index 0326508..12306dd 100644 --- a/include/opkele/basic_op.h +++ b/include/opkele/basic_op.h @@ -1,96 +1,98 @@ #ifndef __OPKELE_BASIC_OP_H #define __OPKELE_BASIC_OP_H #include <string> #include <opkele/types.h> #include <opkele/extension.h> namespace opkele { using std::string; /** * Implementation of basic OP functionality */ class basic_OP { public: /** * The request mode for the request being processed */ mode_t mode; /** * association used in transaction. reset in case of dumb operation */ assoc_t assoc; /** * true if the request is openid2 request */ bool openid2; /** * The return_to RP endpoint */ string return_to; /** * The realm we authenticate for */ string realm; /** * Claimed identifier */ string claimed_id; /** * The OP-Local identifier */ string identity; /** * The invalidate handle for the reply request */ string invalidate_handle; + virtual ~basic_OP() { } + void reset_vars(); /** * @name Request information access * Setting and retrieval of the information pertaining to the request being processed * @{ */ /** * Check if the RP expects us to get back to them. * @return true if RP supplied return_to URL */ bool has_return_to() const; /** * Find out where the RP is waiting for us. * @return the return_to URL supplied * @throw no_return_to if no return_to is supplied with the request */ const string& get_return_to() const; /** * Find out what realm we are authenticating user for * @return the realm */ const string& get_realm() const; /** * Check if request is about identity * @return true if so */ bool has_identity() const; /** * Get claimed identifier supplied with the request * @return claimed identifier * @throw non_identity if request is not about identity */ const string& get_claimed_id() const; /** * Get the identity (OP-Local identifier) being confirmed * @return identity * @throw non_identity if request is not about identity */ const string& get_identity() const; /** * Is identifier supposed to be selected on our side? * @return true if identity is a special identifier select URI */ bool is_id_select() const; diff --git a/include/opkele/expat.h b/include/opkele/expat.h index 60c41ac..3ab1630 100644 --- a/include/opkele/expat.h +++ b/include/opkele/expat.h @@ -1,91 +1,91 @@ #ifndef __OPKELE_EXPAT_H #define __OPKELE_EXPAT_H #include <cassert> #include <expat.h> namespace opkele { namespace util { class expat_t { public: XML_Parser _x; expat_t() : _x(0) { } expat_t(XML_Parser x) : _x(x) { } virtual ~expat_t() throw(); expat_t& operator=(XML_Parser x); operator const XML_Parser(void) const { return _x; } operator XML_Parser(void) { return _x; } inline bool parse(const char *s,int len,bool final=false) { assert(_x); return XML_Parse(_x,s,len,final); } - virtual void start_element(const XML_Char *n,const XML_Char **a) { } - virtual void end_element(const XML_Char *n) { } + virtual void start_element(const XML_Char * /* n */,const XML_Char ** /* a */) { } + virtual void end_element(const XML_Char * /* n */) { } void set_element_handler(); - virtual void character_data(const XML_Char *s,int l) { } + virtual void character_data(const XML_Char * /* s */,int /* l */) { } void set_character_data_handler(); - virtual void processing_instruction(const XML_Char *t,const XML_Char *d) { } + virtual void processing_instruction(const XML_Char * /* t */,const XML_Char * /* d */) { } void set_processing_instruction_handler(); - virtual void comment(const XML_Char *d) { } + virtual void comment(const XML_Char * /* d */) { } void set_comment_handler(); virtual void start_cdata_section() { } virtual void end_cdata_section() { } void set_cdata_section_handler(); - virtual void default_handler(const XML_Char *s,int l) { } + virtual void default_handler(const XML_Char * /* s */,int /* l */) { } void set_default_handler(); void set_default_handler_expand(); - virtual void start_namespace_decl(const XML_Char *p,const XML_Char *u) { } - virtual void end_namespace_decl(const XML_Char *p) { } + virtual void start_namespace_decl(const XML_Char * /* p */,const XML_Char * /* u */) { } + virtual void end_namespace_decl(const XML_Char * /* p */) { } void set_namespace_decl_handler(); inline enum XML_Error get_error_code() { assert(_x); return XML_GetErrorCode(_x); } static inline const XML_LChar *error_string(XML_Error c) { return XML_ErrorString(c); } inline long get_current_byte_index() { assert(_x); return XML_GetCurrentByteIndex(_x); } inline int get_current_line_number() { assert(_x); return XML_GetCurrentLineNumber(_x); } inline int get_current_column_number() { assert(_x); return XML_GetCurrentColumnNumber(_x); } inline void set_user_data() { assert(_x); XML_SetUserData(_x,this); } inline bool set_base(const XML_Char *b) { assert(_x); return XML_SetBase(_x,b); } inline const XML_Char *get_base() { assert(_x); return XML_GetBase(_x); } inline int get_specified_attribute_count() { assert(_x); return XML_GetSpecifiedAttributeCount(_x); } inline bool set_param_entity_parsing(enum XML_ParamEntityParsing c) { assert(_x); return XML_SetParamEntityParsing(_x,c); } inline static XML_Parser parser_create(const XML_Char *e=0) { return XML_ParserCreate(e); } inline static XML_Parser parser_create_ns(const XML_Char *e=0,XML_Char s='\t') { return XML_ParserCreateNS(e,s); } }; } } #endif /* __OPKELE_EXPAT_H */ diff --git a/include/opkele/iterator.h b/include/opkele/iterator.h index 812a786..28c1c83 100644 --- a/include/opkele/iterator.h +++ b/include/opkele/iterator.h @@ -1,217 +1,216 @@ #ifndef __OPKELE_ITERATOR_H #define __OPKELE_ITERATOR_H #include <cassert> #include <iterator> namespace opkele { namespace util { using std::iterator; using std::forward_iterator_tag; using std::output_iterator_tag; template <typename T> class basic_output_iterator_proxy_impl : public iterator<output_iterator_tag,T,void,T*,T&> { public: virtual ~basic_output_iterator_proxy_impl() { } virtual basic_output_iterator_proxy_impl<T>* dup() const = 0; basic_output_iterator_proxy_impl<T>& operator*() { return *this; }; virtual basic_output_iterator_proxy_impl<T>& operator=(const T& x) = 0; }; template<typename IT,typename T=typename IT::value_type> class output_iterator_proxy_impl : public basic_output_iterator_proxy_impl<T> { public: IT i; - output_iterator_proxy_impl(const IT& i) : i(i) { } + output_iterator_proxy_impl(const IT& _i) : i(_i) { } basic_output_iterator_proxy_impl<T>* dup() const { return new output_iterator_proxy_impl<IT,T>(i); } basic_output_iterator_proxy_impl<T>& operator=(const T& x) { - (*i) = x; - } + (*i) = x; return *this; } }; template<typename T> class output_iterator_proxy : public iterator<output_iterator_tag,T,void,T*,T&> { public: basic_output_iterator_proxy_impl<T> *I; template<typename IT> output_iterator_proxy(const IT& i) : I(new output_iterator_proxy_impl<IT,T>(i)) { } output_iterator_proxy(const output_iterator_proxy<T>& x) : I(x.I->dup()) { } ~output_iterator_proxy() { delete I; } output_iterator_proxy& operator=(const output_iterator_proxy<T>& x) { delete I; I = x.I->dup(); } output_iterator_proxy& operator*() { return *this; } output_iterator_proxy& operator=(const T& x) { - (**I) = x; } + (**I) = x; return *this; } output_iterator_proxy& operator++() { return *this; } output_iterator_proxy& operator++(int) { return *this; } }; template <typename T,typename TR=T&,typename TP=T*> class basic_forward_iterator_proxy_impl : public iterator<forward_iterator_tag,T,void,TP,TR> { public: virtual ~basic_forward_iterator_proxy_impl() { } virtual basic_forward_iterator_proxy_impl<T,TR,TP>* dup() const = 0; virtual bool operator==(const basic_forward_iterator_proxy_impl<T,TR,TP>& x) const = 0; virtual bool operator!=(const basic_forward_iterator_proxy_impl<T,TR,TP>& x) const { return !((*this)==x); } virtual TR operator*() const = 0; virtual TP operator->() const = 0; virtual void advance() = 0; }; template <typename IT> class forward_iterator_proxy_impl : public basic_forward_iterator_proxy_impl<typename IT::value_type,typename IT::reference,typename IT::pointer> { public: IT i; - forward_iterator_proxy_impl(const IT& i) : i(i) { } + forward_iterator_proxy_impl(const IT& _i) : i(_i) { } virtual basic_forward_iterator_proxy_impl<typename IT::value_type,typename IT::reference,typename IT::pointer>* dup() const { return new forward_iterator_proxy_impl<IT>(i); } virtual bool operator==(const basic_forward_iterator_proxy_impl<typename IT::value_type,typename IT::reference,typename IT::pointer>& x) const { return i==static_cast<const forward_iterator_proxy_impl<IT>*>(&x)->i; } virtual bool operator!=(const basic_forward_iterator_proxy_impl<typename IT::value_type,typename IT::reference,typename IT::pointer>& x) const { return i!=static_cast<const forward_iterator_proxy_impl<IT>*>(&x)->i; } virtual typename IT::reference operator*() const { return *i; } virtual typename IT::pointer operator->() const { return i.operator->(); } virtual void advance() { ++i; } }; template<typename T,typename TR=T&,typename TP=T*> class forward_iterator_proxy : public iterator<forward_iterator_tag,T,void,TP,TR> { public: basic_forward_iterator_proxy_impl<T,TR,TP> *I; template<typename IT> forward_iterator_proxy(const IT& i) : I(new forward_iterator_proxy_impl<IT>(i)) { } forward_iterator_proxy(const forward_iterator_proxy<T,TR,TP>& x) : I(x.I->dup()) { } ~forward_iterator_proxy() { delete I; } forward_iterator_proxy& operator=(const forward_iterator_proxy<T,TR,TP>& x) { delete I; I = x.I->dup(); } bool operator==(const forward_iterator_proxy<T,TR,TP>& x) const { return (*I)==(*(x.I)); } bool operator!=(const forward_iterator_proxy<T,TR,TP>& x) const { return (*I)!=(*(x.I)); } TR operator*() const { return **I; } TP operator->() const { return I->operator->(); } forward_iterator_proxy<T,TR,TP>& operator++() { I->advance(); return *this; } forward_iterator_proxy<T,TR,TP>& operator++(int) { forward_iterator_proxy<T,TR,TP> rv(*this); I->advance(); return rv; } }; template<typename IT> class basic_filterator : public iterator< typename IT::iterator_category, typename IT::value_type, typename IT::difference_type, typename IT::pointer, typename IT::reference> { public: IT it; IT ei; bool empty; basic_filterator() : empty(true) { } - basic_filterator(const IT& bi,const IT& ei) - : it(bi), ei(ei) { empty = (bi==ei); } + basic_filterator(const IT& _bi,const IT& _ei) + : it(_bi), ei(_ei) { empty = (it==ei); } basic_filterator(const basic_filterator<IT>& x) : it(x.it), ei(x.ei), empty(x.empty) { } virtual ~basic_filterator() { } bool operator==(const basic_filterator<IT>& x) const { return empty?x.empty:(it==x.it); } bool operator!=(const basic_filterator<IT>& x) const { return empty!=x.empty || it!=x.it; } typename IT::reference operator*() const { assert(!empty); return *it; } typename IT::pointer operator->() const { assert(!empty); return it.operator->(); } basic_filterator<IT>& operator++() { bool found = false; for(++it;!(it==ei || (found=is_interesting()));++it); if(!found) empty=true; return *this; } basic_filterator<IT> operator++(int) { basic_filterator<IT> rv(*this); ++(*this); return rv; } void prepare() { bool found = false; for(;!(it==ei || (found=is_interesting()));++it); if(!found) empty = true; } virtual bool is_interesting() const = 0; }; template<typename IT,typename T=typename IT::value_type::first_type,typename TR=T&,typename TP=T*> class map_keys_iterator : public iterator< typename IT::iterator_category, T,void,TP,TR> { public: typedef map_keys_iterator<IT,T,TR,TP> self_type; IT it; IT ei; bool empty; map_keys_iterator() : empty(true) { } - map_keys_iterator(const IT& bi, - const IT& ei) - : it(bi), ei(ei) { empty = (bi==ei); } + map_keys_iterator(const IT& _bi, + const IT& _ei) + : it(_bi), ei(_ei) { empty = (it==ei); } map_keys_iterator(const self_type& x) : it(x.it), ei(x.ei), empty(x.empty) { } bool operator==(const self_type& x) const { return empty?x.empty:(it==x.it); } bool operator!=(const self_type& x) const { return empty!=x.empty || it!=x.it; } TR operator*() const { assert(!empty); return it->first; } TP operator->() const { assert(!empty); return &(it->first); } self_type& operator++() { assert(!empty); empty=((++it)==ei); return *this; } self_type operator++(int) { self_type rv(*this); ++(*this); return rv; } }; } } #endif /* __OPKELE_ITERATOR_H */ diff --git a/include/opkele/types.h b/include/opkele/types.h index 6ab51ef..a3b657d 100644 --- a/include/opkele/types.h +++ b/include/opkele/types.h @@ -81,96 +81,97 @@ namespace opkele { * @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() { } + virtual ~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); virtual void to_keyvalues(ostream& o) const; virtual void to_htmlhiddens(ostream& o) const; 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); }; diff --git a/lib/basic_op.cc b/lib/basic_op.cc index 18446dc..2d82147 100644 --- a/lib/basic_op.cc +++ b/lib/basic_op.cc @@ -21,168 +21,165 @@ namespace opkele { return !return_to.empty(); } 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 { assert(!realm.empty()); return realm; } bool basic_OP::has_identity() const { return !identity.empty(); } 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 { 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 { return identity==IDURI_SELECT20; } 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) { claimed_id = c; } 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]; size_t d_len = 0; - enum { - sess_cleartext, sess_dh_sha1, sess_dh_sha256 - } st = sess_cleartext; string sts = inm.get_field("session_type"); string ats = inm.get_field("assoc_type"); if(sts=="DH-SHA1" || sts=="DH-SHA256") { if(!(dh = DH_new())) throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); c_pub = util::base64_to_bignum(inm.get_field("dh_consumer_public")); try { dh->p = util::base64_to_bignum(inm.get_field("dh_modulus")); }catch(failed_lookup&) { dh->p = util::dec_to_bignum(data::_default_p); } try { dh->g = util::base64_to_bignum(inm.get_field("dh_gen")); }catch(failed_lookup&) { 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; } if(sts=="DH-SHA1") { SHA1(ckptr,cklen,key_digest); d_len = SHA_DIGEST_LENGTH; }else if(sts=="DH-SHA256") { SHA256(ckptr,cklen,key_digest); d_len = SHA256_DIGEST_LENGTH; }else throw internal_error(OPKELE_CP_ "I thought I knew the session type"); }else throw unsupported(OPKELE_CP_ "Unsupported session_type"); - assoc_t assoc; + assoc_t a; if(ats=="HMAC-SHA1") - assoc = alloc_assoc(ats,SHA_DIGEST_LENGTH,true); + a = alloc_assoc(ats,SHA_DIGEST_LENGTH,true); else if(ats=="HMAC-SHA256") - assoc = alloc_assoc(ats,SHA256_DIGEST_LENGTH,true); + a = alloc_assoc(ats,SHA256_DIGEST_LENGTH,true); else throw unsupported(OPKELE_CP_ "Unsupported assoc_type"); oum.reset_fields(); oum.set_field("ns",OIURI_OPENID20); - oum.set_field("assoc_type",assoc->assoc_type()); - oum.set_field("assoc_handle",assoc->handle()); + oum.set_field("assoc_type",a->assoc_type()); + oum.set_field("assoc_handle",a->handle()); oum.set_field("expires_in",util::long_to_string(assoc->expires_in())); - secret_t secret = assoc->secret(); + secret_t secret = a->secret(); if(sts=="DH-SHA1" || sts=="DH-SHA256") { if(d_len != secret.size()) throw bad_input(OPKELE_CP_ "Association secret and session MAC are not of the same size"); oum.set_field("session_type",sts); oum.set_field("dh_server_public",util::bignum_to_base64(dh->pub_key)); string b64; secret.enxor_to_base64(key_digest,b64); oum.set_field("enc_mac_key",b64); }else /* TODO: support cleartext over encrypted connection */ throw unsupported(OPKELE_CP_ "Unsupported session type"); return oum; } catch(unsupported& u) { oum.reset_fields(); oum.set_field("ns",OIURI_OPENID20); oum.set_field("error",u.what()); 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, extension_t *ext) { reset_vars(); - string mode = inm.get_field("mode"); - if(mode=="checkid_setup") + string modestr = inm.get_field("mode"); + if(modestr=="checkid_setup") mode = mode_checkid_setup; - else if(mode=="checkid_immediate") + else if(modestr=="checkid_immediate") mode = mode_checkid_immediate; else throw bad_input(OPKELE_CP_ "Invalid checkid_* mode"); try { assoc = retrieve_assoc(invalidate_handle=inm.get_field("assoc_handle")); invalidate_handle.clear(); }catch(failed_lookup&) { } try { openid2 = (inm.get_field("ns")==OIURI_OPENID20); }catch(failed_lookup&) { openid2 = false; } try { return_to = inm.get_field("return_to"); }catch(failed_lookup&) { } if(openid2) { try { realm = inm.get_field("realm"); }catch(failed_lookup&) { try { realm = inm.get_field("trust_root"); }catch(failed_lookup&) { if(return_to.empty()) throw bad_input(OPKELE_CP_ "Both realm and return_to are unset"); realm = return_to; } } }else{ try { realm = inm.get_field("trust_root"); }catch(failed_lookup&) { if(return_to.empty()) throw bad_input(OPKELE_CP_ "Both realm and return_to are unset"); realm = return_to; } } try { identity = inm.get_field("identity"); try { claimed_id = inm.get_field("claimed_id"); }catch(failed_lookup&) { if(openid2) throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent"); claimed_id = identity; } }catch(failed_lookup&) { if(openid2 && inm.has_field("claimed_id")) @@ -193,104 +190,104 @@ namespace opkele { if(ext) ext->op_checkid_hook(inm); } 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); } time_t now = time(0); struct tm gmt; gmtime_r(&now,&gmt); char w3timestr[24]; if(!strftime(w3timestr,sizeof(w3timestr),"%Y-%m-%dT%H:%M:%SZ",&gmt)) throw failed_conversion(OPKELE_CP_ "Failed to build time string for nonce" ); om.set_field("ns",OIURI_OPENID20); om.set_field("mode","id_res"); om.set_field("op_endpoint",get_op_endpoint()); string ats = "ns,mode,op_endpoint,return_to,response_nonce," "assoc_handle,signed"; if(!identity.empty()) { 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)); 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) { 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, - const string& error,const string& contact, + const string& err,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); + om.set_field("error",err); + if(!contact.empty()) om.set_field("contact",contact); + if(!reference.empty()) om.set_field("reference",reference); return om; } 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"); }else{ oum.set_field("mode","id_res"); static const string setupmode = "checkid_setup"; oum.set_field("user_setup_url", util::change_mode_message_proxy(inm,setupmode) .append_query(get_op_endpoint())); } return oum; } 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; try { o2 = (inm.get_field("ns")==OIURI_OPENID20); }catch(failed_lookup&) { o2 = false; } string nonce; if(o2) { try { if(!check_nonce(nonce = inm.get_field("response_nonce"))) throw failed_check_authentication(OPKELE_CP_ "Invalid nonce"); }catch(failed_lookup&) { throw failed_check_authentication(OPKELE_CP_ "No nonce provided with check_authentication request"); } } try { assoc = retrieve_assoc(inm.get_field("assoc_handle")); if(!assoc->stateless()) throw failed_check_authentication(OPKELE_CP_ "Will not do check_authentication on a stateful handle"); }catch(failed_lookup&) { throw failed_check_authentication(OPKELE_CP_ "No assoc_handle or invalid assoc_handle specified with check_authentication request"); } static const string idresmode = "id_res"; try { diff --git a/lib/basic_rp.cc b/lib/basic_rp.cc index bd45d99..a0ad130 100644 --- a/lib/basic_rp.cc +++ b/lib/basic_rp.cc @@ -1,138 +1,140 @@ +#include <cassert> #include <openssl/sha.h> #include <openssl/hmac.h> #include <opkele/basic_rp.h> #include <opkele/exception.h> #include <opkele/uris.h> #include <opkele/data.h> #include <opkele/util.h> #include <opkele/curl.h> namespace opkele { static void dh_get_secret( secret_t& secret, const basic_openid_message& om, const char *exp_assoc, const char *exp_sess, util::dh_t& dh, size_t d_len, unsigned char *(*d_fun)(const unsigned char*,size_t,unsigned char*), size_t exp_s_len) try { if(om.get_field("assoc_type")!=exp_assoc || om.get_field("session_type")!=exp_sess) throw bad_input(OPKELE_CP_ "Unexpected associate response"); util::bignum_t s_pub = util::base64_to_bignum(om.get_field("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_digest[d_len]; + assert(d_len<=SHA256_DIGEST_LENGTH); + unsigned char key_digest[SHA256_DIGEST_LENGTH]; secret.enxor_from_base64((*d_fun)(ckptr,cklen,key_digest),om.get_field("enc_mac_key")); if(secret.size()!=exp_s_len) throw bad_input(OPKELE_CP_ "Secret length isn't consistent with association type"); }catch(opkele::failed_lookup& ofl) { throw bad_input(OPKELE_CP_ "Incoherent response from OP"); } OPKELE_RETHROW static void direct_request(basic_openid_message& oum,const basic_openid_message& inm,const string& OP) { util::curl_pick_t curl = util::curl_pick_t::easy_init(); if(!curl) throw exception_curl(OPKELE_CP_ "failed to initialize curl"); string request = inm.query_string(); CURLcode r; (r=curl.misc_sets()) || (r=curl.easy_setopt(CURLOPT_URL,OP.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); oum.from_keyvalues(curl.response); } assoc_t basic_RP::associate(const string& OP) { 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()"); openid_message_t req; req.set_field("ns",OIURI_OPENID20); req.set_field("mode","associate"); req.set_field("dh_modulus",util::bignum_to_base64(dh->p)); req.set_field("dh_gen",util::bignum_to_base64(dh->g)); req.set_field("dh_consumer_public",util::bignum_to_base64(dh->pub_key)); openid_message_t res; req.set_field("assoc_type","HMAC-SHA256"); req.set_field("session_type","DH-SHA256"); secret_t secret; int expires_in; try { direct_request(res,req,OP); dh_get_secret( secret, res, "HMAC-SHA256", "DH-SHA256", dh, SHA256_DIGEST_LENGTH, SHA256, SHA256_DIGEST_LENGTH ); expires_in = util::string_to_long(res.get_field("expires_in")); - }catch(exception& e) { + }catch(exception&) { try { req.set_field("assoc_type","HMAC-SHA1"); req.set_field("session_type","DH-SHA1"); direct_request(res,req,OP); dh_get_secret( secret, res, "HMAC-SHA1", "DH-SHA1", dh, SHA_DIGEST_LENGTH, SHA1, SHA_DIGEST_LENGTH ); expires_in = util::string_to_long(res.get_field("expires_in")); - }catch(bad_input& e) { + }catch(bad_input&) { throw dumb_RP(OPKELE_CP_ "OP failed to supply an association"); } } return store_assoc( OP, res.get_field("assoc_handle"), res.get_field("assoc_type"), secret, expires_in ); } basic_openid_message& basic_RP::checkid_( basic_openid_message& rv, mode_t mode, const string& return_to,const string& realm, extension_t *ext) { rv.reset_fields(); rv.set_field("ns",OIURI_OPENID20); if(mode==mode_checkid_immediate) rv.set_field("mode","checkid_immediate"); else if(mode==mode_checkid_setup) rv.set_field("mode","checkid_setup"); else throw bad_input(OPKELE_CP_ "unknown checkid_* mode"); if(realm.empty() && return_to.empty()) throw bad_input(OPKELE_CP_ "At least one of realm and return_to must be non-empty"); if(!realm.empty()) { rv.set_field("realm",realm); rv.set_field("trust_root",realm); } if(!return_to.empty()) rv.set_field("return_to",return_to); const openid_endpoint_t& ep = get_endpoint(); rv.set_field("claimed_id",ep.claimed_id); rv.set_field("identity",ep.local_id); try { rv.set_field("assoc_handle",find_assoc(ep.uri)->handle()); }catch(dumb_RP& drp) { }catch(failed_lookup& fl) { try { rv.set_field("assoc_handle",associate(ep.uri)->handle()); }catch(dumb_RP& drp) { } } OPKELE_RETHROW if(ext) ext->rp_checkid_hook(rv); return rv; } class signed_part_message_proxy : public basic_openid_message { public: const basic_openid_message& x; @@ -189,97 +191,97 @@ namespace opkele { } q = ++am; } } } void basic_RP::id_res(const basic_openid_message& om,extension_t *ext) { bool o2 = om.has_field("ns") && om.get_field("ns")==OIURI_OPENID20; if( (!o2) && om.has_field("user_setup_url")) throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided", om.get_field("user_setup_url")); string m = om.get_field("mode"); if(o2 && m=="setup_needed") throw id_res_setup(OPKELE_CP_ "setup needed, no setup url provided"); if(m=="cancel") throw id_res_cancel(OPKELE_CP_ "authentication cancelled"); bool go_dumb=false; try { string OP = o2 ?om.get_field("op_endpoint") :get_endpoint().uri; assoc_t assoc = retrieve_assoc( OP,om.get_field("assoc_handle")); if(om.get_field("sig")!=util::base64_signature(assoc,om)) throw id_res_mismatch(OPKELE_CP_ "signature mismatch"); }catch(dumb_RP& drp) { go_dumb=true; }catch(failed_lookup& e) { go_dumb=true; } OPKELE_RETHROW if(go_dumb) { try { string OP = o2 ?om.get_field("op_endpoint") :get_endpoint().uri; check_authentication(OP,om); }catch(failed_check_authentication& fca) { throw id_res_failed(OPKELE_CP_ "failed to check_authentication()"); } OPKELE_RETHROW } signed_part_message_proxy signeds(om); if(o2) { check_nonce(om.get_field("op_endpoint"), om.get_field("response_nonce")); static const char *mustsign[] = { "op_endpoint", "return_to", "response_nonce", "assoc_handle", "claimed_id", "identity" }; - for(int ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) { + for(size_t ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) { if(om.has_field(mustsign[ms]) && !signeds.has_field(mustsign[ms])) throw bad_input(OPKELE_CP_ string("Field '")+mustsign[ms]+"' is not signed against the specs"); } if( ( (om.has_field("claimed_id")?1:0) ^ (om.has_field("identity")?1:0) )&1 ) throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent"); string turl = util::rfc_3986_normalize_uri(get_this_url()); util::strip_uri_fragment_part(turl); string rurl = util::rfc_3986_normalize_uri(om.get_field("return_to")); util::strip_uri_fragment_part(rurl); string::size_type tq = turl.find('?'), rq = rurl.find('?'); if( ((tq==string::npos)?turl:turl.substr(0,tq)) != ((rq==string::npos)?rurl:rurl.substr(0,rq)) ) throw id_res_bad_return_to(OPKELE_CP_ "return_to url doesn't match request url"); map<string,string> tp; parse_query(turl,tq,tp); map<string,string> rp; parse_query(rurl,rq,rp); for(map<string,string>::const_iterator rpi=rp.begin();rpi!=rp.end();++rpi) { map<string,string>::const_iterator tpi = tp.find(rpi->first); if(tpi==tp.end()) throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to is missing from the request"); if(tpi->second!=rpi->second) throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to doesn't matche the request"); } if(om.has_field("claimed_id")) { verify_OP( om.get_field("op_endpoint"), om.get_field("claimed_id"), om.get_field("identity") ); } } if(ext) ext->rp_id_res_hook(om,signeds); } void basic_RP::check_authentication(const string& OP, const basic_openid_message& om){ openid_message_t res; static const string checkauthmode = "check_authentication"; direct_request(res,util::change_mode_message_proxy(om,checkauthmode),OP); diff --git a/lib/discovery.cc b/lib/discovery.cc index 6f58339..6f9926c 100644 --- a/lib/discovery.cc +++ b/lib/discovery.cc @@ -285,97 +285,97 @@ namespace opkele { } void html2xrd(endpoint_discovery_iterator& oi,idiscovery_t& id) { XRD_t& x = id.xrd; if(!html_openid2.uris.empty()) { html_openid2.types.insert(STURI_OPENID20); x.services.add(-1,html_openid2); queue_endpoints(oi,id,&op_service_types[st_index_2]); } if(!html_openid1.uris.empty()) { html_openid1.types.insert(STURI_OPENID11); x.services.add(-1,html_openid1); queue_endpoints(oi,id,&op_service_types[st_index_1]); } } size_t write(void *p,size_t s,size_t nm) { /* TODO: limit total size */ size_t bytes = s*nm; const char *inbuf = (const char*)p; if(xmode&xmode_html) { size_t mbts = save_html.capacity()-save_html.size(); size_t bts = 0; if(mbts>0) { bts = (bytes>mbts)?mbts:bytes; save_html.append(inbuf,bts); } if(skipping<0) return bts; } if(skipping<0) return 0; bool rp = parse(inbuf,bytes,false); if(!rp) { parser_choked = true; skipping = -1; if(!(xmode&xmode_html)) bytes = 0; } return bytes; } size_t header(void *p,size_t s,size_t nm) { size_t bytes = s*nm; const char *h = (const char*)p; const char *colon = (const char*)memchr(p,':',bytes); const char *space = (const char*)memchr(p,' ',bytes); if(space && ( (!colon) || space<colon ) ) { xrds_location.clear(); http_content_type.clear(); }else if(colon) { const char *hv = ++colon; - int hnl = colon-h; + size_t hnl = colon-h; int rb; for(rb = bytes-hnl-1;rb>0 && isspace(*hv);++hv,--rb); while(rb>0 && isspace(hv[rb-1])) --rb; if(rb) { if( (hnl>=sizeof(XRDS_HEADER)) && !strncasecmp(h,XRDS_HEADER":", sizeof(XRDS_HEADER)) ) { xrds_location.assign(hv,rb); }else if( (hnl>=sizeof(CT_HEADER)) && !strncasecmp(h,CT_HEADER":", sizeof(CT_HEADER)) ) { const char *sc = (const char*)memchr( hv,';',rb); http_content_type.assign(hv,sc?(sc-hv):rb); } } } return curl_t::header(p,s,nm); } void start_element(const XML_Char *n,const XML_Char **a) { if(skipping<0) return; if(skipping) { if(xmode&xmode_html) html_start_element(n,a); ++skipping; return; } if(pt_stack.empty()) { if(is_qelement(n,NSURI_XRDS "\tXRDS")) return; if(is_qelement(n,NSURI_XRD "\tXRD")) { assert(xrd); xrd->clear(); pt_stack.push_back(n); }else if(xmode&xmode_html) { html_start_element(n,a); }else{ skipping = -1; } }else{ int pt_s = pt_stack.size(); if(pt_s==1) { if(is_qelement(n,NSURI_XRD "\tCanonicalID")) { assert(xrd); cdata = &(xrd->canonical_ids.add(element_priority(a),string())); }else if(is_qelement(n,NSURI_XRD "\tLocalID")) { assert(xrd); cdata = &(xrd->local_ids.add(element_priority(a),string())); diff --git a/lib/expat.cc b/lib/expat.cc index fa6fdde..c4dab7e 100644 --- a/lib/expat.cc +++ b/lib/expat.cc @@ -1,63 +1,64 @@ #include <opkele/expat.h> namespace opkele { namespace util { expat_t::~expat_t() throw() { if(_x) XML_ParserFree(_x); } expat_t& expat_t::operator=(XML_Parser x) { if(_x) XML_ParserFree(_x); _x = x; + return *this; } static void _start_element(void* ud,const XML_Char *n,const XML_Char **a) { ((expat_t*)ud)->start_element(n,a); } static void _end_element(void *ud,const XML_Char *n) { ((expat_t*)ud)->end_element(n); } void expat_t::set_element_handler() { assert(_x); XML_SetElementHandler(_x,_start_element,_end_element); } static void _character_data(void *ud,const XML_Char *s,int l) { ((expat_t*)ud)->character_data(s,l); } void expat_t::set_character_data_handler() { assert(_x); XML_SetCharacterDataHandler(_x,_character_data); } static void _processing_instruction(void *ud,const XML_Char *t,const XML_Char *d) { ((expat_t*)ud)->processing_instruction(t,d); } void expat_t::set_processing_instruction_handler() { assert(_x); XML_SetProcessingInstructionHandler(_x,_processing_instruction); } static void _comment(void *ud,const XML_Char *d) { ((expat_t*)ud)->comment(d); } void expat_t::set_comment_handler() { assert(_x); XML_SetCommentHandler(_x,_comment); } static void _start_cdata_section(void *ud) { ((expat_t*)ud)->start_cdata_section(); } static void _end_cdata_section(void *ud) { ((expat_t*)ud)->end_cdata_section(); } diff --git a/lib/extension.cc b/lib/extension.cc index f7aaea5..0f121ca 100644 --- a/lib/extension.cc +++ b/lib/extension.cc @@ -1,26 +1,26 @@ #include <opkele/exception.h> #include <opkele/extension.h> namespace opkele { void extension_t::rp_checkid_hook(basic_openid_message&) { throw not_implemented(OPKELE_CP_ "RP checkid_* hook not implemented"); } void extension_t::rp_id_res_hook(const basic_openid_message&, const basic_openid_message&) { throw not_implemented(OPKELE_CP_ "RP id_res hook not implemented"); } void extension_t::op_checkid_hook(const basic_openid_message&) { throw not_implemented(OPKELE_CP_ "OP checkid_* hook not implemented"); } - void extension_t::op_id_res_hook(basic_openid_message& om) { + void extension_t::op_id_res_hook(basic_openid_message&) { throw not_implemented(OPKELE_CP_ "OP id_res hook not implemented"); } void extension_t::checkid_hook(basic_openid_message&) { throw not_implemented(OPKELE_CP_ "deprecated consumer checkid_* hook not implemented"); } void extension_t::id_res_hook(const basic_openid_message&, const basic_openid_message&) { throw not_implemented(OPKELE_CP_ "deprecated consumer id_res hook not implemented"); } void extension_t::checkid_hook(const basic_openid_message&,basic_openid_message&) { throw not_implemented(OPKELE_CP_ "deprecated server checkid hook not implemented"); } } diff --git a/lib/openid_message.cc b/lib/openid_message.cc index fdb4b04..521ea85 100644 --- a/lib/openid_message.cc +++ b/lib/openid_message.cc @@ -1,216 +1,216 @@ #include <cassert> #include <opkele/types.h> #include <opkele/exception.h> #include <opkele/util.h> #include <opkele/debug.h> #include "config.h" namespace opkele { using std::input_iterator_tag; using std::unary_function; struct __om_copier : public unary_function<const string&,void> { public: const basic_openid_message& from; basic_openid_message& to; - __om_copier(basic_openid_message& to,const basic_openid_message& from) - : from(from), to(to) { + __om_copier(basic_openid_message& t,const basic_openid_message& f) + : from(f), to(t) { to.reset_fields(); } result_type operator()(argument_type f) { to.set_field(f,from.get_field(f)); } }; basic_openid_message::basic_openid_message(const basic_openid_message& x) { x.copy_to(*this); } void basic_openid_message::copy_to(basic_openid_message& x) const { for_each(fields_begin(),fields_end(), __om_copier(x,*this) ); } struct __om_ns_finder : public unary_function<const string&,bool> { public: const basic_openid_message& om; const string& uri; - __om_ns_finder(const basic_openid_message& om, - const string& uri) : om(om), uri(uri) { } + __om_ns_finder(const basic_openid_message& m, + const string& u) : om(m), uri(u) { } result_type operator()(argument_type f) { return (!strncmp(f.c_str(),"ns.",sizeof("ns.")-1)) && om.get_field(f)==uri ; } }; bool basic_openid_message::has_ns(const string& uri) const { fields_iterator ei = fields_end(); fields_iterator i = find_if(fields_begin(),fields_end(), __om_ns_finder(*this,uri)); return !(i==ei); } string basic_openid_message::get_ns(const string& uri) const { fields_iterator ei = fields_end(); fields_iterator i = find_if(fields_begin(),fields_end(), __om_ns_finder(*this,uri)); if(i==ei) throw failed_lookup(OPKELE_CP_ string("failed to find namespace ")+uri); return i->substr(3); } struct __om_query_builder : public unary_function<const string&,void> { public: const basic_openid_message& om; - string& rv; bool first; + string& rv; - __om_query_builder(string& rv,const basic_openid_message& om) - : om(om), first(true), rv(rv) { + __om_query_builder(string& r,const basic_openid_message& m) + : om(m), first(true), rv(r) { for_each(om.fields_begin(),om.fields_end(),*this); } - __om_query_builder(string& rv,const basic_openid_message& om,const string& url) - : om(om), first(true), rv(rv) { - rv = url; + __om_query_builder(string& r,const basic_openid_message& m,const string& u) + : om(m), first(true), rv(r) { + rv = u; if(rv.find('?')==string::npos) rv += '?'; else first = false; for_each(om.fields_begin(),om.fields_end(),*this); } result_type operator()(argument_type f) { if(first) first = false; else rv += '&'; rv += "openid."; rv+= f; rv += '='; rv += util::url_encode(om.get_field(f)); } }; string basic_openid_message::append_query(const string& url) const { string rv; return __om_query_builder(rv,*this,url).rv; } string basic_openid_message::query_string() const { string rv; return __om_query_builder(rv,*this).rv; } void basic_openid_message::reset_fields() { throw not_implemented(OPKELE_CP_ "reset_fields() not implemented"); } - void basic_openid_message::set_field(const string& n,const string& v) { + void basic_openid_message::set_field(const string&,const string&) { throw not_implemented(OPKELE_CP_ "set_field() not implemented"); } - void basic_openid_message::reset_field(const string& n) { + void basic_openid_message::reset_field(const string&) { throw not_implemented(OPKELE_CP_ "reset_field() not implemented"); } void basic_openid_message::from_keyvalues(const string& kv) { reset_fields(); string::size_type p = 0; while(true) { string::size_type co = kv.find(':',p); if(co==string::npos) break; #ifndef POSTELS_LAW string::size_type nl = kv.find('\n',co+1); if(nl==string::npos) throw bad_input(OPKELE_CP_ "malformed input"); if(nl>co) insert(value_type(kv.substr(p,co-p),kv.substr(co+1,nl-co-1))); p = nl+1; #else /* POSTELS_LAW */ string::size_type lb = kv.find_first_of("\r\n",co+1); if(lb==string::npos) { set_field(kv.substr(p,co-p),kv.substr(co+1)); break; } if(lb>co) set_field(kv.substr(p,co-p),kv.substr(co+1,lb-co-1)); string::size_type nolb = kv.find_first_not_of("\r\n",lb); if(nolb==string::npos) break; p = nolb; #endif /* POSTELS_LAW */ } } struct __om_kv_outputter : public unary_function<const string&,void> { public: const basic_openid_message& om; ostream& os; - __om_kv_outputter(const basic_openid_message& om,ostream& os) - : om(om), os(os) { } + __om_kv_outputter(const basic_openid_message& m,ostream& s) + : om(m), os(s) { } result_type operator()(argument_type f) { os << f << ':' << om.get_field(f) << '\n'; } }; void basic_openid_message::to_keyvalues(ostream& o) const { for_each(fields_begin(),fields_end(),__om_kv_outputter(*this,o)); } struct __om_html_outputter : public unary_function<const string&,void> { public: const basic_openid_message& om; ostream& os; - __om_html_outputter(const basic_openid_message& om,ostream& os) - : om(om), os(os) { } + __om_html_outputter(const basic_openid_message& m,ostream& s) + : om(m), os(s) { } result_type operator()(argument_type f) { os << "<input type=\"hidden\"" " name=\"" << util::attr_escape(f) << "\"" " value=\"" << util::attr_escape(om.get_field(f)) << "\" />"; } }; void basic_openid_message::to_htmlhiddens(ostream& o) const { for_each(fields_begin(),fields_end(),__om_html_outputter(*this,o)); } void basic_openid_message::add_to_signed(const string& fields) { string::size_type fnc = fields.find_first_not_of(","); if(fnc==string::npos) throw bad_input(OPKELE_CP_ "Trying to add nothing in particular to the list of signed fields"); string signeds; try { signeds = get_field("signed"); string::size_type lnc = signeds.find_last_not_of(","); if(lnc==string::npos) signeds.assign(fields,fnc,fields.size()-fnc); else{ string::size_type ss = signeds.size(); if(lnc==(ss-1)) { signeds+= ','; signeds.append(fields,fnc,fields.size()-fnc); }else{ if(lnc<(ss-2)) signeds.replace(lnc+2,ss-lnc-2, fields,fnc,fields.size()-fnc); else signeds.append(fields,fnc,fields.size()-fnc); } } }catch(failed_lookup&) { signeds.assign(fields,fnc,fields.size()-fnc); } set_field("signed",signeds); } string basic_openid_message::find_ns(const string& uri,const char *pfx) const { if(has_field("ns")) return get_ns(uri); return pfx; } string basic_openid_message::allocate_ns(const string& uri,const char *pfx) { diff --git a/lib/prequeue_rp.cc b/lib/prequeue_rp.cc index e242f87..3aa960f 100644 --- a/lib/prequeue_rp.cc +++ b/lib/prequeue_rp.cc @@ -10,72 +10,72 @@ #include <opkele/curl.h> #include <opkele/debug.h> namespace opkele { class __OP_verifier_good_input : public exception { public: __OP_verifier_good_input(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; class OP_verifier : public iterator<output_iterator_tag,openid_endpoint_t,void> { public: const string& OP; const string& id; OP_verifier(const string& o,const string& i) : OP(o), id(i) { } OP_verifier& operator*() { return *this; } OP_verifier& operator=(const openid_endpoint_t& oep) { if(oep.uri==OP) { if(oep.claimed_id==IDURI_SELECT20 || oep.local_id==IDURI_SELECT20 ) throw bad_input(OPKELE_CP_ "claimed_id is an OP-Id"); if(oep.local_id==id) throw __OP_verifier_good_input(OPKELE_CP_ "Found corresponding endpoint"); } return *this; } OP_verifier& operator++() { return *this; } OP_verifier& operator++(int) { return *this; } }; void prequeue_RP::verify_OP(const string& OP,const string& claimed_id,const string& identity) const { try { idiscover(OP_verifier(OP,identity),claimed_id); throw id_res_unauthorized(OPKELE_CP_ "OP is not authorized to make an assertion regarding the identity"); }catch(__OP_verifier_good_input& ovgi) { } } class endpoint_queuer : public iterator<output_iterator_tag,openid_endpoint_t,void> { public: prequeue_RP& rp; - endpoint_queuer(prequeue_RP& rp) : rp(rp) { } + endpoint_queuer(prequeue_RP& r) : rp(r) { } endpoint_queuer& operator*() { return *this; } endpoint_queuer& operator=(const openid_endpoint_t& oep) { rp.queue_endpoint(oep); return *this; } endpoint_queuer& operator++() { return *this; } endpoint_queuer& operator++(int) { return *this; } }; void prequeue_RP::initiate(const string& usi) { begin_queueing(); set_normalized_id( idiscover(endpoint_queuer(*this),usi) ); end_queueing(); } - void prequeue_RP::set_normalized_id(const string& nid) { + void prequeue_RP::set_normalized_id(const string&) { } const string prequeue_RP::get_normalized_id() const { throw not_implemented(OPKELE_CP_ "get_normalized_id() is not implemented"); } } diff --git a/lib/sreg.cc b/lib/sreg.cc index b40cd45..0bd4d2e 100644 --- a/lib/sreg.cc +++ b/lib/sreg.cc @@ -10,102 +10,100 @@ namespace opkele { const char *fieldname; sreg_t::fieldbit_t fieldbit; } fields[] = { { "nickname", sreg_t::field_nickname }, { "email", sreg_t::field_email }, { "fullname", sreg_t::field_fullname }, { "dob", sreg_t::field_dob }, { "gender", sreg_t::field_gender }, { "postcode", sreg_t::field_postcode }, { "country", sreg_t::field_country }, { "language", sreg_t::field_language }, { "timezone", sreg_t::field_timezone } }; # define fields_BEGIN fields # define fields_END &fields[sizeof(fields)/sizeof(*fields)] typedef const struct _sreg_field *fields_iterator; bool operator==(const struct _sreg_field& fd,const string& fn) { return fd.fieldname==fn; } void sreg_t::rp_checkid_hook(basic_openid_message& om) { string fr, fo; for(fields_iterator f=fields_BEGIN;f<fields_END;++f) { if(f->fieldbit&fields_required) { if(!fr.empty()) fr+=","; fr += f->fieldname; } if(f->fieldbit&fields_optional) { if(!fo.empty()) fo+=","; fo += f->fieldname; } } string pfx = om.allocate_ns(OIURI_SREG11,"sreg"); if(!fr.empty()) om.set_field(pfx+".required",fr); if(!fo.empty()) om.set_field(pfx+".optional",fo); if(!policy_url.empty()) om.set_field(pfx+".policy_url",policy_url); } void sreg_t::checkid_hook(basic_openid_message& om) { rp_checkid_hook(om); } void sreg_t::rp_id_res_hook(const basic_openid_message& om, const basic_openid_message& sp) { clear(); string pfx; try { pfx = om.find_ns(OIURI_SREG11,"sreg"); - }catch(failed_lookup& fl) { + }catch(failed_lookup&) { try { pfx = om.find_ns(OIURI_SREG10,"sreg"); - }catch(failed_lookup& fl) { - return; - } + }catch(failed_lookup&) { return; } } pfx += '.'; for(fields_iterator f=fields_BEGIN;f<fields_END;++f) { string fn = pfx; fn+=f->fieldname; if(!sp.has_field(fn)) continue; has_fields |= f->fieldbit; response[f->fieldbit]=sp.get_field(fn); } } void sreg_t::id_res_hook(const basic_openid_message& om, const basic_openid_message& sp) { rp_id_res_hook(om,sp); } const string& sreg_t::get_field(fieldbit_t fb) const { response_t::const_iterator i = response.find(fb); if(i==response.end()) throw failed_lookup(OPKELE_CP_ "no field data available"); return i->second; } void sreg_t::set_field(fieldbit_t fb,const string& fv) { response[fb] = fv; has_fields |= fb; } void sreg_t::reset_field(fieldbit_t fb) { has_fields &= ~fb; response.erase(fb); } void sreg_t::clear() { has_fields = 0; response.clear(); } static long fields_list_to_bitmask(string& fl) { long rv = 0; while(!fl.empty()) { string::size_type co = fl.find(','); string fn; if(co==string::npos) { fn = fl; fl.erase(); }else{ fn = fl.substr(0,co); fl.erase(0,co+1); } fields_iterator f = find(fields_BEGIN,fields_END,fn); if(f!=fields_END) rv |= f->fieldbit; diff --git a/lib/verify_op.cc b/lib/verify_op.cc index ab21b4f..c493c12 100644 --- a/lib/verify_op.cc +++ b/lib/verify_op.cc @@ -1,53 +1,53 @@ #include <opkele/verify_op.h> #include <opkele/discovery.h> #include <opkele/exception.h> #include <opkele/util.h> #include <opkele/uris.h> namespace opkele { using std::output_iterator_tag; class __RP_verifier_good_input : public exception { public: __RP_verifier_good_input(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; class RP_verifier : public iterator<output_iterator_tag,openid_endpoint_t,void> { public: - int seen; const string& return_to; + int seen; RP_verifier(const string& rt) : return_to(rt), seen(0) { } RP_verifier& operator*() { return *this; } RP_verifier& operator=(const openid_endpoint_t& oep) { if(util::uri_matches_realm(return_to,oep.uri)) throw __RP_verifier_good_input(OPKELE_CP_ "Found matching realm"); return *this; } RP_verifier& operator++() { ++seen; return *this; } - RP_verifier& operator++(int) { +seen; return *this; } + RP_verifier& operator++(int) { ++seen; return *this; } }; void verify_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"); const char *rtt[] = { STURI_OPENID20_RT, 0 }; yadiscover(rpv,drealm,rtt,false); if(rpv.seen) throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match any found while doing discovery on RP"); }catch(__RP_verifier_good_input&) { }catch(bad_return_to& brt) { throw; }catch(exception_network&) { } } } @@ -14,98 +14,98 @@ using namespace std; #include <opkele/association.h> #include <opkele/debug.h> #include <opkele/verify_op.h> #include <opkele/sreg.h> #include "sqlite.h" #include "kingate_openid_message.h" static const string get_self_url(const kingate::cgi_gateway& gw) { bool s = gw.has_meta("SSL_PROTOCOL_VERSION"); string rv = s?"https://":"http://"; rv += gw.http_request_header("Host"); const string& port = gw.get_meta("SERVER_PORT"); if( port!=(s?"443":"80") ) { rv += ':'; rv += port; } rv += gw.get_meta("REQUEST_URI"); string::size_type q = rv.find('?'); if(q!=string::npos) rv.erase(q); return rv; } class opdb_t : public sqlite3_t { public: opdb_t() : sqlite3_t("/tmp/OP.db") { assert(_D); char **resp; int nr,nc; char *errm; if(sqlite3_get_table( _D, "SELECT a_op FROM assoc LIMIT 0", &resp,&nr,&nc,&errm)!=SQLITE_OK) { extern const char *__OP_db_bootstrap; DOUT_("Bootstrapping DB"); if(sqlite3_exec(_D,__OP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK) throw opkele::exception(OPKELE_CP_ string("Failed to boostrap SQLite database: ")+errm); }else sqlite3_free_table(resp); } }; class example_op_t : public opkele::verify_OP { public: kingate::cgi_gateway& gw; opdb_t db; kingate::cookie htc; - example_op_t(kingate::cgi_gateway& gw) - : gw(gw) { + example_op_t(kingate::cgi_gateway& g) + : gw(g) { try { htc = gw.cookies.get_cookie("htop_session"); sqlite3_mem_t<char*> S = sqlite3_mprintf( "SELECT 1 FROM ht_sessions WHERE hts_id=%Q", htc.get_value().c_str()); sqlite3_table_t T; int nr,nc; db.get_table(S,T,&nr,&nc); if(nr<1) throw kingate::exception_notfound(CODEPOINT,"forcing cookie generation"); }catch(kingate::exception_notfound& kenf) { uuid_t uuid; uuid_generate(uuid); htc = kingate::cookie("htop_session",opkele::util::encode_base64(uuid,sizeof(uuid))); sqlite3_mem_t<char*> S = sqlite3_mprintf( "INSERT INTO ht_sessions (hts_id) VALUES (%Q)", htc.get_value().c_str()); db.exec(S); } } void set_authorized(bool a) { sqlite3_mem_t<char*> S = sqlite3_mprintf( "UPDATE ht_sessions" " SET authorized=%d" " WHERE hts_id=%Q", (int)a,htc.get_value().c_str()); db.exec(S); } bool get_authorized() { sqlite3_mem_t<char*> S = sqlite3_mprintf( "SELECT authorized" " FROM ht_sessions" " WHERE hts_id=%Q", htc.get_value().c_str()); sqlite3_table_t T; int nr,nc; db.get_table(S,T,&nr,&nc); assert(nr==1); assert(nc=1); return opkele::util::string_to_long(T.get(1,0,nc)); } ostream& cookie_header(ostream& o) const { o << "Set-Cookie: " << htc.set_cookie_header() << "\n"; return o; } opkele::assoc_t alloc_assoc(const string& type,size_t klength,bool sl) { uuid_t uuid; uuid_generate(uuid); @@ -155,233 +155,233 @@ class example_op_t : public opkele::verify_OP { "couldn't retrieve valid unexpired assoc"); assert(nr==1); assert(nc==6); opkele::secret_t secret; opkele::util::decode_base64(T.get(1,2,nc),secret); 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) { 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)", nonce.c_str() ); db.exec(S); return nonce; } bool check_nonce(const string& nonce) { sqlite3_mem_t<char*> S = sqlite3_mprintf( "SELECT 1" " FROM nonces" " WHERE n_once=%Q AND n_itime IS NULL", nonce.c_str()); sqlite3_table_t T; int nr,nc; db.get_table(S,T,&nr,&nc); return nr>=1; } void invalidate_nonce(const string& nonce) { sqlite3_mem_t<char*> S = sqlite3_mprintf( "UPDATE nonces" " SET n_itime=datetime('now')" " WHERE n_once=%Q", nonce.c_str()); db.exec(S); } const string get_op_endpoint() const { return get_self_url(gw); } }; -int main(int argc,char *argv[]) { +int main(int,char **) { try { kingate::plaincgi_interface ci; kingate::cgi_gateway gw(ci); string op; try { op = gw.get_param("op"); }catch(kingate::exception_notfound&) { } string message; if(op=="set_password") { example_op_t OP(gw); string password = gw.get_param("password"); sqlite3_mem_t<char*> Sget = sqlite3_mprintf("SELECT s_password FROM setup LIMIT 1"); sqlite3_table_t T; int nr,nc; OP.db.get_table(Sget,T,&nr,&nc); if(nr>=1) throw opkele::exception(OPKELE_CP_ "Password already set"); sqlite3_mem_t<char*> Sset = sqlite3_mprintf( "INSERT INTO setup (s_password) VALUES (%Q)", password.c_str()); OP.db.exec(Sset); op.clear(); message = "password set"; }else if(op=="login") { example_op_t OP(gw); string password = gw.get_param("password"); sqlite3_mem_t<char*> Sget = sqlite3_mprintf("SELECT s_password FROM setup LIMIT 1"); sqlite3_table_t T; int nr,nc; OP.db.get_table(Sget,T,&nr,&nc); if(nr<1) throw opkele::exception(OPKELE_CP_ "no password set"); if(password!=T.get(1,0,nc)) throw opkele::exception(OPKELE_CP_ "wrong password"); OP.set_authorized(true); op.clear(); message = "logged in"; OP.cookie_header(cout); }else if(op=="logout") { example_op_t OP(gw); OP.set_authorized(false); op.clear(); message = "logged out"; } - string om; - try { om = gw.get_param("openid.mode"); }catch(kingate::exception_notfound&) { } + string omode; + try { omode = gw.get_param("openid.mode"); }catch(kingate::exception_notfound&) { } if(op=="xrds") { cout << "Content-type: application/xrds+xml\n\n" "<?xml version='1.0' encoding='utf-8'?>" "<xrds:XRDS xmlns:xrds='xri://$xrds' xmlns='xri://$xrd*($v*2.0)'>" "<XRD>" "<Service>" "<Type>" STURI_OPENID20 "</Type>" "<URI>" << get_self_url(gw) << "</URI>" "</Service>"; if(gw.has_param("idsel")){ cout << "<Service>" "<Type>" STURI_OPENID20_OP "</Type>" "<URI>" << get_self_url(gw) << "</URI>"; } cout << "</XRD>" "</xrds:XRDS>"; }else if(op=="id_res" || op=="cancel") { kingate_openid_message_t inm(gw); example_op_t OP(gw); if(gw.get_param("hts_id")!=OP.htc.get_value()) throw opkele::exception(OPKELE_CP_ "toying around, huh?"); opkele::sreg_t sreg; OP.checkid_(inm,sreg); OP.cookie_header(cout); opkele::openid_message_t om; if(op=="id_res") { if(!OP.get_authorized()) throw opkele::exception(OPKELE_CP_ "not logged in"); if(OP.is_id_select()) { OP.select_identity( get_self_url(gw), get_self_url(gw) ); } sreg.set_field(opkele::sreg_t::field_nickname,"anonymous"); sreg.set_field(opkele::sreg_t::field_fullname,"Ann O'Nymus"); sreg.set_field(opkele::sreg_t::field_gender,"F"); sreg.setup_response(); cout << "Status: 302 Going back to RP with id_res\n" "Location: " << OP.id_res(om,sreg).append_query(OP.get_return_to()) << "\n\n"; }else{ cout << "Status: 302 Going back to RP with cancel\n" "Location: " << OP.cancel(om).append_query(OP.get_return_to()) << "\n\n"; } om.to_keyvalues(clog); - }else if(om=="associate") { + }else if(omode=="associate") { kingate_openid_message_t inm(gw); opkele::openid_message_t oum; example_op_t OP(gw); OP.associate(oum,inm); cout << "Content-type: text/plain\n\n"; oum.to_keyvalues(cout); - }else if(om=="checkid_setup") { + }else if(omode=="checkid_setup") { kingate_openid_message_t inm(gw); example_op_t OP(gw); OP.checkid_(inm,0); OP.cookie_header(cout) << "Content-type: text/html\n" "\n" "<html>" "<head>" "<title>test OP: confirm authentication</title>" "</head>" "<body>" "realm: " << OP.get_realm() << "<br/>" "return_to: " << OP.get_return_to() << "<br/>" "claimed_id: " << OP.get_claimed_id() << "<br/>" "identity: " << OP.get_identity() << "<br/>"; if(OP.is_id_select()) { OP.select_identity( get_self_url(gw), get_self_url(gw) ); cout << "selected claimed_id: " << OP.get_claimed_id() << "<br/>" "selected identity: " << OP.get_identity() << "<br/>"; } cout << "<form method='post'>"; inm.to_htmlhiddens(cout); cout << "<input type='hidden' name='hts_id'" " value='" << opkele::util::attr_escape(OP.htc.get_value()) << "'/>" "<input type='submit' name='op' value='id_res'/>" "<input type='submit' name='op' value='cancel'/>" "</form>" "</body>" "</html>"; - }else if(om=="check_authentication") { + }else if(omode=="check_authentication") { kingate_openid_message_t inm(gw); example_op_t OP(gw); opkele::openid_message_t oum; OP.check_authentication(oum,inm); cout << "Content-type: text/plain\n\n"; oum.to_keyvalues(cout); oum.to_keyvalues(clog); }else{ example_op_t OP(gw); string idsel; if(gw.has_param("idsel")) idsel = "&idsel=idsel"; OP.cookie_header(cout) << "Content-type: text/html\n" "X-XRDS-Location: " << get_self_url(gw) << "?op=xrds" << idsel << "\n" "\n" "<html>" "<head>" "<title>test OP</title>" "<link rel='openid.server' href='" << get_self_url(gw) << "'/>" "</head>" "<body>" "test openid 2.0 endpoint" "<br/>" "<a href='" << get_self_url(gw) << "?op=xrds" << idsel << "'>XRDS document</a>" "<br/>" "<h1>" << message << "</h1>"; sqlite3_mem_t<char*> S = sqlite3_mprintf("SELECT s_password FROM setup LIMIT 1"); sqlite3_table_t T; int nr,nc; OP.db.get_table(S,T,&nr,&nc); if(nr<1) { cout << "<form method='post'>" "set password " "<input type='hidden' name='op' value='set_password'/>" "<input type='password' name='password' value=''/>" "<input type='submit' name='submit' value='submit'/>" "</form>"; }else if(OP.get_authorized()) { cout << "<br/>" "<a href='" << get_self_url(gw) << "?op=logout'>logout</a>"; }else{ cout << "<form method='post'>" "login " @@ -13,98 +13,98 @@ using namespace std; #include <opkele/types.h> #include <opkele/util.h> #include <opkele/uris.h> #include <opkele/discovery.h> #include <opkele/association.h> #include <opkele/sreg.h> using namespace opkele; #include <opkele/prequeue_rp.h> #include <opkele/debug.h> #include "sqlite.h" #include "kingate_openid_message.h" #undef DUMB_RP #ifdef DUMB_RP # define DUMBTHROW throw opkele::dumb_RP(OPKELE_CP_ "This RP is dumb") #else # define DUMBTHROW (void)0 #endif class rpdb_t : public sqlite3_t { public: rpdb_t() : sqlite3_t("/tmp/RP.db") { assert(_D); char **resp; int nrow,ncol; char *errm; if(sqlite3_get_table( _D,"SELECT a_op FROM assoc LIMIT 0", &resp,&nrow,&ncol,&errm)!=SQLITE_OK) { extern const char *__RP_db_bootstrap; DOUT_("Bootstrapping DB"); if(sqlite3_exec(_D,__RP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK) throw opkele::exception(OPKELE_CP_ string("Failed to bootstrap SQLite database: ")+errm); }else sqlite3_free_table(resp); } }; class example_rp_t : public opkele::prequeue_RP { public: mutable rpdb_t db; kingate::cookie htc; long as_id; int ordinal; kingate::cgi_gateway& gw; - example_rp_t(kingate::cgi_gateway& gw) - : ordinal(0), have_eqtop(false), gw(gw), as_id(-1) { + example_rp_t(kingate::cgi_gateway& g) + : as_id(-1), ordinal(0), gw(g), have_eqtop(false) { try { htc = gw.cookies.get_cookie("ht_session"); as_id = opkele::util::string_to_long(gw.get_param("asid")); }catch(kingate::exception_notfound& kenf) { uuid_t uuid; uuid_generate(uuid); htc = kingate::cookie("ht_session",util::encode_base64(uuid,sizeof(uuid))); sqlite3_mem_t<char*> S = sqlite3_mprintf( "INSERT INTO ht_sessions (hts_id) VALUES (%Q)", htc.get_value().c_str()); db.exec(S); } } /* Global persistent store */ opkele::assoc_t store_assoc( const string& OP,const string& handle, const string& type,const secret_t& secret, int expires_in) { DUMBTHROW; DOUT_("Storing '" << handle << "' assoc with '" << OP << "'"); time_t exp = time(0)+expires_in; sqlite3_mem_t<char*> S = sqlite3_mprintf( "INSERT INTO assoc" " (a_op,a_handle,a_type,a_ctime,a_etime,a_secret)" " VALUES (" " %Q,%Q,%Q," " datetime('now'), datetime('now','+%d seconds')," " %Q" " );", OP.c_str(), handle.c_str(), type.c_str(), expires_in, util::encode_base64(&(secret.front()),secret.size()).c_str() ); db.exec(S); return opkele::assoc_t(new opkele::association( OP, handle, type, secret, exp, false )); } opkele::assoc_t find_assoc( const string& OP) { DUMBTHROW; DOUT_("Looking for an assoc with '" << OP << '\''); sqlite3_mem_t<char*> S = sqlite3_mprintf( "SELECT" " a_op,a_handle,a_type,a_secret," " strftime('%%s',a_etime) AS a_etime" " FROM assoc" @@ -306,97 +306,97 @@ class example_rp_t : public opkele::prequeue_RP { _nid = T.get(1,0,nc); } return _nid; } const string get_this_url() const { bool s = gw.has_meta("SSL_PROTOCOL_VERSION"); string rv = s?"https://":"http://"; rv += gw.http_request_header("Host"); const string& port = gw.get_meta("SERVER_PORT"); if( port!=(s?"443":"80") ) { rv += ':'; rv += port; } rv += gw.get_meta("REQUEST_URI"); return rv; } void initiate(const string& usi) { allocate_asid(); prequeue_RP::initiate(usi); } string get_self_url() const { string rv = get_this_url(); string::size_type q = rv.find('?'); if(q!=string::npos) rv.erase(q); return rv; } void allocate_asid() { sqlite3_mem_t<char*> S = sqlite3_mprintf( "INSERT INTO auth_sessions (hts_id)" " VALUES (%Q)", htc.get_value().c_str()); db.exec(S); as_id = sqlite3_last_insert_rowid(db); DOUT_("Allocated authentication session id "<<as_id); assert(as_id>=0); } #ifdef DUMB_RP virtual assoc_t associate(const string& OP) { DUMBTHROW; } #endif }; -int main(int argc,char *argv[]) { +int main(int,char **) { try { kingate::plaincgi_interface ci; kingate::cgi_gateway gw(ci); string op; try { op = gw.get_param("op"); }catch(kingate::exception_notfound&) { } if(op=="initiate") { example_rp_t rp(gw); string usi = gw.get_param("openid_identity"); rp.initiate(usi); opkele::sreg_t sreg(opkele::sreg_t::fields_NONE,opkele::sreg_t::fields_ALL); opkele::openid_message_t cm; string loc; cout << "Set-Cookie: " << rp.htc.set_cookie_header() << "\n" "Status: 302 Going to OP\n" "Location: " << ( loc = rp.checkid_(cm,opkele::mode_checkid_setup, rp.get_self_url()+ "?op=confirm&asid="+opkele::util::long_to_string(rp.as_id), rp.get_self_url(),&sreg).append_query(rp.get_endpoint().uri) ) << "\n\n"; DOUT_("Going to " << loc); }else if(op=="confirm") { kingate_openid_message_t om(gw); example_rp_t rp(gw); opkele::sreg_t sreg(opkele::sreg_t::fields_NONE,opkele::sreg_t::fields_ALL); rp.id_res(om,&sreg); cout << "Content-Type: text/plain\n\n"; for(opkele::basic_openid_message::fields_iterator i=om.fields_begin(); i!=om.fields_end();++i) { cout << *i << '=' << om.get_field(*i) << endl; } cout << endl << "SREG fields: " << sreg.has_fields << endl; }else{ cout << "Content-type: text/html\n\n" "<html>" "<head><title>test RP</title></head>" "<body>" "<form action='' method='post'>" "<input type='hidden' name='op' value='initiate' />" "<input type='text' name='openid_identity'/>" "<input type='submit' name='submit' value='submit' />" "</form>" diff --git a/test/kingate_openid_message.h b/test/kingate_openid_message.h index 37dcdfa..7029ff7 100644 --- a/test/kingate_openid_message.h +++ b/test/kingate_openid_message.h @@ -12,98 +12,98 @@ class join_iterator : public iterator< bool cleanup() { bool rv = false; while(!(ranges.empty() || ranges.front().first!=ranges.front().second)) { ranges.pop_front(); rv = true; } return rv; } join_iterator<IT>& add_range(const IT& b,const IT& e) { ranges.push_back(typename ranges_t::value_type(b,e)); cleanup(); return *this; } bool operator==(const join_iterator<IT>& x) const { return ranges==x.ranges; } bool operator!=(const join_iterator<IT>& x) const { return ranges!=x.ranges; } typename IT::reference operator*() const { assert(!ranges.empty()); assert(ranges.front().first!=ranges.front().second); return *ranges.front().first; } typename IT::pointer operator->() const { assert(!ranges.empty()); assert(ranges.front().first!=ranges.front().second); return ranges.front().first.operator->(); } join_iterator<IT>& operator++() { cleanup(); if(ranges.empty()) return *this; do { ++ranges.front().first; }while(cleanup() && !ranges.empty()); return *this; } join_iterator<IT> operator++(int) { join_iterator<IT> rv(*this); ++(*this); return rv; } }; template<typename IT> class cut_prefix_filterator : public opkele::util::basic_filterator<IT> { public: string pfx; mutable string tmp; cut_prefix_filterator() { } - cut_prefix_filterator(const IT& bi,const IT&ei,const string& pfx) - : opkele::util::basic_filterator<IT>(bi,ei), pfx(pfx) { + cut_prefix_filterator(const IT& _bi,const IT&_ei,const string& p) + : opkele::util::basic_filterator<IT>(_bi,_ei), pfx(p) { this->prepare(); } bool is_interesting() const { return pfx.length()==0 || !strncmp(this->it->c_str(),pfx.c_str(),pfx.length()); } typename IT::reference operator*() const { assert(!this->empty); tmp = *this->it; tmp.erase(0,pfx.length()); return tmp; } typename IT::pointer operator->() const { assert(!this->empty); return &this->operator*(); } }; class kingate_openid_message_t : public opkele::basic_openid_message { typedef join_iterator<kingate::cgi_gateway::params_t::const_iterator> jitterator; typedef opkele::util::map_keys_iterator< jitterator, fields_iterator::value_type, fields_iterator::reference, fields_iterator::pointer> keys_iterator; typedef cut_prefix_filterator<keys_iterator> pfilterator; public: const kingate::cgi_gateway& gw; kingate_openid_message_t(const kingate::cgi_gateway& g) : gw(g) { } bool has_field(const string& n) const { return gw.has_param("openid."+n); } const string& get_field(const string& n) const try { return gw.get_param("openid."+n); }catch(kingate::exception_notfound& nf) { throw opkele::failed_lookup(OPKELE_CP_ nf.what()); } fields_iterator fields_begin() const { return pfilterator( keys_iterator( jitterator() .add_range( gw.get.begin(), gw.get.end() ) .add_range( gw.post.begin(), gw.post.end() ), jitterator() ), keys_iterator(), "openid." ); } fields_iterator fields_end() const { return pfilterator(); } }; |