-rw-r--r-- | test/RP.cc | 110 | ||||
-rw-r--r-- | test/kingate_openid_message.h | 108 |
2 files changed, 109 insertions, 109 deletions
@@ -1,333 +1,225 @@ | |||
1 | #include <uuid/uuid.h> | 1 | #include <uuid/uuid.h> |
2 | #include <iostream> | 2 | #include <iostream> |
3 | #include <cassert> | 3 | #include <cassert> |
4 | #include <stdexcept> | 4 | #include <stdexcept> |
5 | #include <string> | 5 | #include <string> |
6 | #include <set> | 6 | #include <set> |
7 | #include <iterator> | 7 | #include <iterator> |
8 | using namespace std; | 8 | using namespace std; |
9 | #include <kingate/exception.h> | 9 | #include <kingate/exception.h> |
10 | #include <kingate/plaincgi.h> | 10 | #include <kingate/plaincgi.h> |
11 | #include <kingate/cgi_gateway.h> | 11 | #include <kingate/cgi_gateway.h> |
12 | #include <opkele/exception.h> | 12 | #include <opkele/exception.h> |
13 | #include <opkele/types.h> | 13 | #include <opkele/types.h> |
14 | #include <opkele/util.h> | 14 | #include <opkele/util.h> |
15 | #include <opkele/uris.h> | 15 | #include <opkele/uris.h> |
16 | #include <opkele/discovery.h> | 16 | #include <opkele/discovery.h> |
17 | #include <opkele/association.h> | 17 | #include <opkele/association.h> |
18 | #include <opkele/sreg.h> | 18 | #include <opkele/sreg.h> |
19 | using namespace opkele; | 19 | using namespace opkele; |
20 | #include <opkele/prequeue_rp.h> | 20 | #include <opkele/prequeue_rp.h> |
21 | #include <opkele/debug.h> | 21 | #include <opkele/debug.h> |
22 | 22 | ||
23 | #include "sqlite.h" | 23 | #include "sqlite.h" |
24 | #include "kingate_openid_message.h" | ||
24 | 25 | ||
25 | #undef DUMB_RP | 26 | #undef DUMB_RP |
26 | 27 | ||
27 | #ifdef DUMB_RP | 28 | #ifdef DUMB_RP |
28 | # define DUMBTHROW throw opkele::dumb_RP(OPKELE_CP_ "This RP is dumb") | 29 | # define DUMBTHROW throw opkele::dumb_RP(OPKELE_CP_ "This RP is dumb") |
29 | #else | 30 | #else |
30 | # define DUMBTHROW (void)0 | 31 | # define DUMBTHROW (void)0 |
31 | #endif | 32 | #endif |
32 | 33 | ||
33 | template<typename IT> | ||
34 | class 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 | |||
85 | template<typename IT> | ||
86 | class 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 | |||
110 | class 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 | |||
142 | class rpdb_t : public sqlite3_t { | 34 | class rpdb_t : public sqlite3_t { |
143 | public: | 35 | public: |
144 | rpdb_t() | 36 | rpdb_t() |
145 | : sqlite3_t("/tmp/RP.db") { | 37 | : sqlite3_t("/tmp/RP.db") { |
146 | assert(_D); | 38 | assert(_D); |
147 | char **resp; int nrow,ncol; char *errm; | 39 | char **resp; int nrow,ncol; char *errm; |
148 | if(sqlite3_get_table( | 40 | if(sqlite3_get_table( |
149 | _D,"SELECT a_op FROM assoc LIMIT 0", | 41 | _D,"SELECT a_op FROM assoc LIMIT 0", |
150 | &resp,&nrow,&ncol,&errm)!=SQLITE_OK) { | 42 | &resp,&nrow,&ncol,&errm)!=SQLITE_OK) { |
151 | extern const char *__RP_db_bootstrap; | 43 | extern const char *__RP_db_bootstrap; |
152 | DOUT_("Bootstrapping DB"); | 44 | DOUT_("Bootstrapping DB"); |
153 | if(sqlite3_exec(_D,__RP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK) | 45 | 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); | 46 | throw opkele::exception(OPKELE_CP_ string("Failed to bootstrap SQLite database: ")+errm); |
155 | }else | 47 | }else |
156 | sqlite3_free_table(resp); | 48 | sqlite3_free_table(resp); |
157 | 49 | ||
158 | } | 50 | } |
159 | }; | 51 | }; |
160 | 52 | ||
161 | class example_rp_t : public opkele::prequeue_RP { | 53 | class example_rp_t : public opkele::prequeue_RP { |
162 | public: | 54 | public: |
163 | mutable rpdb_t db; | 55 | mutable rpdb_t db; |
164 | kingate::cookie htc; | 56 | kingate::cookie htc; |
165 | long as_id; | 57 | long as_id; |
166 | int ordinal; | 58 | int ordinal; |
167 | kingate::cgi_gateway& gw; | 59 | kingate::cgi_gateway& gw; |
168 | 60 | ||
169 | example_rp_t(kingate::cgi_gateway& gw) | 61 | example_rp_t(kingate::cgi_gateway& gw) |
170 | : ordinal(0), have_eqtop(false), gw(gw), as_id(-1) { | 62 | : ordinal(0), have_eqtop(false), gw(gw), as_id(-1) { |
171 | try { | 63 | try { |
172 | htc = gw.cookies.get_cookie("ht_session"); | 64 | htc = gw.cookies.get_cookie("ht_session"); |
173 | as_id = opkele::util::string_to_long(gw.get_param("asid")); | 65 | as_id = opkele::util::string_to_long(gw.get_param("asid")); |
174 | }catch(kingate::exception_notfound& kenf) { | 66 | }catch(kingate::exception_notfound& kenf) { |
175 | uuid_t uuid; uuid_generate(uuid); | 67 | uuid_t uuid; uuid_generate(uuid); |
176 | htc = kingate::cookie("ht_session",util::encode_base64(uuid,sizeof(uuid))); | 68 | htc = kingate::cookie("ht_session",util::encode_base64(uuid,sizeof(uuid))); |
177 | sqlite3_mem_t<char*> S = sqlite3_mprintf( | 69 | sqlite3_mem_t<char*> S = sqlite3_mprintf( |
178 | "INSERT INTO ht_sessions (hts_id) VALUES (%Q)", | 70 | "INSERT INTO ht_sessions (hts_id) VALUES (%Q)", |
179 | htc.get_value().c_str()); | 71 | htc.get_value().c_str()); |
180 | db.exec(S); | 72 | db.exec(S); |
181 | } | 73 | } |
182 | } | 74 | } |
183 | 75 | ||
184 | /* Global persistent store */ | 76 | /* Global persistent store */ |
185 | 77 | ||
186 | opkele::assoc_t store_assoc( | 78 | opkele::assoc_t store_assoc( |
187 | const string& OP,const string& handle, | 79 | const string& OP,const string& handle, |
188 | const string& type,const secret_t& secret, | 80 | const string& type,const secret_t& secret, |
189 | int expires_in) { | 81 | int expires_in) { |
190 | DUMBTHROW; | 82 | DUMBTHROW; |
191 | DOUT_("Storing '" << handle << "' assoc with '" << OP << "'"); | 83 | DOUT_("Storing '" << handle << "' assoc with '" << OP << "'"); |
192 | time_t exp = time(0)+expires_in; | 84 | time_t exp = time(0)+expires_in; |
193 | sqlite3_mem_t<char*> | 85 | sqlite3_mem_t<char*> |
194 | S = sqlite3_mprintf( | 86 | S = sqlite3_mprintf( |
195 | "INSERT INTO assoc" | 87 | "INSERT INTO assoc" |
196 | " (a_op,a_handle,a_type,a_ctime,a_etime,a_secret)" | 88 | " (a_op,a_handle,a_type,a_ctime,a_etime,a_secret)" |
197 | " VALUES (" | 89 | " VALUES (" |
198 | " %Q,%Q,%Q," | 90 | " %Q,%Q,%Q," |
199 | " datetime('now'), datetime('now','+%d seconds')," | 91 | " datetime('now'), datetime('now','+%d seconds')," |
200 | " %Q" | 92 | " %Q" |
201 | " );", OP.c_str(), handle.c_str(), type.c_str(), | 93 | " );", OP.c_str(), handle.c_str(), type.c_str(), |
202 | expires_in, | 94 | expires_in, |
203 | util::encode_base64(&(secret.front()),secret.size()).c_str() ); | 95 | util::encode_base64(&(secret.front()),secret.size()).c_str() ); |
204 | db.exec(S); | 96 | db.exec(S); |
205 | return opkele::assoc_t(new opkele::association( | 97 | return opkele::assoc_t(new opkele::association( |
206 | OP, handle, type, secret, exp, false )); | 98 | OP, handle, type, secret, exp, false )); |
207 | } | 99 | } |
208 | 100 | ||
209 | opkele::assoc_t find_assoc( | 101 | opkele::assoc_t find_assoc( |
210 | const string& OP) { | 102 | const string& OP) { |
211 | DUMBTHROW; | 103 | DUMBTHROW; |
212 | DOUT_("Looking for an assoc with '" << OP << '\''); | 104 | DOUT_("Looking for an assoc with '" << OP << '\''); |
213 | sqlite3_mem_t<char*> | 105 | sqlite3_mem_t<char*> |
214 | S = sqlite3_mprintf( | 106 | S = sqlite3_mprintf( |
215 | "SELECT" | 107 | "SELECT" |
216 | " a_op,a_handle,a_type,a_secret," | 108 | " a_op,a_handle,a_type,a_secret," |
217 | " strftime('%%s',a_etime) AS a_etime" | 109 | " strftime('%%s',a_etime) AS a_etime" |
218 | " FROM assoc" | 110 | " FROM assoc" |
219 | " WHERE a_op=%Q AND a_itime IS NULL AND NOT a_stateless" | 111 | " WHERE a_op=%Q AND a_itime IS NULL AND NOT a_stateless" |
220 | " AND ( a_etime > datetime('now','-30 seconds') )" | 112 | " AND ( a_etime > datetime('now','-30 seconds') )" |
221 | " LIMIT 1", | 113 | " LIMIT 1", |
222 | OP.c_str()); | 114 | OP.c_str()); |
223 | sqlite3_table_t T; | 115 | sqlite3_table_t T; |
224 | int nr,nc; | 116 | int nr,nc; |
225 | db.get_table(S,T,&nr,&nc); | 117 | db.get_table(S,T,&nr,&nc); |
226 | if(nr<1) | 118 | if(nr<1) |
227 | throw opkele::failed_lookup(OPKELE_CP_ "Couldn't find unexpired handle"); | 119 | throw opkele::failed_lookup(OPKELE_CP_ "Couldn't find unexpired handle"); |
228 | assert(nr==1); | 120 | assert(nr==1); |
229 | assert(nc==5); | 121 | assert(nc==5); |
230 | secret_t secret; | 122 | secret_t secret; |
231 | util::decode_base64(T.get(1,3,nc),secret); | 123 | util::decode_base64(T.get(1,3,nc),secret); |
232 | DOUT_(" found '" << T.get(1,1,nc) << '\''); | 124 | DOUT_(" found '" << T.get(1,1,nc) << '\''); |
233 | return opkele::assoc_t(new opkele::association( | 125 | return opkele::assoc_t(new opkele::association( |
234 | T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), | 126 | 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 )); | 127 | secret, strtol(T.get(1,4,nc),0,0), false )); |
236 | } | 128 | } |
237 | 129 | ||
238 | opkele::assoc_t retrieve_assoc( | 130 | opkele::assoc_t retrieve_assoc( |
239 | const string& OP,const string& handle) { | 131 | const string& OP,const string& handle) { |
240 | DUMBTHROW; | 132 | DUMBTHROW; |
241 | DOUT_("Retrieving assoc '" << handle << "' with '" << OP << '\''); | 133 | DOUT_("Retrieving assoc '" << handle << "' with '" << OP << '\''); |
242 | sqlite3_mem_t<char*> | 134 | sqlite3_mem_t<char*> |
243 | S = sqlite3_mprintf( | 135 | S = sqlite3_mprintf( |
244 | "SELECT" | 136 | "SELECT" |
245 | " a_op,a_handle,a_type,a_secret," | 137 | " a_op,a_handle,a_type,a_secret," |
246 | " strftime('%%s',a_etime) AS a_etime" | 138 | " strftime('%%s',a_etime) AS a_etime" |
247 | " FROM assoc" | 139 | " FROM assoc" |
248 | " WHERE a_op=%Q AND a_handle=%Q" | 140 | " WHERE a_op=%Q AND a_handle=%Q" |
249 | " AND a_itime IS NULL AND NOT a_stateless" | 141 | " AND a_itime IS NULL AND NOT a_stateless" |
250 | " LIMIT 1", | 142 | " LIMIT 1", |
251 | OP.c_str(),handle.c_str()); | 143 | OP.c_str(),handle.c_str()); |
252 | sqlite3_table_t T; | 144 | sqlite3_table_t T; |
253 | int nr,nc; | 145 | int nr,nc; |
254 | db.get_table(S,T,&nr,&nc); | 146 | db.get_table(S,T,&nr,&nc); |
255 | if(nr<1) | 147 | if(nr<1) |
256 | throw opkele::failed_lookup(OPKELE_CP_ "couldn't retrieve valid association"); | 148 | throw opkele::failed_lookup(OPKELE_CP_ "couldn't retrieve valid association"); |
257 | assert(nr==1); assert(nc==5); | 149 | assert(nr==1); assert(nc==5); |
258 | secret_t secret; util::decode_base64(T.get(1,3,nc),secret); | 150 | secret_t secret; util::decode_base64(T.get(1,3,nc),secret); |
259 | DOUT_(" found. type=" << T.get(1,2,nc) << '\''); | 151 | DOUT_(" found. type=" << T.get(1,2,nc) << '\''); |
260 | return opkele::assoc_t(new opkele::association( | 152 | return opkele::assoc_t(new opkele::association( |
261 | T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), | 153 | 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 )); | 154 | secret, strtol(T.get(1,4,nc),0,0), false )); |
263 | } | 155 | } |
264 | 156 | ||
265 | void invalidate_assoc( | 157 | void invalidate_assoc( |
266 | const string& OP,const string& handle) { | 158 | const string& OP,const string& handle) { |
267 | DUMBTHROW; | 159 | DUMBTHROW; |
268 | DOUT_("Invalidating assoc '" << handle << "' with '" << OP << '\''); | 160 | DOUT_("Invalidating assoc '" << handle << "' with '" << OP << '\''); |
269 | sqlite3_mem_t<char*> | 161 | sqlite3_mem_t<char*> |
270 | S = sqlite3_mprintf( | 162 | S = sqlite3_mprintf( |
271 | "UPDATE assoc SET a_itime=datetime('now')" | 163 | "UPDATE assoc SET a_itime=datetime('now')" |
272 | " WHERE a_op=%Q AND a_handle=%Q", | 164 | " WHERE a_op=%Q AND a_handle=%Q", |
273 | OP.c_str(), handle.c_str() ); | 165 | OP.c_str(), handle.c_str() ); |
274 | db.exec(S); | 166 | db.exec(S); |
275 | } | 167 | } |
276 | 168 | ||
277 | void check_nonce(const string& OP,const string& nonce) { | 169 | void check_nonce(const string& OP,const string& nonce) { |
278 | DOUT_("Checking nonce '" << nonce << "' from '" << OP << '\''); | 170 | DOUT_("Checking nonce '" << nonce << "' from '" << OP << '\''); |
279 | sqlite3_mem_t<char*> | 171 | sqlite3_mem_t<char*> |
280 | S = sqlite3_mprintf( | 172 | S = sqlite3_mprintf( |
281 | "SELECT 1 FROM nonces WHERE n_op=%Q AND n_once=%Q", | 173 | "SELECT 1 FROM nonces WHERE n_op=%Q AND n_once=%Q", |
282 | OP.c_str(), nonce.c_str()); | 174 | OP.c_str(), nonce.c_str()); |
283 | sqlite3_table_t T; | 175 | sqlite3_table_t T; |
284 | int nr,nc; | 176 | int nr,nc; |
285 | db.get_table(S,T,&nr,&nc); | 177 | db.get_table(S,T,&nr,&nc); |
286 | if(nr) | 178 | if(nr) |
287 | throw opkele::id_res_bad_nonce(OPKELE_CP_ "already seen that nonce"); | 179 | throw opkele::id_res_bad_nonce(OPKELE_CP_ "already seen that nonce"); |
288 | sqlite3_mem_t<char*> | 180 | sqlite3_mem_t<char*> |
289 | SS = sqlite3_mprintf( | 181 | SS = sqlite3_mprintf( |
290 | "INSERT INTO nonces (n_op,n_once) VALUES (%Q,%Q)", | 182 | "INSERT INTO nonces (n_op,n_once) VALUES (%Q,%Q)", |
291 | OP.c_str(), nonce.c_str()); | 183 | OP.c_str(), nonce.c_str()); |
292 | db.exec(SS); | 184 | db.exec(SS); |
293 | } | 185 | } |
294 | 186 | ||
295 | /* Session perisistent store */ | 187 | /* Session perisistent store */ |
296 | 188 | ||
297 | void begin_queueing() { | 189 | void begin_queueing() { |
298 | assert(as_id>=0); | 190 | assert(as_id>=0); |
299 | DOUT_("Resetting queue for session '" << htc.get_value() << "'/" << as_id); | 191 | DOUT_("Resetting queue for session '" << htc.get_value() << "'/" << as_id); |
300 | sqlite3_mem_t<char*> S = sqlite3_mprintf( | 192 | sqlite3_mem_t<char*> S = sqlite3_mprintf( |
301 | "DELETE FROM endpoints_queue" | 193 | "DELETE FROM endpoints_queue" |
302 | " WHERE as_id=%ld", | 194 | " WHERE as_id=%ld", |
303 | as_id); | 195 | as_id); |
304 | db.exec(S); | 196 | db.exec(S); |
305 | } | 197 | } |
306 | 198 | ||
307 | void queue_endpoint(const opkele::openid_endpoint_t& ep) { | 199 | void queue_endpoint(const opkele::openid_endpoint_t& ep) { |
308 | assert(as_id>=0); | 200 | assert(as_id>=0); |
309 | DOUT_("Queueing endpoint " << ep.claimed_id << " : " << ep.local_id << " @ " << ep.uri); | 201 | DOUT_("Queueing endpoint " << ep.claimed_id << " : " << ep.local_id << " @ " << ep.uri); |
310 | sqlite3_mem_t<char*> S = sqlite3_mprintf( | 202 | sqlite3_mem_t<char*> S = sqlite3_mprintf( |
311 | "INSERT INTO endpoints_queue" | 203 | "INSERT INTO endpoints_queue" |
312 | " (as_id,eq_ctime,eq_ordinal,eq_uri,eq_claimed_id,eq_local_id)" | 204 | " (as_id,eq_ctime,eq_ordinal,eq_uri,eq_claimed_id,eq_local_id)" |
313 | " VALUES (%ld,strftime('%%s','now'),%d,%Q,%Q,%Q)", | 205 | " VALUES (%ld,strftime('%%s','now'),%d,%Q,%Q,%Q)", |
314 | as_id,ordinal++, | 206 | as_id,ordinal++, |
315 | ep.uri.c_str(),ep.claimed_id.c_str(),ep.local_id.c_str()); | 207 | ep.uri.c_str(),ep.claimed_id.c_str(),ep.local_id.c_str()); |
316 | db.exec(S); | 208 | db.exec(S); |
317 | } | 209 | } |
318 | 210 | ||
319 | mutable openid_endpoint_t eqtop; | 211 | mutable openid_endpoint_t eqtop; |
320 | mutable bool have_eqtop; | 212 | mutable bool have_eqtop; |
321 | 213 | ||
322 | const openid_endpoint_t& get_endpoint() const { | 214 | const openid_endpoint_t& get_endpoint() const { |
323 | assert(as_id>=0); | 215 | assert(as_id>=0); |
324 | if(!have_eqtop) { | 216 | if(!have_eqtop) { |
325 | sqlite3_mem_t<char*> | 217 | sqlite3_mem_t<char*> |
326 | S = sqlite3_mprintf( | 218 | S = sqlite3_mprintf( |
327 | "SELECT" | 219 | "SELECT" |
328 | " eq_uri, eq_claimed_id, eq_local_id" | 220 | " eq_uri, eq_claimed_id, eq_local_id" |
329 | " FROM endpoints_queue" | 221 | " FROM endpoints_queue" |
330 | " JOIN auth_sessions USING(as_id)" | 222 | " JOIN auth_sessions USING(as_id)" |
331 | " WHERE hts_id=%Q AND as_id=%ld" | 223 | " WHERE hts_id=%Q AND as_id=%ld" |
332 | " ORDER BY eq_ctime,eq_ordinal" | 224 | " ORDER BY eq_ctime,eq_ordinal" |
333 | " LIMIT 1",htc.get_value().c_str(),as_id); | 225 | " LIMIT 1",htc.get_value().c_str(),as_id); |
diff --git a/test/kingate_openid_message.h b/test/kingate_openid_message.h new file mode 100644 index 0000000..b3a2c9d --- a/dev/null +++ b/test/kingate_openid_message.h | |||
@@ -0,0 +1,108 @@ | |||
1 | template<typename IT> | ||
2 | class join_iterator : public iterator< | ||
3 | input_iterator_tag,typename IT::value_type, | ||
4 | void,typename IT::pointer,typename IT::reference> { | ||
5 | public: | ||
6 | typedef pair<IT,IT> range_t; | ||
7 | typedef list<range_t> ranges_t; | ||
8 | ranges_t ranges; | ||
9 | |||
10 | join_iterator() { } | ||
11 | |||
12 | bool cleanup() { | ||
13 | bool rv = false; | ||
14 | while(!(ranges.empty() || ranges.front().first!=ranges.front().second)) { | ||
15 | ranges.pop_front(); rv = true; | ||
16 | } | ||
17 | return rv; | ||
18 | } | ||
19 | |||
20 | join_iterator<IT>& add_range(const IT& b,const IT& e) { | ||
21 | ranges.push_back(typename ranges_t::value_type(b,e)); | ||
22 | cleanup(); | ||
23 | return *this; | ||
24 | } | ||
25 | |||
26 | bool operator==(const join_iterator<IT>& x) const { | ||
27 | return ranges==x.ranges; } | ||
28 | bool operator!=(const join_iterator<IT>& x) const { | ||
29 | return ranges!=x.ranges; } | ||
30 | |||
31 | typename IT::reference operator*() const { | ||
32 | assert(!ranges.empty()); | ||
33 | assert(ranges.front().first!=ranges.front().second); | ||
34 | return *ranges.front().first; } | ||
35 | typename IT::pointer operator->() const { | ||
36 | assert(!ranges.empty()); | ||
37 | assert(ranges.front().first!=ranges.front().second); | ||
38 | return ranges.front().first.operator->(); } | ||
39 | |||
40 | join_iterator<IT>& operator++() { | ||
41 | cleanup(); | ||
42 | if(ranges.empty()) return *this; | ||
43 | do { | ||
44 | ++ranges.front().first; | ||
45 | }while(cleanup() && !ranges.empty()); | ||
46 | return *this; | ||
47 | } | ||
48 | join_iterator<IT> operator++(int) { | ||
49 | join_iterator<IT> rv(*this); | ||
50 | ++(*this); return rv; } | ||
51 | }; | ||
52 | |||
53 | template<typename IT> | ||
54 | class cut_prefix_filterator : public opkele::util::basic_filterator<IT> { | ||
55 | public: | ||
56 | string pfx; | ||
57 | mutable string tmp; | ||
58 | |||
59 | cut_prefix_filterator() { } | ||
60 | cut_prefix_filterator(const IT& bi,const IT&ei,const string& pfx) | ||
61 | : opkele::util::basic_filterator<IT>(bi,ei), pfx(pfx) { | ||
62 | this->prepare(); | ||
63 | } | ||
64 | |||
65 | bool is_interesting() const { | ||
66 | return pfx.length()==0 || !strncmp(this->it->c_str(),pfx.c_str(),pfx.length()); | ||
67 | } | ||
68 | |||
69 | typename IT::reference operator*() const { | ||
70 | assert(!this->empty); | ||
71 | tmp = *this->it; tmp.erase(0,pfx.length()); | ||
72 | return tmp; } | ||
73 | typename IT::pointer operator->() const { | ||
74 | assert(!this->empty); | ||
75 | return &this->operator*(); } | ||
76 | }; | ||
77 | |||
78 | class kingate_openid_message_t : public opkele::basic_openid_message { | ||
79 | typedef join_iterator<kingate::cgi_gateway::params_t::const_iterator> jitterator; | ||
80 | typedef opkele::util::map_keys_iterator< | ||
81 | jitterator, | ||
82 | fields_iterator::value_type, | ||
83 | fields_iterator::reference, | ||
84 | fields_iterator::pointer> keys_iterator; | ||
85 | typedef cut_prefix_filterator<keys_iterator> pfilterator; | ||
86 | public: | ||
87 | const kingate::cgi_gateway& gw; | ||
88 | |||
89 | kingate_openid_message_t(const kingate::cgi_gateway& g) : gw(g) { } | ||
90 | |||
91 | bool has_field(const string& n) const { | ||
92 | return gw.has_param("openid."+n); } | ||
93 | const string& get_field(const string& n) const { | ||
94 | return gw.get_param("openid."+n); } | ||
95 | |||
96 | fields_iterator fields_begin() const { | ||
97 | return | ||
98 | pfilterator( keys_iterator( | ||
99 | jitterator() | ||
100 | .add_range( gw.get.begin(), gw.get.end() ) | ||
101 | .add_range( gw.post.begin(), gw.post.end() ), | ||
102 | jitterator() | ||
103 | ), keys_iterator(), "openid." ); | ||
104 | } | ||
105 | fields_iterator fields_end() const { | ||
106 | return pfilterator(); | ||
107 | } | ||
108 | }; | ||