|
|
|
@@ -1,237 +1,129 @@ |
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 | |
|