summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--test/.gitignore2
-rw-r--r--test/Makefile.am35
-rw-r--r--test/RP-db.sql37
-rw-r--r--test/RP.cc538
-rw-r--r--test/html/2rels.html7
-rw-r--r--test/html/empty.html0
-rw-r--r--test/html/head-in-body.html10
-rw-r--r--test/html/hkn-delegate.html7
-rw-r--r--test/html/hkn-server.html7
-rw-r--r--test/html/hkn.html8
-rw-r--r--test/html/in-body.html8
-rw-r--r--test/html/spaced-link-attrs.html8
-rw-r--r--test/html/spaced-links.html8
-rw-r--r--test/html/unclosed-head.html7
-rw-r--r--test/idiscover.cc46
-rw-r--r--test/sqlite.h71
-rw-r--r--test/test.cc49
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 @@
1/.deps 1/.deps
2/.libs 2/.libs
3/test 3/test
4*.o 4*.o
5/idiscover 5/idiscover
6/RP.cgi
7/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 @@
1noinst_PROGRAMS = test idiscover 1noinst_PROGRAMS = test idiscover RP.cgi
2 2
3AM_CPPFLAGS=${CPPFLAGS_DEBUG} 3AM_CPPFLAGS=${CPPFLAGS_DEBUG}
4DEFAULT_INCLUDES = -I${top_builddir} 4DEFAULT_INCLUDES = -I${top_builddir}
5INCLUDES = -I${top_srcdir}/include/ ${KONFORKA_CFLAGS} ${LIBCURL_CPPFLAGS} 5INCLUDES = -I${top_srcdir}/test/ -I${top_builddir}/include/ -I${top_srcdir}/include/ ${KONFORKA_CFLAGS} ${LIBCURL_CPPFLAGS}
6 6
7test_SOURCES = test.cc 7test_SOURCES = test.cc
8test_LDADD = ${top_builddir}/lib/libopkele.la 8test_LDADD = ${top_builddir}/lib/libopkele.la
9 9
10EXTRA_DIST=$(addsuffix .html,$(addprefix html/, \ 10EXTRA_DIST= \
11 empty head-in-body hkn-delegate hkn-server hkn in-body \ 11 sqlite.h \
12 unclosed-head spaced-links spaced-link-attrs 2rels \ 12 RP-db.sql
13 ))
14 13
15idiscover_SOURCES = idiscover.cc 14idiscover_SOURCES = idiscover.cc
16idiscover_LDADD = ${top_builddir}/lib/libopkele.la 15idiscover_LDADD = ${top_builddir}/lib/libopkele.la
16
17if HAVE_SQLITE3
18if HAVE_KINGATE
19if HAVE_UUID
20
21RP_cgi_SOURCES = RP.cc
22nodist_RP_cgi_SOURCES = RP-db.cc
23RP_cgi_LDADD = ${top_builddir}/lib/libopkele.la \
24 ${SQLITE3_LIBS} ${KINGATE_LIBS} ${UUID_LIBS}
25RP_cgi_CFLAGS = ${SQLITE3_CFLAGS} ${KINGATE_CFLAGS} ${UUID_CFLAGS}
26
27RP-db.cc: RP-db.sql
28 ( \
29 echo 'const char * __RP_db_bootstrap = ' && \
30 sed -e 's/^/"/' -e 's/$$/"/' $< && \
31 echo ';' \
32 ) >$@
33
34clean-local:
35 rm -f RP-db.cc
36
37endif #HAVE_UUID
38endif #HAVE_KINGATE
39endif #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 @@
1CREATE TABLE assoc (
2 a_op text,
3 a_handle text NOT NULL,
4 a_type text DEFAULT 'HMAC-SHA1',
5 a_ctime text NOT NULL,
6 a_etime text NOT NULL,
7 a_secret text NOT NULL,
8 a_stateless integer NOT NULL DEFAULT 0,
9 a_itime integer,
10 UNIQUE(a_op,a_handle)
11);
12
13CREATE TABLE nonces (
14 n_op text NOT NULL,
15 n_once text NOT NULL,
16 PRIMARY KEY (n_op,n_once)
17);
18
19CREATE TABLE ht_sessions (
20 hts_id text NOT NULL PRIMARY KEY
21);
22
23CREATE TABLE auth_sessions (
24 as_id integer PRIMARY KEY AUTOINCREMENT,
25 hts_id text NOT NULL REFERENCES ht_sessions(hts_id),
26 as_normalized_id text,
27 UNIQUE (hts_id,as_id)
28);
29
30CREATE TABLE endpoints_queue (
31 as_id integer NOT NULL REFERENCES auth_sessions (as_id),
32 eq_ctime integer NOT NULL,
33 eq_ordinal integer NOT NULL,
34 eq_uri text,
35 eq_claimed_id text,
36 eq_local_id text
37);
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 @@
1#include <uuid/uuid.h>
2#include <iostream>
3#include <cassert>
4#include <stdexcept>
5#include <string>
6#include <set>
7#include <iterator>
8using namespace std;
9#include <kingate/exception.h>
10#include <kingate/plaincgi.h>
11#include <kingate/cgi_gateway.h>
12#include <opkele/exception.h>
13#include <opkele/types.h>
14#include <opkele/util.h>
15#include <opkele/uris.h>
16#include <opkele/discovery.h>
17#include <opkele/association.h>
18#include <opkele/sreg.h>
19using namespace opkele;
20#include <opkele/prequeue_rp.h>
21#include <opkele/debug.h>
22
23#include "sqlite.h"
24
25#undef DUMB_RP
26
27#ifdef DUMB_RP
28# define DUMBTHROW throw opkele::dumb_RP(OPKELE_CP_ "This RP is dumb")
29#else
30# define DUMBTHROW (void)0
31#endif
32
33template<typename IT>
34class join_iterator : public iterator<
35 input_iterator_tag,typename IT::value_type,
36 void,typename IT::pointer,typename IT::reference> {
37 public:
38 typedef pair<IT,IT> range_t;
39 typedef list<range_t> ranges_t;
40 ranges_t ranges;
41
42 join_iterator() { }
43
44 bool cleanup() {
45 bool rv = false;
46 while(!(ranges.empty() || ranges.front().first!=ranges.front().second)) {
47 ranges.pop_front(); rv = true;
48 }
49 return rv;
50 }
51
52 join_iterator<IT>& add_range(const IT& b,const IT& e) {
53 ranges.push_back(typename ranges_t::value_type(b,e));
54 cleanup();
55 return *this;
56 }
57
58 bool operator==(const join_iterator<IT>& x) const {
59 return ranges==x.ranges; }
60 bool operator!=(const join_iterator<IT>& x) const {
61 return ranges!=x.ranges; }
62
63 typename IT::reference operator*() const {
64 assert(!ranges.empty());
65 assert(ranges.front().first!=ranges.front().second);
66 return *ranges.front().first; }
67 typename IT::pointer operator->() const {
68 assert(!ranges.empty());
69 assert(ranges.front().first!=ranges.front().second);
70 return ranges.front().first.operator->(); }
71
72 join_iterator<IT>& operator++() {
73 cleanup();
74 if(ranges.empty()) return *this;
75 do {
76 ++ranges.front().first;
77 }while(cleanup() && !ranges.empty());
78 return *this;
79 }
80 join_iterator<IT> operator++(int) {
81 join_iterator<IT> rv(*this);
82 ++(*this); return rv; }
83};
84
85template<typename IT>
86class cut_prefix_filterator : public opkele::util::basic_filterator<IT> {
87 public:
88 string pfx;
89 mutable string tmp;
90
91 cut_prefix_filterator() { }
92 cut_prefix_filterator(const IT& bi,const IT&ei,const string& pfx)
93 : opkele::util::basic_filterator<IT>(bi,ei), pfx(pfx) {
94 this->prepare();
95 }
96
97 bool is_interesting() const {
98 return pfx.length()==0 || !strncmp(this->it->c_str(),pfx.c_str(),pfx.length());
99 }
100
101 typename IT::reference operator*() const {
102 assert(!this->empty);
103 tmp = *this->it; tmp.erase(0,pfx.length());
104 return tmp; }
105 typename IT::pointer operator->() const {
106 assert(!this->empty);
107 return &this->operator*(); }
108};
109
110class kingate_openid_message_t : public opkele::basic_openid_message {
111 typedef join_iterator<kingate::cgi_gateway::params_t::const_iterator> jitterator;
112 typedef opkele::util::map_keys_iterator<
113 jitterator,
114 fields_iterator::value_type,
115 fields_iterator::reference,
116 fields_iterator::pointer> keys_iterator;
117 typedef cut_prefix_filterator<keys_iterator> pfilterator;
118 public:
119 const kingate::cgi_gateway& gw;
120
121 kingate_openid_message_t(const kingate::cgi_gateway& g) : gw(g) { }
122
123 bool has_field(const string& n) const {
124 return gw.has_param("openid."+n); }
125 const string& get_field(const string& n) const {
126 return gw.get_param("openid."+n); }
127
128 fields_iterator fields_begin() const {
129 return
130 pfilterator( keys_iterator(
131 jitterator()
132 .add_range( gw.get.begin(), gw.get.end() )
133 .add_range( gw.post.begin(), gw.post.end() ),
134 jitterator()
135 ), keys_iterator(), "openid." );
136 }
137 fields_iterator fields_end() const {
138 return pfilterator();
139 }
140};
141
142class rpdb_t : public sqlite3_t {
143 public:
144 rpdb_t()
145 : sqlite3_t("/tmp/RP.db") {
146 assert(_D);
147 char **resp; int nrow,ncol; char *errm;
148 if(sqlite3_get_table(
149 _D,"SELECT a_op FROM assoc LIMIT 0",
150 &resp,&nrow,&ncol,&errm)!=SQLITE_OK) {
151 extern const char *__RP_db_bootstrap;
152 DOUT_("Bootstrapping DB");
153 if(sqlite3_exec(_D,__RP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK)
154 throw opkele::exception(OPKELE_CP_ string("Failed to bootstrap SQLite database: ")+errm);
155 }else
156 sqlite3_free_table(resp);
157
158 }
159};
160
161class example_rp_t : public opkele::prequeue_RP {
162 public:
163 mutable rpdb_t db;
164 kingate::cookie htc;
165 long as_id;
166 int ordinal;
167 kingate::cgi_gateway& gw;
168
169 example_rp_t(kingate::cgi_gateway& gw)
170 : ordinal(0), have_eqtop(false), gw(gw), as_id(-1) {
171 try {
172 htc = gw.cookies.get_cookie("ht_session");
173 as_id = opkele::util::string_to_long(gw.get_param("asid"));
174 }catch(kingate::exception_notfound& kenf) {
175 uuid_t uuid; uuid_generate(uuid);
176 htc = kingate::cookie("ht_session",util::encode_base64(uuid,sizeof(uuid)));
177 sqlite3_mem_t<char*> S = sqlite3_mprintf(
178 "INSERT INTO ht_sessions (hts_id) VALUES (%Q)",
179 htc.get_value().c_str());
180 db.exec(S);
181 }
182 }
183
184 /* Global persistent store */
185
186 opkele::assoc_t store_assoc(
187 const string& OP,const string& handle,
188 const string& type,const secret_t& secret,
189 int expires_in) {
190 DUMBTHROW;
191 DOUT_("Storing '" << handle << "' assoc with '" << OP << "'");
192 time_t exp = time(0)+expires_in;
193 sqlite3_mem_t<char*>
194 S = sqlite3_mprintf(
195 "INSERT INTO assoc"
196 " (a_op,a_handle,a_type,a_ctime,a_etime,a_secret)"
197 " VALUES ("
198 " %Q,%Q,%Q,"
199 " datetime('now'), datetime('now','+%d seconds'),"
200 " %Q"
201 " );", OP.c_str(), handle.c_str(), type.c_str(),
202 expires_in,
203 util::encode_base64(&(secret.front()),secret.size()).c_str() );
204 db.exec(S);
205 return opkele::assoc_t(new opkele::association(
206 OP, handle, type, secret, exp, false ));
207 }
208
209 opkele::assoc_t find_assoc(
210 const string& OP) {
211 DUMBTHROW;
212 DOUT_("Looking for an assoc with '" << OP << '\'');
213 sqlite3_mem_t<char*>
214 S = sqlite3_mprintf(
215 "SELECT"
216 " a_op,a_handle,a_type,a_secret,"
217 " strftime('%%s',a_etime) AS a_etime"
218 " FROM assoc"
219 " WHERE a_op=%Q AND a_itime IS NULL AND NOT a_stateless"
220 " AND ( a_etime > datetime('now','-30 seconds') )"
221 " LIMIT 1",
222 OP.c_str());
223 sqlite3_table_t T;
224 int nr,nc;
225 db.get_table(S,T,&nr,&nc);
226 if(nr<1)
227 throw opkele::failed_lookup(OPKELE_CP_ "Couldn't find unexpired handle");
228 assert(nr==1);
229 assert(nc==5);
230 secret_t secret;
231 util::decode_base64(T.get(1,3,nc),secret);
232 DOUT_(" found '" << T.get(1,1,nc) << '\'');
233 return opkele::assoc_t(new opkele::association(
234 T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc),
235 secret, strtol(T.get(1,4,nc),0,0), false ));
236 }
237
238 opkele::assoc_t retrieve_assoc(
239 const string& OP,const string& handle) {
240 DUMBTHROW;
241 DOUT_("Retrieving assoc '" << handle << "' with '" << OP << '\'');
242 sqlite3_mem_t<char*>
243 S = sqlite3_mprintf(
244 "SELECT"
245 " a_op,a_handle,a_type,a_secret,"
246 " strftime('%%s',a_etime) AS a_etime"
247 " FROM assoc"
248 " WHERE a_op=%Q AND a_handle=%Q"
249 " AND a_itime IS NULL AND NOT a_stateless"
250 " LIMIT 1",
251 OP.c_str(),handle.c_str());
252 sqlite3_table_t T;
253 int nr,nc;
254 db.get_table(S,T,&nr,&nc);
255 if(nr<1)
256 throw opkele::failed_lookup(OPKELE_CP_ "couldn't retrieve valid association");
257 assert(nr==1); assert(nc==5);
258 secret_t secret; util::decode_base64(T.get(1,3,nc),secret);
259 DOUT_(" found. type=" << T.get(1,2,nc) << '\'');
260 return opkele::assoc_t(new opkele::association(
261 T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc),
262 secret, strtol(T.get(1,4,nc),0,0), false ));
263 }
264
265 void invalidate_assoc(
266 const string& OP,const string& handle) {
267 DUMBTHROW;
268 DOUT_("Invalidating assoc '" << handle << "' with '" << OP << '\'');
269 sqlite3_mem_t<char*>
270 S = sqlite3_mprintf(
271 "UPDATE assoc SET a_itime=datetime('now')"
272 " WHERE a_op=%Q AND a_handle=%Q",
273 OP.c_str(), handle.c_str() );
274 db.exec(S);
275 }
276
277 void check_nonce(const string& OP,const string& nonce) {
278 DOUT_("Checking nonce '" << nonce << "' from '" << OP << '\'');
279 sqlite3_mem_t<char*>
280 S = sqlite3_mprintf(
281 "SELECT 1 FROM nonces WHERE n_op=%Q AND n_once=%Q",
282 OP.c_str(), nonce.c_str());
283 sqlite3_table_t T;
284 int nr,nc;
285 db.get_table(S,T,&nr,&nc);
286 if(nr)
287 throw opkele::id_res_bad_nonce(OPKELE_CP_ "already seen that nonce");
288 sqlite3_mem_t<char*>
289 SS = sqlite3_mprintf(
290 "INSERT INTO nonces (n_op,n_once) VALUES (%Q,%Q)",
291 OP.c_str(), nonce.c_str());
292 db.exec(SS);
293 }
294
295 /* Session perisistent store */
296
297 void begin_queueing() {
298 assert(as_id>=0);
299 DOUT_("Resetting queue for session '" << htc.get_value() << "'/" << as_id);
300 sqlite3_mem_t<char*> S = sqlite3_mprintf(
301 "DELETE FROM endpoints_queue"
302 " WHERE as_id=%ld",
303 as_id);
304 db.exec(S);
305 }
306
307 void queue_endpoint(const opkele::openid_endpoint_t& ep) {
308 assert(as_id>=0);
309 DOUT_("Queueing endpoint " << ep.claimed_id << " : " << ep.local_id << " @ " << ep.uri);
310 sqlite3_mem_t<char*> S = sqlite3_mprintf(
311 "INSERT INTO endpoints_queue"
312 " (as_id,eq_ctime,eq_ordinal,eq_uri,eq_claimed_id,eq_local_id)"
313 " VALUES (%ld,strftime('%%s','now'),%d,%Q,%Q,%Q)",
314 as_id,ordinal++,
315 ep.uri.c_str(),ep.claimed_id.c_str(),ep.local_id.c_str());
316 db.exec(S);
317 }
318
319 mutable openid_endpoint_t eqtop;
320 mutable bool have_eqtop;
321
322 const openid_endpoint_t& get_endpoint() const {
323 assert(as_id>=0);
324 if(!have_eqtop) {
325 sqlite3_mem_t<char*>
326 S = sqlite3_mprintf(
327 "SELECT"
328 " eq_uri, eq_claimed_id, eq_local_id"
329 " FROM endpoints_queue"
330 " JOIN auth_sessions USING(as_id)"
331 " WHERE hts_id=%Q AND as_id=%ld"
332 " ORDER BY eq_ctime,eq_ordinal"
333 " LIMIT 1",htc.get_value().c_str(),as_id);
334 sqlite3_table_t T; int nr,nc;
335 db.get_table(S,T,&nr,&nc);
336 if(nr<1)
337 throw opkele::exception(OPKELE_CP_ "No more endpoints queued");
338 assert(nr==1); assert(nc==3);
339 eqtop.uri = T.get(1,0,nc);
340 eqtop.claimed_id = T.get(1,1,nc);
341 eqtop.local_id = T.get(1,2,nc);
342 have_eqtop = true;
343 }
344 return eqtop;
345 }
346
347 void next_endpoint() {
348 assert(as_id>=0);
349 get_endpoint();
350 have_eqtop = false;
351 sqlite3_mem_t<char*> S = sqlite3_mprintf(
352 "DELETE FROM endpoints_queue"
353 " WHERE as_id=%ld AND eq_uri=%Q AND eq_local_id=%Q",
354 htc.get_value().c_str(),as_id,
355 eqtop.uri.c_str());
356 db.exec(S);
357 }
358
359 mutable string _cid;
360 mutable string _nid;
361
362 void set_claimed_id(const string& cid) {
363 assert(as_id>=0);
364 sqlite3_mem_t<char*> S = sqlite3_mprintf(
365 "UPDATE auth_sessions"
366 " SET as_claimed_id=%Q"
367 " WHERE hts_id=%Q and as_id=%ld",
368 cid.c_str(),
369 htc.get_value().c_str(),as_id);
370 db.exec(S);
371 _cid = cid;
372 }
373 const string get_claimed_id() const {
374 assert(as_id>=0);
375 if(_cid.empty()) {
376 sqlite3_mem_t<char*> S = sqlite3_mprintf(
377 "SELECT as_claimed_id"
378 " FROM"
379 " auth_sessions"
380 " WHERE"
381 " hts_id=%Q AND as_id=%ld",
382 htc.get_value().c_str(),as_id);
383 sqlite3_table_t T; int nr,nc;
384 db.get_table(S,T,&nr,&nc);
385 assert(nr==1); assert(nc==1);
386 _cid = T.get(1,0,nc);
387 }
388 return _cid;
389 }
390 void set_normalized_id(const string& nid) {
391 assert(as_id>=0);
392 sqlite3_mem_t<char*> S = sqlite3_mprintf(
393 "UPDATE auth_sessions"
394 " SET as_normalized_id=%Q"
395 " WHERE hts_id=%Q and as_id=%ld",
396 nid.c_str(),
397 htc.get_value().c_str(),as_id);
398 db.exec(S);
399 _nid = nid;
400 }
401 const string get_normalized_id() const {
402 assert(as_id>=0);
403 if(_nid.empty()) {
404 sqlite3_mem_t<char*> S = sqlite3_mprintf(
405 "SELECT as_normalized_id"
406 " FROM"
407 " auth_sessions"
408 " WHERE"
409 " hts_id=%Q AND as_id=%ld",
410 htc.get_value().c_str(),as_id);
411 sqlite3_table_t T; int nr,nc;
412 db.get_table(S,T,&nr,&nc);
413 assert(nr==1); assert(nc==1);
414 _nid = T.get(1,0,nc);
415 }
416 return _nid;
417 }
418
419 const string get_this_url() const {
420 bool s = gw.has_meta("SSL_PROTOCOL_VERSION");
421 string rv = s?"https://":"http://";
422 rv += gw.http_request_header("Host");
423 const string& port = gw.get_meta("SERVER_PORT");
424 if( port!=(s?"443":"80") ) {
425 rv += ':'; rv += port;
426 }
427 rv += gw.get_meta("REQUEST_URI");
428 return rv;
429 }
430
431 void initiate(const string& usi) {
432 allocate_asid();
433 prequeue_RP::initiate(usi);
434 }
435
436 string get_self_url() const {
437 string rv = get_this_url();
438 string::size_type q = rv.find('?');
439 if(q!=string::npos)
440 rv.erase(q);
441 return rv;
442 }
443
444 void allocate_asid() {
445 sqlite3_mem_t<char*> S = sqlite3_mprintf(
446 "INSERT INTO auth_sessions (hts_id)"
447 " VALUES (%Q)",
448 htc.get_value().c_str());
449 db.exec(S);
450 as_id = sqlite3_last_insert_rowid(db);
451 DOUT_("Allocated authentication session id "<<as_id);
452 assert(as_id>=0);
453 }
454
455#ifdef DUMB_RP
456 virtual assoc_t associate(const string& OP) {
457 DUMBTHROW;
458 }
459#endif
460};
461
462int main(int argc,char *argv[]) {
463 try {
464 kingate::plaincgi_interface ci;
465 kingate::cgi_gateway gw(ci);
466 string op;
467 try { op = gw.get_param("op"); }catch(kingate::exception_notfound&) { }
468 if(op=="initiate") {
469 example_rp_t rp(gw);
470 string usi = gw.get_param("openid_identity");
471 rp.initiate(usi);
472 opkele::sreg_t sreg(opkele::sreg_t::fields_NONE,opkele::sreg_t::fields_ALL);
473 opkele::openid_message_t cm;
474 string loc;
475 cout <<
476 "Set-Cookie: " << rp.htc.set_cookie_header() << "\n"
477 "Status: 302 Going to OP\n"
478 "Location: " << (
479 loc = rp.checkid_(cm,opkele::mode_checkid_setup,
480 rp.get_self_url()+
481 "?op=confirm&asid="+opkele::util::long_to_string(rp.as_id),
482 rp.get_self_url(),&sreg).append_query(rp.get_endpoint().uri)
483 )
484 << "\n\n";
485 DOUT_("Going to " << loc);
486 }else if(op=="confirm") {
487 kingate_openid_message_t om(gw);
488 example_rp_t rp(gw);
489 opkele::sreg_t sreg(opkele::sreg_t::fields_NONE,opkele::sreg_t::fields_ALL);
490 rp.id_res(om,&sreg);
491 cout <<
492 "Content-Type: text/plain\n\n";
493 for(opkele::basic_openid_message::fields_iterator i=om.fields_begin();
494 i!=om.fields_end();++i) {
495 cout << *i << '=' << om.get_field(*i) << endl;
496 }
497 cout << endl
498 << "SREG fields: " << sreg.has_fields << endl;
499 }else{
500 cout <<
501 "Content-type: text/html\n\n"
502
503 "<html>"
504 "<head><title>test RP</title></head>"
505 "<body>"
506 "<form action='' method='post'>"
507 "<input type='hidden' name='op' value='initiate' />"
508 "<input type='text' name='openid_identity'/>"
509 "<input type='submit' name='submit' value='submit' />"
510 "</form>"
511 "<br/><br/>"
512 "<a href='?op=initiate&amp;openid_identity=www.myopenid.com&amp;dummy=" << time(0) << "'>login with myopenid.com account</a>"
513 "<br/>"
514 "</body"
515 "</html>"
516 ;
517 }
518#ifdef OPKELE_HAVE_KONFORKA
519 }catch(konforka::exception& e) {
520#else
521 }catch(std::exception& e){
522#endif
523 DOUT_("Oops: " << e.what());
524 cout << "Content-Type: text/plain\n\n"
525 "Exception:\n"
526 " what: " << e.what() << endl;
527#ifdef OPKELE_HAVE_KONFORKA
528 cout << " where: " << e.where() << endl;
529 if(!e._seen.empty()) {
530 cout << " seen:" << endl;
531 for(list<konforka::code_point>::const_iterator
532 i=e._seen.begin();i!=e._seen.end();++i) {
533 cout << " " << i->c_str() << endl;
534 }
535 }
536#endif
537 }
538}
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 @@
1<html>
2 <head>
3 <link rel="openid.server openid.delegate" href="http://www.klever.net/openid.server" />
4 </head>
5 <body>
6 </body>
7</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 @@
1<html>
2 <head>
3 </head>
4 <body>
5 <head>
6 <link rel="openid.server" href="http://www.klever.net/openid.server" />
7 <link rel="openid.delegate" href="http://hacker.klever.net/" />
8 </head>
9 </body>
10</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 @@
1<html>
2 <head>
3 <link rel="openid.delegate" href="http://hacker.klever.net/" />
4 </head>
5 <body>
6 </body>
7</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 @@
1<html>
2 <head>
3 <link rel="openid.server" href="http://www.klever.net/openid.server" />
4 </head>
5 <body>
6 </body>
7</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 @@
1<html>
2 <head>
3 <link rel="openid.server" href="http://www.klever.net/openid.server" />
4 <link rel="openid.delegate" href="http://hacker.klever.net/" />
5 </head>
6 <body>
7 </body>
8</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 @@
1<html>
2 <head>
3 </head>
4 <body>
5 <link rel="openid.server" href="http://www.klever.net/openid.server" />
6 <link rel="openid.delegate" href="http://hacker.klever.net/" />
7 </body>
8</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 @@
1<html>
2 <head>
3 <link rel=" openid.server " href=" http://www.klever.net/openid.server" />
4 <link rel=" openid.delegate" href="http://hacker.klever.net/ " />
5 </head>
6 <body>
7 </body>
8</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 @@
1<html>
2 <head>
3 < link rel = "openid.server" href = "http://www.klever.net/openid.server" />
4 <link rel="openid.delegate" href='http://hacker.klever.net/' />
5 </head>
6 <body>
7 </body>
8</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 @@
1<html>
2 <head>
3 <link rel="openid.server" href="http://www.klever.net/openid.server" />
4 <link rel="openid.delegate" href="http://hacker.klever.net/" />
5 <body>
6 </body>
7</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 @@
1#include <iostream> 1#include <iostream>
2#include <stdexcept> 2#include <stdexcept>
3#include <iterator> 3#include <iterator>
4#include <algorithm> 4#include <algorithm>
5using namespace std; 5using namespace std;
6#include <opkele/exception.h> 6#include <opkele/exception.h>
7#include <opkele/discovery.h> 7#include <opkele/discovery.h>
8#include <opkele/util.h>
8 9
9template<typename _PDT> 10namespace opkele {
10 ostream& operator<<(ostream& o,const opkele::xrd::priority_map<_PDT>& pm) { 11 ostream& operator<<(ostream& o,const opkele::openid_endpoint_t& oep) {
11 for(typename opkele::xrd::priority_map<_PDT>::const_iterator i=pm.begin(); 12 o
12 i!=pm.end();++i) 13 << " URI: " << oep.uri << endl
13 o << ' ' << i->second << '[' << i->first << ']'; 14 << " Claimed ID: " << oep.claimed_id << endl
15 << " Local ID: " << oep.local_id << endl;
14 return o; 16 return o;
15 } 17 }
16
17ostream& operator<<(ostream& o,const opkele::xrd::service_t s) {
18 o << "{" << endl
19 << " Type: ";
20 copy(s.types.begin(),s.types.end(),
21 ostream_iterator<string>(o," "));
22 o << endl
23 << " URI: " << s.uris << endl
24 << " LocalID: " << s.local_ids << endl
25 << " ProviderID: " << s.provider_id << endl;
26 o << "}";
27} 18}
28 19
29int main(int argc,char **argv) { 20int main(int argc,char **argv) {
30 try { 21 try {
31 if(argc<2) 22 if(argc<2)
32 throw opkele::exception(OPKELE_CP_ "Please, give me something to resolve"); 23 throw opkele::exception(OPKELE_CP_ "Please, give me something to resolve");
33 for(int a=1;a<argc;++a) { 24 for(int a=1;a<argc;++a) {
34 opkele::idiscovery_t discovery(argv[a]); 25 cout << "==============================================================" << endl
35 clog
36 << "===============================================================" << endl
37 << "User-supplied ID: " << argv[a] << endl 26 << "User-supplied ID: " << argv[a] << endl
38 << "Normalized ID: " << discovery.normalized_id << endl 27 << "Endpoints:" << endl
39 << "Canonicalized ID: " << discovery.canonicalized_id << endl 28 << " --" << endl;
40 << "The identity is " << (discovery.xri_identity?"":"not ") << "an i-name" << endl; 29 string normalized = opkele::idiscover(
41 if(discovery.xrd.expires) 30 ostream_iterator<opkele::openid_endpoint_t>(cout," --\n")
42 clog << "Information expires in " << discovery.xrd.expires-time(0) << " seconds" << endl; 31 ,argv[a]);
43 clog << endl 32 cout << "Normalized ID: " << normalized << endl;
44 << "CanonicalID: " << discovery.xrd.canonical_ids << endl
45 << "LocalID: " << discovery.xrd.local_ids << endl
46 << "ProviderID: " << discovery.xrd.provider_id << endl
47 << "Services: " << discovery.xrd.services << endl;
48 } 33 }
49 }catch(exception& e) { 34 }catch(exception& e) {
50 cerr << "oops: " << e.what() << endl; 35 cerr << "oops, caught " << opkele::util::abi_demangle(typeid(e).name()) << endl
36 << " .what(): " << e.what() << endl;
51 _exit(1); 37 _exit(1);
52 } 38 }
53 _exit(0); 39 _exit(0);
54} 40}
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 @@
1#include <sqlite3.h>
2
3class sqlite3_t {
4 public:
5 sqlite3 *_D;
6
7 sqlite3_t(const char *f)
8 : _D(0) {
9 int r = sqlite3_open(f,&_D);
10 if(r!=SQLITE_OK) {
11 string msg = sqlite3_errmsg(_D); sqlite3_close(_D);
12 throw opkele::exception(OPKELE_CP_ "Failed to open SQLite database: "+msg);
13 }
14 }
15 ~sqlite3_t() {
16 if(_D) sqlite3_close(_D);
17 }
18
19 operator const sqlite3*(void) const { return _D; }
20 operator sqlite3*(void) { return _D; }
21
22 void exec(const char *sql) {
23 assert(_D);
24 char *errm;
25 if(sqlite3_exec(_D,sql,NULL,NULL,&errm)!=SQLITE_OK)
26 throw opkele::exception(OPKELE_CP_ string("Failed to sqlite3_exec():")+errm);
27 }
28 void get_table(const char *sql,char ***resp,int *nr,int *nc) {
29 assert(_D);
30 char *errm;
31 if(sqlite3_get_table(_D,sql,resp,nr,nc,&errm)!=SQLITE_OK)
32 throw opkele::exception(OPKELE_CP_ string("Failed to sqlite3_get_table():")+errm);
33 }
34};
35
36template<typename T>
37class sqlite3_mem_t {
38 public:
39 T _M;
40
41 sqlite3_mem_t(T M) :_M(M) { }
42 ~sqlite3_mem_t() { if(_M) sqlite3_free(_M); }
43
44 operator const T&(void) const { return _M; }
45 operator T&(void) { return _M; }
46
47 sqlite3_mem_t operator=(T M) {
48 if(_M) sqlite3_free(_M);
49 _M = M;
50 }
51};
52
53class sqlite3_table_t {
54 public:
55 char **_T;
56
57 sqlite3_table_t() : _T(0) { }
58 sqlite3_table_t(char **T) : _T(T) { }
59 ~sqlite3_table_t() { if(_T) sqlite3_free_table(_T); }
60
61 operator char**&(void) { return _T; }
62
63 operator char ***(void) {
64 if(_T) sqlite3_free_table(_T);
65 return &_T; }
66
67 const char *get(int r,int c,int nc) {
68 assert(_T);
69 return _T[r*nc+c];
70 }
71};
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 @@
1#include <iostream> 1#include <iostream>
2#include <stdexcept> 2#include <stdexcept>
3using namespace std; 3using namespace std;
4#include <opkele/exception.h> 4#include <opkele/exception.h>
5#include <opkele/consumer.h>
6#include <opkele/util.h> 5#include <opkele/util.h>
7 6
8#include "config.h" 7#include "config.h"
9 8
10class failed_test : public opkele::exception { 9class failed_test : public opkele::exception {
11 public: 10 public:
12 failed_test(OPKELE_E_PARS) 11 failed_test(OPKELE_E_PARS)
13 : exception(OPKELE_E_CONS) { } 12 : exception(OPKELE_E_CONS) { }
14}; 13};
15 14
16class dummy_consumer_t : public opkele::consumer_t {
17 public:
18 virtual opkele::assoc_t store_assoc(const string& /* server */,const string& /* handle */,const opkele::secret_t& /* secret */,int /* expires_in */) {
19 throw opkele::not_implemented(OPKELE_CP_ "Not implemented");
20 }
21 virtual opkele::assoc_t retrieve_assoc(const string& /* server */ ,const string& /* handle */) {
22 throw opkele::not_implemented(OPKELE_CP_ "Not implemented");
23 }
24 virtual void invalidate_assoc(const string& /* server */,const string& /* handle */) {
25 throw opkele::not_implemented(OPKELE_CP_ "Not implemented");
26 }
27};
28
29
30void test_retrieve_links(const string& f,bool success,const string& s="",const string& d="") {
31 dummy_consumer_t dc;
32 string server, delegate;
33 try {
34 dc.retrieve_links("file://" OPKELE_SRC_DIR "/test/html/"+f,server,delegate);
35 if(!success)
36 throw failed_test(OPKELE_CP_ "Retrieved links when it shouldn't");
37 if(server!=s)
38 throw failed_test(OPKELE_CP_ "retrieve_links test failed, expected server '"+s+"', got '"+server+"'");
39 if(delegate!=d)
40 throw failed_test(OPKELE_CP_ "retrieve_links test failed, expected delegate '"+d+"', got '"+delegate+"'");
41 }catch(opkele::bad_input& obi) {
42 if(success)
43 throw failed_test(OPKELE_CP_ "Test '"+f+"' failed due to 'bad_input'["+obi.what()+"]");
44 }catch(opkele::failed_assertion& ofa) {
45 if(success)
46 throw failed_test(OPKELE_CP_ "Test '"+f+"' failed due to 'failed_assertion'["+ofa.what()+"]");
47 }
48}
49
50void test_retrieve_links() {
51 test_retrieve_links("empty.html",false);
52 test_retrieve_links("in-body.html",false);
53 test_retrieve_links("head-in-body.html",false);
54 test_retrieve_links("hkn.html",true,"http://www.klever.net/openid.server","http://hacker.klever.net/");
55 test_retrieve_links("hkn-server.html",true,"http://www.klever.net/openid.server");
56 test_retrieve_links("hkn-delegate.html",false);
57 test_retrieve_links("unclosed-head.html",true,"http://www.klever.net/openid.server","http://hacker.klever.net/");
58 test_retrieve_links("spaced-links.html",true,"http://www.klever.net/openid.server","http://hacker.klever.net/");
59 test_retrieve_links("spaced-link-attrs.html",true,"http://www.klever.net/openid.server","http://hacker.klever.net/");
60 test_retrieve_links("2rels.html",true,"http://www.klever.net/openid.server","http://www.klever.net/openid.server");
61}
62
63void test_rfc_3986_normalize_uri(const string &ouri,bool success,const string& nuri="") { 15void test_rfc_3986_normalize_uri(const string &ouri,bool success,const string& nuri="") {
64 try { 16 try {
65 string n = opkele::util::rfc_3986_normalize_uri(ouri); 17 string n = opkele::util::rfc_3986_normalize_uri(ouri);
66 if(!success) 18 if(!success)
67 throw failed_test(OPKELE_CP_ "Normalized URI when it shouldn't"); 19 throw failed_test(OPKELE_CP_ "Normalized URI when it shouldn't");
68 if(n!=nuri) 20 if(n!=nuri)
69 throw failed_test(OPKELE_CP_ "rfc_3986_test_failed for '"+ouri+"' failed, expected '"+nuri+"', got '"+n+"'"); 21 throw failed_test(OPKELE_CP_ "rfc_3986_test_failed for '"+ouri+"' failed, expected '"+nuri+"', got '"+n+"'");
70 }catch(opkele::bad_input& obi) { 22 }catch(opkele::bad_input& obi) {
71 if(success) 23 if(success)
72 throw failed_test(OPKELE_CP_ "Test '"+ouri+"' failed due to 'bad_input'["+obi.what()+"]"); 24 throw failed_test(OPKELE_CP_ "Test '"+ouri+"' failed due to 'bad_input'["+obi.what()+"]");
73 }catch(opkele::not_implemented& oni) { 25 }catch(opkele::not_implemented& oni) {
74 if(success) 26 if(success)
75 throw failed_test(OPKELE_CP_ "Test '"+ouri+"' failed due to 'not_implemented'["+oni.what()+"]"); 27 throw failed_test(OPKELE_CP_ "Test '"+ouri+"' failed due to 'not_implemented'["+oni.what()+"]");
76 } 28 }
77} 29}
78 30
79void test_rfc_3986_normalize_uri() { 31void test_rfc_3986_normalize_uri() {
80 test_rfc_3986_normalize_uri( 32 test_rfc_3986_normalize_uri(
81 "invalid", false ); 33 "invalid", false );
82 test_rfc_3986_normalize_uri( 34 test_rfc_3986_normalize_uri(
83 "ftp://hacker.klever.net/", false ); 35 "ftp://hacker.klever.net/", false );
84 test_rfc_3986_normalize_uri( 36 test_rfc_3986_normalize_uri(
85 "http://", false ); 37 "http://", false );
86 test_rfc_3986_normalize_uri( 38 test_rfc_3986_normalize_uri(
87 "http:/hacker.klever.net/", false ); 39 "http:/hacker.klever.net/", false );
88 test_rfc_3986_normalize_uri( 40 test_rfc_3986_normalize_uri(
89 "hTTp://hacker.klever.net#uh?oh", true, "http://hacker.klever.net/#uh?oh" ); 41 "hTTp://hacker.klever.net#uh?oh", true, "http://hacker.klever.net/#uh?oh" );
90 test_rfc_3986_normalize_uri( 42 test_rfc_3986_normalize_uri(
91 "http://hacker.klever.net?uh#oh", true, "http://hacker.klever.net/?uh#oh" ); 43 "http://hacker.klever.net?uh#oh", true, "http://hacker.klever.net/?uh#oh" );
92 test_rfc_3986_normalize_uri( 44 test_rfc_3986_normalize_uri(
93 "http://hacker.klever.net:80/", true, "http://hacker.klever.net/" ); 45 "http://hacker.klever.net:80/", true, "http://hacker.klever.net/" );
94 test_rfc_3986_normalize_uri( 46 test_rfc_3986_normalize_uri(
95 "http://hacker.klever.net:80?uh", true, "http://hacker.klever.net/?uh" ); 47 "http://hacker.klever.net:80?uh", true, "http://hacker.klever.net/?uh" );
96 test_rfc_3986_normalize_uri( 48 test_rfc_3986_normalize_uri(
97 "http://hacker.klever.net:80#uh", true, "http://hacker.klever.net/#uh" ); 49 "http://hacker.klever.net:80#uh", true, "http://hacker.klever.net/#uh" );
98 test_rfc_3986_normalize_uri( 50 test_rfc_3986_normalize_uri(
99 "https://hacker.klever.net:443", true, "https://hacker.klever.net/" ); 51 "https://hacker.klever.net:443", true, "https://hacker.klever.net/" );
100 test_rfc_3986_normalize_uri( 52 test_rfc_3986_normalize_uri(
101 "http://hacker.klever.net:?oh", true, "http://hacker.klever.net/?oh" ); 53 "http://hacker.klever.net:?oh", true, "http://hacker.klever.net/?oh" );
102 test_rfc_3986_normalize_uri( 54 test_rfc_3986_normalize_uri(
103 "http://hacker.klever.net/ah%2E", true, "http://hacker.klever.net/ah." ); 55 "http://hacker.klever.net/ah%2E", true, "http://hacker.klever.net/ah." );
104 test_rfc_3986_normalize_uri( 56 test_rfc_3986_normalize_uri(
105 "http://hacker.klever.net/ah/%2E/", true, "http://hacker.klever.net/ah/" ); 57 "http://hacker.klever.net/ah/%2E/", true, "http://hacker.klever.net/ah/" );
106 test_rfc_3986_normalize_uri( 58 test_rfc_3986_normalize_uri(
107 "http://hacker.klever.net/ah/%2b/", true, "http://hacker.klever.net/ah/%2B/" ); 59 "http://hacker.klever.net/ah/%2b/", true, "http://hacker.klever.net/ah/%2B/" );
108 test_rfc_3986_normalize_uri( 60 test_rfc_3986_normalize_uri(
109 "http://hacker.klever.net/ah/./oh?eh", true, "http://hacker.klever.net/ah/oh?eh" ); 61 "http://hacker.klever.net/ah/./oh?eh", true, "http://hacker.klever.net/ah/oh?eh" );
110 test_rfc_3986_normalize_uri( 62 test_rfc_3986_normalize_uri(
111 "http://hacker.klever.net/ah/../oh?", true, "http://hacker.klever.net/oh?" ); 63 "http://hacker.klever.net/ah/../oh?", true, "http://hacker.klever.net/oh?" );
112 test_rfc_3986_normalize_uri( 64 test_rfc_3986_normalize_uri(
113 "http://hacker.klever.net/ah//oh?", true, "http://hacker.klever.net/ah/oh?" ); 65 "http://hacker.klever.net/ah//oh?", true, "http://hacker.klever.net/ah/oh?" );
114 test_rfc_3986_normalize_uri( 66 test_rfc_3986_normalize_uri(
115 "http://hacker.klever.net/ah/?", true, "http://hacker.klever.net/ah/?" ); 67 "http://hacker.klever.net/ah/?", true, "http://hacker.klever.net/ah/?" );
116 test_rfc_3986_normalize_uri( 68 test_rfc_3986_normalize_uri(
117 "http://hacker.klever.net/ah/%", false ); 69 "http://hacker.klever.net/ah/%", false );
118 test_rfc_3986_normalize_uri( 70 test_rfc_3986_normalize_uri(
119 "http://hacker.klever.net/ah/%a", false ); 71 "http://hacker.klever.net/ah/%a", false );
120 test_rfc_3986_normalize_uri( 72 test_rfc_3986_normalize_uri(
121 "http://hacker.klever.net/ah/%zx", false ); 73 "http://hacker.klever.net/ah/%zx", false );
122 test_rfc_3986_normalize_uri( 74 test_rfc_3986_normalize_uri(
123 "http://hacker.klever.net/ah/%5x", false ); 75 "http://hacker.klever.net/ah/%5x", false );
124 test_rfc_3986_normalize_uri( 76 test_rfc_3986_normalize_uri(
125 "Http://Hacker.Klever.Net:", true, "http://hacker.klever.net/" ); 77 "Http://Hacker.Klever.Net:", true, "http://hacker.klever.net/" );
126} 78}
127 79
128int main() { 80int main() {
129 try { 81 try {
130 test_rfc_3986_normalize_uri(); 82 test_rfc_3986_normalize_uri();
131 test_retrieve_links();
132 }catch(failed_test& ft) { 83 }catch(failed_test& ft) {
133 cerr << "Test failed: " << ft.what() << endl; 84 cerr << "Test failed: " << ft.what() << endl;
134 }catch(exception& e) { 85 }catch(exception& e) {
135 cerr << "oops: " << e.what() << endl; 86 cerr << "oops: " << e.what() << endl;
136 _exit(1); 87 _exit(1);
137 } 88 }
138 _exit(0); 89 _exit(0);
139} 90}