-rw-r--r-- | test/.gitignore | 2 | ||||
-rw-r--r-- | test/Makefile.am | 35 | ||||
-rw-r--r-- | test/RP-db.sql | 37 | ||||
-rw-r--r-- | test/RP.cc | 538 | ||||
-rw-r--r-- | test/html/2rels.html | 7 | ||||
-rw-r--r-- | test/html/empty.html | 0 | ||||
-rw-r--r-- | test/html/head-in-body.html | 10 | ||||
-rw-r--r-- | test/html/hkn-delegate.html | 7 | ||||
-rw-r--r-- | test/html/hkn-server.html | 7 | ||||
-rw-r--r-- | test/html/hkn.html | 8 | ||||
-rw-r--r-- | test/html/in-body.html | 8 | ||||
-rw-r--r-- | test/html/spaced-link-attrs.html | 8 | ||||
-rw-r--r-- | test/html/spaced-links.html | 8 | ||||
-rw-r--r-- | test/html/unclosed-head.html | 7 | ||||
-rw-r--r-- | test/idiscover.cc | 46 | ||||
-rw-r--r-- | test/sqlite.h | 71 | ||||
-rw-r--r-- | test/test.cc | 49 |
17 files changed, 693 insertions, 155 deletions
diff --git a/test/.gitignore b/test/.gitignore index 31ae686..d07884c 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,5 +1,7 @@ /.deps /.libs /test *.o /idiscover +/RP.cgi +/RP-db.cc diff --git a/test/Makefile.am b/test/Makefile.am index b573d55..61e3787 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,16 +1,39 @@ -noinst_PROGRAMS = test idiscover +noinst_PROGRAMS = test idiscover RP.cgi AM_CPPFLAGS=${CPPFLAGS_DEBUG} DEFAULT_INCLUDES = -I${top_builddir} -INCLUDES = -I${top_srcdir}/include/ ${KONFORKA_CFLAGS} ${LIBCURL_CPPFLAGS} +INCLUDES = -I${top_srcdir}/test/ -I${top_builddir}/include/ -I${top_srcdir}/include/ ${KONFORKA_CFLAGS} ${LIBCURL_CPPFLAGS} test_SOURCES = test.cc test_LDADD = ${top_builddir}/lib/libopkele.la -EXTRA_DIST=$(addsuffix .html,$(addprefix html/, \ - empty head-in-body hkn-delegate hkn-server hkn in-body \ - unclosed-head spaced-links spaced-link-attrs 2rels \ - )) +EXTRA_DIST= \ + sqlite.h \ + RP-db.sql idiscover_SOURCES = idiscover.cc idiscover_LDADD = ${top_builddir}/lib/libopkele.la + +if HAVE_SQLITE3 +if HAVE_KINGATE +if HAVE_UUID + +RP_cgi_SOURCES = RP.cc +nodist_RP_cgi_SOURCES = RP-db.cc +RP_cgi_LDADD = ${top_builddir}/lib/libopkele.la \ + ${SQLITE3_LIBS} ${KINGATE_LIBS} ${UUID_LIBS} +RP_cgi_CFLAGS = ${SQLITE3_CFLAGS} ${KINGATE_CFLAGS} ${UUID_CFLAGS} + +RP-db.cc: RP-db.sql + ( \ + echo 'const char * __RP_db_bootstrap = ' && \ + sed -e 's/^/"/' -e 's/$$/"/' $< && \ + echo ';' \ + ) >$@ + +clean-local: + rm -f RP-db.cc + +endif #HAVE_UUID +endif #HAVE_KINGATE +endif #HAVE_SQLITE3 diff --git a/test/RP-db.sql b/test/RP-db.sql new file mode 100644 index 0000000..71a82d4 --- a/dev/null +++ b/test/RP-db.sql @@ -0,0 +1,37 @@ +CREATE TABLE assoc ( + a_op text, + a_handle text NOT NULL, + a_type text DEFAULT 'HMAC-SHA1', + a_ctime text NOT NULL, + a_etime text NOT NULL, + a_secret text NOT NULL, + a_stateless integer NOT NULL DEFAULT 0, + a_itime integer, + UNIQUE(a_op,a_handle) +); + +CREATE TABLE nonces ( + n_op text NOT NULL, + n_once text NOT NULL, + PRIMARY KEY (n_op,n_once) +); + +CREATE TABLE ht_sessions ( + hts_id text NOT NULL PRIMARY KEY +); + +CREATE TABLE auth_sessions ( + as_id integer PRIMARY KEY AUTOINCREMENT, + hts_id text NOT NULL REFERENCES ht_sessions(hts_id), + as_normalized_id text, + UNIQUE (hts_id,as_id) +); + +CREATE TABLE endpoints_queue ( + as_id integer NOT NULL REFERENCES auth_sessions (as_id), + eq_ctime integer NOT NULL, + eq_ordinal integer NOT NULL, + eq_uri text, + eq_claimed_id text, + eq_local_id text +); diff --git a/test/RP.cc b/test/RP.cc new file mode 100644 index 0000000..f2f8851 --- a/dev/null +++ b/test/RP.cc @@ -0,0 +1,538 @@ +#include <uuid/uuid.h> +#include <iostream> +#include <cassert> +#include <stdexcept> +#include <string> +#include <set> +#include <iterator> +using namespace std; +#include <kingate/exception.h> +#include <kingate/plaincgi.h> +#include <kingate/cgi_gateway.h> +#include <opkele/exception.h> +#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" + +#undef DUMB_RP + +#ifdef DUMB_RP +# define DUMBTHROW throw opkele::dumb_RP(OPKELE_CP_ "This RP is dumb") +#else +# define DUMBTHROW (void)0 +#endif + +template<typename IT> +class join_iterator : public iterator< + input_iterator_tag,typename IT::value_type, + void,typename IT::pointer,typename IT::reference> { + public: + typedef pair<IT,IT> range_t; + typedef list<range_t> ranges_t; + ranges_t ranges; + + join_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) { + 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 { + return gw.get_param("openid."+n); } + + 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(); + } +}; + +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) { + 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" + " WHERE a_op=%Q AND a_itime IS NULL AND NOT a_stateless" + " AND ( a_etime > datetime('now','-30 seconds') )" + " LIMIT 1", + OP.c_str()); + sqlite3_table_t T; + int nr,nc; + db.get_table(S,T,&nr,&nc); + if(nr<1) + throw opkele::failed_lookup(OPKELE_CP_ "Couldn't find unexpired handle"); + assert(nr==1); + assert(nc==5); + secret_t secret; + util::decode_base64(T.get(1,3,nc),secret); + DOUT_(" found '" << T.get(1,1,nc) << '\''); + return opkele::assoc_t(new opkele::association( + T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), + secret, strtol(T.get(1,4,nc),0,0), false )); + } + + opkele::assoc_t retrieve_assoc( + const string& OP,const string& handle) { + DUMBTHROW; + DOUT_("Retrieving assoc '" << handle << "' 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" + " WHERE a_op=%Q AND a_handle=%Q" + " AND a_itime IS NULL AND NOT a_stateless" + " LIMIT 1", + OP.c_str(),handle.c_str()); + sqlite3_table_t T; + int nr,nc; + db.get_table(S,T,&nr,&nc); + if(nr<1) + throw opkele::failed_lookup(OPKELE_CP_ "couldn't retrieve valid association"); + assert(nr==1); assert(nc==5); + secret_t secret; util::decode_base64(T.get(1,3,nc),secret); + DOUT_(" found. type=" << T.get(1,2,nc) << '\''); + return opkele::assoc_t(new opkele::association( + T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), + secret, strtol(T.get(1,4,nc),0,0), false )); + } + + void invalidate_assoc( + const string& OP,const string& handle) { + DUMBTHROW; + DOUT_("Invalidating assoc '" << handle << "' with '" << OP << '\''); + sqlite3_mem_t<char*> + S = sqlite3_mprintf( + "UPDATE assoc SET a_itime=datetime('now')" + " WHERE a_op=%Q AND a_handle=%Q", + OP.c_str(), handle.c_str() ); + db.exec(S); + } + + void check_nonce(const string& OP,const string& nonce) { + DOUT_("Checking nonce '" << nonce << "' from '" << OP << '\''); + sqlite3_mem_t<char*> + S = sqlite3_mprintf( + "SELECT 1 FROM nonces WHERE n_op=%Q AND n_once=%Q", + OP.c_str(), nonce.c_str()); + sqlite3_table_t T; + int nr,nc; + db.get_table(S,T,&nr,&nc); + if(nr) + throw opkele::id_res_bad_nonce(OPKELE_CP_ "already seen that nonce"); + sqlite3_mem_t<char*> + SS = sqlite3_mprintf( + "INSERT INTO nonces (n_op,n_once) VALUES (%Q,%Q)", + OP.c_str(), nonce.c_str()); + db.exec(SS); + } + + /* Session perisistent store */ + + void begin_queueing() { + assert(as_id>=0); + DOUT_("Resetting queue for session '" << htc.get_value() << "'/" << as_id); + sqlite3_mem_t<char*> S = sqlite3_mprintf( + "DELETE FROM endpoints_queue" + " WHERE as_id=%ld", + as_id); + db.exec(S); + } + + void queue_endpoint(const opkele::openid_endpoint_t& ep) { + assert(as_id>=0); + DOUT_("Queueing endpoint " << ep.claimed_id << " : " << ep.local_id << " @ " << ep.uri); + sqlite3_mem_t<char*> S = sqlite3_mprintf( + "INSERT INTO endpoints_queue" + " (as_id,eq_ctime,eq_ordinal,eq_uri,eq_claimed_id,eq_local_id)" + " VALUES (%ld,strftime('%%s','now'),%d,%Q,%Q,%Q)", + as_id,ordinal++, + ep.uri.c_str(),ep.claimed_id.c_str(),ep.local_id.c_str()); + db.exec(S); + } + + mutable openid_endpoint_t eqtop; + mutable bool have_eqtop; + + const openid_endpoint_t& get_endpoint() const { + assert(as_id>=0); + if(!have_eqtop) { + sqlite3_mem_t<char*> + S = sqlite3_mprintf( + "SELECT" + " eq_uri, eq_claimed_id, eq_local_id" + " FROM endpoints_queue" + " JOIN auth_sessions USING(as_id)" + " WHERE hts_id=%Q AND as_id=%ld" + " ORDER BY eq_ctime,eq_ordinal" + " LIMIT 1",htc.get_value().c_str(),as_id); + sqlite3_table_t T; int nr,nc; + db.get_table(S,T,&nr,&nc); + if(nr<1) + throw opkele::exception(OPKELE_CP_ "No more endpoints queued"); + assert(nr==1); assert(nc==3); + eqtop.uri = T.get(1,0,nc); + eqtop.claimed_id = T.get(1,1,nc); + eqtop.local_id = T.get(1,2,nc); + have_eqtop = true; + } + return eqtop; + } + + void next_endpoint() { + assert(as_id>=0); + get_endpoint(); + have_eqtop = false; + sqlite3_mem_t<char*> S = sqlite3_mprintf( + "DELETE FROM endpoints_queue" + " WHERE as_id=%ld AND eq_uri=%Q AND eq_local_id=%Q", + htc.get_value().c_str(),as_id, + eqtop.uri.c_str()); + db.exec(S); + } + + mutable string _cid; + mutable string _nid; + + void set_claimed_id(const string& cid) { + assert(as_id>=0); + sqlite3_mem_t<char*> S = sqlite3_mprintf( + "UPDATE auth_sessions" + " SET as_claimed_id=%Q" + " WHERE hts_id=%Q and as_id=%ld", + cid.c_str(), + htc.get_value().c_str(),as_id); + db.exec(S); + _cid = cid; + } + const string get_claimed_id() const { + assert(as_id>=0); + if(_cid.empty()) { + sqlite3_mem_t<char*> S = sqlite3_mprintf( + "SELECT as_claimed_id" + " FROM" + " auth_sessions" + " WHERE" + " hts_id=%Q AND as_id=%ld", + htc.get_value().c_str(),as_id); + sqlite3_table_t T; int nr,nc; + db.get_table(S,T,&nr,&nc); + assert(nr==1); assert(nc==1); + _cid = T.get(1,0,nc); + } + return _cid; + } + void set_normalized_id(const string& nid) { + assert(as_id>=0); + sqlite3_mem_t<char*> S = sqlite3_mprintf( + "UPDATE auth_sessions" + " SET as_normalized_id=%Q" + " WHERE hts_id=%Q and as_id=%ld", + nid.c_str(), + htc.get_value().c_str(),as_id); + db.exec(S); + _nid = nid; + } + const string get_normalized_id() const { + assert(as_id>=0); + if(_nid.empty()) { + sqlite3_mem_t<char*> S = sqlite3_mprintf( + "SELECT as_normalized_id" + " FROM" + " auth_sessions" + " WHERE" + " hts_id=%Q AND as_id=%ld", + htc.get_value().c_str(),as_id); + sqlite3_table_t T; int nr,nc; + db.get_table(S,T,&nr,&nc); + assert(nr==1); assert(nc==1); + _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[]) { + 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>" + "<br/><br/>" + "<a href='?op=initiate&openid_identity=www.myopenid.com&dummy=" << time(0) << "'>login with myopenid.com account</a>" + "<br/>" + "</body" + "</html>" + ; + } +#ifdef OPKELE_HAVE_KONFORKA + }catch(konforka::exception& e) { +#else + }catch(std::exception& e){ +#endif + DOUT_("Oops: " << e.what()); + cout << "Content-Type: text/plain\n\n" + "Exception:\n" + " what: " << e.what() << endl; +#ifdef OPKELE_HAVE_KONFORKA + cout << " where: " << e.where() << endl; + if(!e._seen.empty()) { + cout << " seen:" << endl; + for(list<konforka::code_point>::const_iterator + i=e._seen.begin();i!=e._seen.end();++i) { + cout << " " << i->c_str() << endl; + } + } +#endif + } +} diff --git a/test/html/2rels.html b/test/html/2rels.html deleted file mode 100644 index 8773c55..0000000 --- a/test/html/2rels.html +++ b/dev/null @@ -1,7 +0,0 @@ -<html> - <head> - <link rel="openid.server openid.delegate" href="http://www.klever.net/openid.server" /> - </head> - <body> - </body> -</html> diff --git a/test/html/empty.html b/test/html/empty.html deleted file mode 100644 index e69de29..0000000 --- a/test/html/empty.html +++ b/dev/null diff --git a/test/html/head-in-body.html b/test/html/head-in-body.html deleted file mode 100644 index 0f778f3..0000000 --- a/test/html/head-in-body.html +++ b/dev/null @@ -1,10 +0,0 @@ -<html> - <head> - </head> - <body> - <head> - <link rel="openid.server" href="http://www.klever.net/openid.server" /> - <link rel="openid.delegate" href="http://hacker.klever.net/" /> - </head> - </body> -</html> diff --git a/test/html/hkn-delegate.html b/test/html/hkn-delegate.html deleted file mode 100644 index 62e25a3..0000000 --- a/test/html/hkn-delegate.html +++ b/dev/null @@ -1,7 +0,0 @@ -<html> - <head> - <link rel="openid.delegate" href="http://hacker.klever.net/" /> - </head> - <body> - </body> -</html> diff --git a/test/html/hkn-server.html b/test/html/hkn-server.html deleted file mode 100644 index e6b64e8..0000000 --- a/test/html/hkn-server.html +++ b/dev/null @@ -1,7 +0,0 @@ -<html> - <head> - <link rel="openid.server" href="http://www.klever.net/openid.server" /> - </head> - <body> - </body> -</html> diff --git a/test/html/hkn.html b/test/html/hkn.html deleted file mode 100644 index 8d6e409..0000000 --- a/test/html/hkn.html +++ b/dev/null @@ -1,8 +0,0 @@ -<html> - <head> - <link rel="openid.server" href="http://www.klever.net/openid.server" /> - <link rel="openid.delegate" href="http://hacker.klever.net/" /> - </head> - <body> - </body> -</html> diff --git a/test/html/in-body.html b/test/html/in-body.html deleted file mode 100644 index 53bc06d..0000000 --- a/test/html/in-body.html +++ b/dev/null @@ -1,8 +0,0 @@ -<html> - <head> - </head> - <body> - <link rel="openid.server" href="http://www.klever.net/openid.server" /> - <link rel="openid.delegate" href="http://hacker.klever.net/" /> - </body> -</html> diff --git a/test/html/spaced-link-attrs.html b/test/html/spaced-link-attrs.html deleted file mode 100644 index 33905c0..0000000 --- a/test/html/spaced-link-attrs.html +++ b/dev/null @@ -1,8 +0,0 @@ -<html> - <head> - <link rel=" openid.server " href=" http://www.klever.net/openid.server" /> - <link rel=" openid.delegate" href="http://hacker.klever.net/ " /> - </head> - <body> - </body> -</html> diff --git a/test/html/spaced-links.html b/test/html/spaced-links.html deleted file mode 100644 index a958907..0000000 --- a/test/html/spaced-links.html +++ b/dev/null @@ -1,8 +0,0 @@ -<html> - <head> - < link rel = "openid.server" href = "http://www.klever.net/openid.server" /> - <link rel="openid.delegate" href='http://hacker.klever.net/' /> - </head> - <body> - </body> -</html> diff --git a/test/html/unclosed-head.html b/test/html/unclosed-head.html deleted file mode 100644 index 9c6f2ea..0000000 --- a/test/html/unclosed-head.html +++ b/dev/null @@ -1,7 +0,0 @@ -<html> - <head> - <link rel="openid.server" href="http://www.klever.net/openid.server" /> - <link rel="openid.delegate" href="http://hacker.klever.net/" /> - <body> - </body> -</html> diff --git a/test/idiscover.cc b/test/idiscover.cc index d9a7c62..44df9ce 100644 --- a/test/idiscover.cc +++ b/test/idiscover.cc @@ -1,54 +1,40 @@ #include <iostream> #include <stdexcept> #include <iterator> #include <algorithm> using namespace std; #include <opkele/exception.h> #include <opkele/discovery.h> +#include <opkele/util.h> -template<typename _PDT> - ostream& operator<<(ostream& o,const opkele::xrd::priority_map<_PDT>& pm) { - for(typename opkele::xrd::priority_map<_PDT>::const_iterator i=pm.begin(); - i!=pm.end();++i) - o << ' ' << i->second << '[' << i->first << ']'; +namespace opkele { + ostream& operator<<(ostream& o,const opkele::openid_endpoint_t& oep) { + o + << " URI: " << oep.uri << endl + << " Claimed ID: " << oep.claimed_id << endl + << " Local ID: " << oep.local_id << endl; return o; } - -ostream& operator<<(ostream& o,const opkele::xrd::service_t s) { - o << "{" << endl - << " Type: "; - copy(s.types.begin(),s.types.end(), - ostream_iterator<string>(o," ")); - o << endl - << " URI: " << s.uris << endl - << " LocalID: " << s.local_ids << endl - << " ProviderID: " << s.provider_id << endl; - o << "}"; } int main(int argc,char **argv) { try { if(argc<2) throw opkele::exception(OPKELE_CP_ "Please, give me something to resolve"); for(int a=1;a<argc;++a) { - opkele::idiscovery_t discovery(argv[a]); - clog - << "===============================================================" << endl + cout << "==============================================================" << endl << "User-supplied ID: " << argv[a] << endl - << "Normalized ID: " << discovery.normalized_id << endl - << "Canonicalized ID: " << discovery.canonicalized_id << endl - << "The identity is " << (discovery.xri_identity?"":"not ") << "an i-name" << endl; - if(discovery.xrd.expires) - clog << "Information expires in " << discovery.xrd.expires-time(0) << " seconds" << endl; - clog << endl - << "CanonicalID: " << discovery.xrd.canonical_ids << endl - << "LocalID: " << discovery.xrd.local_ids << endl - << "ProviderID: " << discovery.xrd.provider_id << endl - << "Services: " << discovery.xrd.services << endl; + << "Endpoints:" << endl + << " --" << endl; + string normalized = opkele::idiscover( + ostream_iterator<opkele::openid_endpoint_t>(cout," --\n") + ,argv[a]); + cout << "Normalized ID: " << normalized << endl; } }catch(exception& e) { - cerr << "oops: " << e.what() << endl; + cerr << "oops, caught " << opkele::util::abi_demangle(typeid(e).name()) << endl + << " .what(): " << e.what() << endl; _exit(1); } _exit(0); } diff --git a/test/sqlite.h b/test/sqlite.h new file mode 100644 index 0000000..883a2c0 --- a/dev/null +++ b/test/sqlite.h @@ -0,0 +1,71 @@ +#include <sqlite3.h> + +class sqlite3_t { + public: + sqlite3 *_D; + + sqlite3_t(const char *f) + : _D(0) { + int r = sqlite3_open(f,&_D); + if(r!=SQLITE_OK) { + string msg = sqlite3_errmsg(_D); sqlite3_close(_D); + throw opkele::exception(OPKELE_CP_ "Failed to open SQLite database: "+msg); + } + } + ~sqlite3_t() { + if(_D) sqlite3_close(_D); + } + + operator const sqlite3*(void) const { return _D; } + operator sqlite3*(void) { return _D; } + + void exec(const char *sql) { + assert(_D); + char *errm; + if(sqlite3_exec(_D,sql,NULL,NULL,&errm)!=SQLITE_OK) + throw opkele::exception(OPKELE_CP_ string("Failed to sqlite3_exec():")+errm); + } + void get_table(const char *sql,char ***resp,int *nr,int *nc) { + assert(_D); + char *errm; + if(sqlite3_get_table(_D,sql,resp,nr,nc,&errm)!=SQLITE_OK) + throw opkele::exception(OPKELE_CP_ string("Failed to sqlite3_get_table():")+errm); + } +}; + +template<typename T> +class sqlite3_mem_t { + public: + T _M; + + sqlite3_mem_t(T M) :_M(M) { } + ~sqlite3_mem_t() { if(_M) sqlite3_free(_M); } + + operator const T&(void) const { return _M; } + operator T&(void) { return _M; } + + sqlite3_mem_t operator=(T M) { + if(_M) sqlite3_free(_M); + _M = M; + } +}; + +class sqlite3_table_t { + public: + char **_T; + + sqlite3_table_t() : _T(0) { } + sqlite3_table_t(char **T) : _T(T) { } + ~sqlite3_table_t() { if(_T) sqlite3_free_table(_T); } + + operator char**&(void) { return _T; } + + operator char ***(void) { + if(_T) sqlite3_free_table(_T); + return &_T; } + + const char *get(int r,int c,int nc) { + assert(_T); + return _T[r*nc+c]; + } +}; diff --git a/test/test.cc b/test/test.cc index 1a012b5..35f58ab 100644 --- a/test/test.cc +++ b/test/test.cc @@ -1,139 +1,90 @@ #include <iostream> #include <stdexcept> using namespace std; #include <opkele/exception.h> -#include <opkele/consumer.h> #include <opkele/util.h> #include "config.h" class failed_test : public opkele::exception { public: failed_test(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; -class dummy_consumer_t : public opkele::consumer_t { - public: - virtual opkele::assoc_t store_assoc(const string& /* server */,const string& /* handle */,const opkele::secret_t& /* secret */,int /* expires_in */) { - throw opkele::not_implemented(OPKELE_CP_ "Not implemented"); - } - virtual opkele::assoc_t retrieve_assoc(const string& /* server */ ,const string& /* handle */) { - throw opkele::not_implemented(OPKELE_CP_ "Not implemented"); - } - virtual void invalidate_assoc(const string& /* server */,const string& /* handle */) { - throw opkele::not_implemented(OPKELE_CP_ "Not implemented"); - } -}; - - -void test_retrieve_links(const string& f,bool success,const string& s="",const string& d="") { - dummy_consumer_t dc; - string server, delegate; - try { - dc.retrieve_links("file://" OPKELE_SRC_DIR "/test/html/"+f,server,delegate); - if(!success) - throw failed_test(OPKELE_CP_ "Retrieved links when it shouldn't"); - if(server!=s) - throw failed_test(OPKELE_CP_ "retrieve_links test failed, expected server '"+s+"', got '"+server+"'"); - if(delegate!=d) - throw failed_test(OPKELE_CP_ "retrieve_links test failed, expected delegate '"+d+"', got '"+delegate+"'"); - }catch(opkele::bad_input& obi) { - if(success) - throw failed_test(OPKELE_CP_ "Test '"+f+"' failed due to 'bad_input'["+obi.what()+"]"); - }catch(opkele::failed_assertion& ofa) { - if(success) - throw failed_test(OPKELE_CP_ "Test '"+f+"' failed due to 'failed_assertion'["+ofa.what()+"]"); - } -} - -void test_retrieve_links() { - test_retrieve_links("empty.html",false); - test_retrieve_links("in-body.html",false); - test_retrieve_links("head-in-body.html",false); - test_retrieve_links("hkn.html",true,"http://www.klever.net/openid.server","http://hacker.klever.net/"); - test_retrieve_links("hkn-server.html",true,"http://www.klever.net/openid.server"); - test_retrieve_links("hkn-delegate.html",false); - test_retrieve_links("unclosed-head.html",true,"http://www.klever.net/openid.server","http://hacker.klever.net/"); - test_retrieve_links("spaced-links.html",true,"http://www.klever.net/openid.server","http://hacker.klever.net/"); - test_retrieve_links("spaced-link-attrs.html",true,"http://www.klever.net/openid.server","http://hacker.klever.net/"); - test_retrieve_links("2rels.html",true,"http://www.klever.net/openid.server","http://www.klever.net/openid.server"); -} - void test_rfc_3986_normalize_uri(const string &ouri,bool success,const string& nuri="") { try { string n = opkele::util::rfc_3986_normalize_uri(ouri); if(!success) throw failed_test(OPKELE_CP_ "Normalized URI when it shouldn't"); if(n!=nuri) throw failed_test(OPKELE_CP_ "rfc_3986_test_failed for '"+ouri+"' failed, expected '"+nuri+"', got '"+n+"'"); }catch(opkele::bad_input& obi) { if(success) throw failed_test(OPKELE_CP_ "Test '"+ouri+"' failed due to 'bad_input'["+obi.what()+"]"); }catch(opkele::not_implemented& oni) { if(success) throw failed_test(OPKELE_CP_ "Test '"+ouri+"' failed due to 'not_implemented'["+oni.what()+"]"); } } void test_rfc_3986_normalize_uri() { test_rfc_3986_normalize_uri( "invalid", false ); test_rfc_3986_normalize_uri( "ftp://hacker.klever.net/", false ); test_rfc_3986_normalize_uri( "http://", false ); test_rfc_3986_normalize_uri( "http:/hacker.klever.net/", false ); test_rfc_3986_normalize_uri( "hTTp://hacker.klever.net#uh?oh", true, "http://hacker.klever.net/#uh?oh" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net?uh#oh", true, "http://hacker.klever.net/?uh#oh" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net:80/", true, "http://hacker.klever.net/" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net:80?uh", true, "http://hacker.klever.net/?uh" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net:80#uh", true, "http://hacker.klever.net/#uh" ); test_rfc_3986_normalize_uri( "https://hacker.klever.net:443", true, "https://hacker.klever.net/" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net:?oh", true, "http://hacker.klever.net/?oh" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah%2E", true, "http://hacker.klever.net/ah." ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/%2E/", true, "http://hacker.klever.net/ah/" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/%2b/", true, "http://hacker.klever.net/ah/%2B/" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/./oh?eh", true, "http://hacker.klever.net/ah/oh?eh" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/../oh?", true, "http://hacker.klever.net/oh?" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah//oh?", true, "http://hacker.klever.net/ah/oh?" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/?", true, "http://hacker.klever.net/ah/?" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/%", false ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/%a", false ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/%zx", false ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/%5x", false ); test_rfc_3986_normalize_uri( "Http://Hacker.Klever.Net:", true, "http://hacker.klever.net/" ); } int main() { try { test_rfc_3986_normalize_uri(); - test_retrieve_links(); }catch(failed_test& ft) { cerr << "Test failed: " << ft.what() << endl; }catch(exception& e) { cerr << "oops: " << e.what() << endl; _exit(1); } _exit(0); } |