|
|
|
@@ -1,195 +1,196 @@ |
1 | #include <uuid/uuid.h> |
1 | #include <uuid/uuid.h> |
2 | #include <iostream> |
2 | #include <iostream> |
3 | #include <cassert> |
3 | #include <cassert> |
| |
4 | #include <cstdlib> |
4 | #include <stdexcept> |
5 | #include <stdexcept> |
5 | #include <string> |
6 | #include <string> |
6 | #include <set> |
7 | #include <set> |
7 | #include <iterator> |
8 | #include <iterator> |
8 | using namespace std; |
9 | using namespace std; |
9 | #include <kingate/exception.h> |
10 | #include <kingate/exception.h> |
10 | #include <kingate/plaincgi.h> |
11 | #include <kingate/plaincgi.h> |
11 | #include <kingate/cgi_gateway.h> |
12 | #include <kingate/cgi_gateway.h> |
12 | #include <opkele/exception.h> |
13 | #include <opkele/exception.h> |
13 | #include <opkele/types.h> |
14 | #include <opkele/types.h> |
14 | #include <opkele/util.h> |
15 | #include <opkele/util.h> |
15 | #include <opkele/uris.h> |
16 | #include <opkele/uris.h> |
16 | #include <opkele/discovery.h> |
17 | #include <opkele/discovery.h> |
17 | #include <opkele/association.h> |
18 | #include <opkele/association.h> |
18 | #include <opkele/sreg.h> |
19 | #include <opkele/sreg.h> |
19 | using namespace opkele; |
20 | using namespace opkele; |
20 | #include <opkele/prequeue_rp.h> |
21 | #include <opkele/prequeue_rp.h> |
21 | #include <opkele/debug.h> |
22 | #include <opkele/debug.h> |
22 | |
23 | |
23 | #include "sqlite.h" |
24 | #include "sqlite.h" |
24 | #include "kingate_openid_message.h" |
25 | #include "kingate_openid_message.h" |
25 | |
26 | |
26 | #undef DUMB_RP |
27 | #undef DUMB_RP |
27 | |
28 | |
28 | #ifdef DUMB_RP |
29 | #ifdef DUMB_RP |
29 | # define DUMBTHROW throw opkele::dumb_RP(OPKELE_CP_ "This RP is dumb") |
30 | # define DUMBTHROW throw opkele::dumb_RP(OPKELE_CP_ "This RP is dumb") |
30 | #else |
31 | #else |
31 | # define DUMBTHROW (void)0 |
32 | # define DUMBTHROW (void)0 |
32 | #endif |
33 | #endif |
33 | |
34 | |
34 | class rpdb_t : public sqlite3_t { |
35 | class rpdb_t : public sqlite3_t { |
35 | public: |
36 | public: |
36 | rpdb_t() |
37 | rpdb_t() |
37 | : sqlite3_t("/tmp/RP.db") { |
38 | : sqlite3_t("/tmp/RP.db") { |
38 | assert(_D); |
39 | assert(_D); |
39 | char **resp; int nrow,ncol; char *errm; |
40 | char **resp; int nrow,ncol; char *errm; |
40 | if(sqlite3_get_table( |
41 | if(sqlite3_get_table( |
41 | _D,"SELECT a_op FROM assoc LIMIT 0", |
42 | _D,"SELECT a_op FROM assoc LIMIT 0", |
42 | &resp,&nrow,&ncol,&errm)!=SQLITE_OK) { |
43 | &resp,&nrow,&ncol,&errm)!=SQLITE_OK) { |
43 | extern const char *__RP_db_bootstrap; |
44 | extern const char *__RP_db_bootstrap; |
44 | DOUT_("Bootstrapping DB"); |
45 | DOUT_("Bootstrapping DB"); |
45 | if(sqlite3_exec(_D,__RP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK) |
46 | if(sqlite3_exec(_D,__RP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK) |
46 | throw opkele::exception(OPKELE_CP_ string("Failed to bootstrap SQLite database: ")+errm); |
47 | throw opkele::exception(OPKELE_CP_ string("Failed to bootstrap SQLite database: ")+errm); |
47 | }else |
48 | }else |
48 | sqlite3_free_table(resp); |
49 | sqlite3_free_table(resp); |
49 | |
50 | |
50 | } |
51 | } |
51 | }; |
52 | }; |
52 | |
53 | |
53 | class example_rp_t : public opkele::prequeue_RP { |
54 | class example_rp_t : public opkele::prequeue_RP { |
54 | public: |
55 | public: |
55 | mutable rpdb_t db; |
56 | mutable rpdb_t db; |
56 | kingate::cookie htc; |
57 | kingate::cookie htc; |
57 | long as_id; |
58 | long as_id; |
58 | int ordinal; |
59 | int ordinal; |
59 | kingate::cgi_gateway& gw; |
60 | kingate::cgi_gateway& gw; |
60 | |
61 | |
61 | example_rp_t(kingate::cgi_gateway& g) |
62 | example_rp_t(kingate::cgi_gateway& g) |
62 | : as_id(-1), ordinal(0), gw(g), have_eqtop(false) { |
63 | : as_id(-1), ordinal(0), gw(g), have_eqtop(false) { |
63 | try { |
64 | try { |
64 | htc = gw.cookies.get_cookie("ht_session"); |
65 | htc = gw.cookies.get_cookie("ht_session"); |
65 | as_id = opkele::util::string_to_long(gw.get_param("asid")); |
66 | as_id = opkele::util::string_to_long(gw.get_param("asid")); |
66 | }catch(kingate::exception_notfound& kenf) { |
67 | }catch(kingate::exception_notfound& kenf) { |
67 | uuid_t uuid; uuid_generate(uuid); |
68 | uuid_t uuid; uuid_generate(uuid); |
68 | htc = kingate::cookie("ht_session",util::encode_base64(uuid,sizeof(uuid))); |
69 | htc = kingate::cookie("ht_session",util::encode_base64(uuid,sizeof(uuid))); |
69 | sqlite3_mem_t<char*> S = sqlite3_mprintf( |
70 | sqlite3_mem_t<char*> S = sqlite3_mprintf( |
70 | "INSERT INTO ht_sessions (hts_id) VALUES (%Q)", |
71 | "INSERT INTO ht_sessions (hts_id) VALUES (%Q)", |
71 | htc.get_value().c_str()); |
72 | htc.get_value().c_str()); |
72 | db.exec(S); |
73 | db.exec(S); |
73 | } |
74 | } |
74 | } |
75 | } |
75 | |
76 | |
76 | /* Global persistent store */ |
77 | /* Global persistent store */ |
77 | |
78 | |
78 | opkele::assoc_t store_assoc( |
79 | opkele::assoc_t store_assoc( |
79 | const string& OP,const string& handle, |
80 | const string& OP,const string& handle, |
80 | const string& type,const secret_t& secret, |
81 | const string& type,const secret_t& secret, |
81 | int expires_in) { |
82 | int expires_in) { |
82 | DUMBTHROW; |
83 | DUMBTHROW; |
83 | DOUT_("Storing '" << handle << "' assoc with '" << OP << "'"); |
84 | DOUT_("Storing '" << handle << "' assoc with '" << OP << "'"); |
84 | time_t exp = time(0)+expires_in; |
85 | time_t exp = time(0)+expires_in; |
85 | sqlite3_mem_t<char*> |
86 | sqlite3_mem_t<char*> |
86 | S = sqlite3_mprintf( |
87 | S = sqlite3_mprintf( |
87 | "INSERT INTO assoc" |
88 | "INSERT INTO assoc" |
88 | " (a_op,a_handle,a_type,a_ctime,a_etime,a_secret)" |
89 | " (a_op,a_handle,a_type,a_ctime,a_etime,a_secret)" |
89 | " VALUES (" |
90 | " VALUES (" |
90 | " %Q,%Q,%Q," |
91 | " %Q,%Q,%Q," |
91 | " datetime('now'), datetime('now','+%d seconds')," |
92 | " datetime('now'), datetime('now','+%d seconds')," |
92 | " %Q" |
93 | " %Q" |
93 | " );", OP.c_str(), handle.c_str(), type.c_str(), |
94 | " );", OP.c_str(), handle.c_str(), type.c_str(), |
94 | expires_in, |
95 | expires_in, |
95 | util::encode_base64(&(secret.front()),secret.size()).c_str() ); |
96 | util::encode_base64(&(secret.front()),secret.size()).c_str() ); |
96 | db.exec(S); |
97 | db.exec(S); |
97 | return opkele::assoc_t(new opkele::association( |
98 | return opkele::assoc_t(new opkele::association( |
98 | OP, handle, type, secret, exp, false )); |
99 | OP, handle, type, secret, exp, false )); |
99 | } |
100 | } |
100 | |
101 | |
101 | opkele::assoc_t find_assoc( |
102 | opkele::assoc_t find_assoc( |
102 | const string& OP) { |
103 | const string& OP) { |
103 | DUMBTHROW; |
104 | DUMBTHROW; |
104 | DOUT_("Looking for an assoc with '" << OP << '\''); |
105 | DOUT_("Looking for an assoc with '" << OP << '\''); |
105 | sqlite3_mem_t<char*> |
106 | sqlite3_mem_t<char*> |
106 | S = sqlite3_mprintf( |
107 | S = sqlite3_mprintf( |
107 | "SELECT" |
108 | "SELECT" |
108 | " a_op,a_handle,a_type,a_secret," |
109 | " a_op,a_handle,a_type,a_secret," |
109 | " strftime('%%s',a_etime) AS a_etime" |
110 | " strftime('%%s',a_etime) AS a_etime" |
110 | " FROM assoc" |
111 | " FROM assoc" |
111 | " WHERE a_op=%Q AND a_itime IS NULL AND NOT a_stateless" |
112 | " WHERE a_op=%Q AND a_itime IS NULL AND NOT a_stateless" |
112 | " AND ( a_etime > datetime('now','-30 seconds') )" |
113 | " AND ( a_etime > datetime('now','-30 seconds') )" |
113 | " LIMIT 1", |
114 | " LIMIT 1", |
114 | OP.c_str()); |
115 | OP.c_str()); |
115 | sqlite3_table_t T; |
116 | sqlite3_table_t T; |
116 | int nr,nc; |
117 | int nr,nc; |
117 | db.get_table(S,T,&nr,&nc); |
118 | db.get_table(S,T,&nr,&nc); |
118 | if(nr<1) |
119 | if(nr<1) |
119 | throw opkele::failed_lookup(OPKELE_CP_ "Couldn't find unexpired handle"); |
120 | throw opkele::failed_lookup(OPKELE_CP_ "Couldn't find unexpired handle"); |
120 | assert(nr==1); |
121 | assert(nr==1); |
121 | assert(nc==5); |
122 | assert(nc==5); |
122 | secret_t secret; |
123 | secret_t secret; |
123 | util::decode_base64(T.get(1,3,nc),secret); |
124 | util::decode_base64(T.get(1,3,nc),secret); |
124 | DOUT_(" found '" << T.get(1,1,nc) << '\''); |
125 | DOUT_(" found '" << T.get(1,1,nc) << '\''); |
125 | return opkele::assoc_t(new opkele::association( |
126 | return opkele::assoc_t(new opkele::association( |
126 | T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), |
127 | T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), |
127 | secret, strtol(T.get(1,4,nc),0,0), false )); |
128 | secret, strtol(T.get(1,4,nc),0,0), false )); |
128 | } |
129 | } |
129 | |
130 | |
130 | opkele::assoc_t retrieve_assoc( |
131 | opkele::assoc_t retrieve_assoc( |
131 | const string& OP,const string& handle) { |
132 | const string& OP,const string& handle) { |
132 | DUMBTHROW; |
133 | DUMBTHROW; |
133 | DOUT_("Retrieving assoc '" << handle << "' with '" << OP << '\''); |
134 | DOUT_("Retrieving assoc '" << handle << "' with '" << OP << '\''); |
134 | sqlite3_mem_t<char*> |
135 | sqlite3_mem_t<char*> |
135 | S = sqlite3_mprintf( |
136 | S = sqlite3_mprintf( |
136 | "SELECT" |
137 | "SELECT" |
137 | " a_op,a_handle,a_type,a_secret," |
138 | " a_op,a_handle,a_type,a_secret," |
138 | " strftime('%%s',a_etime) AS a_etime" |
139 | " strftime('%%s',a_etime) AS a_etime" |
139 | " FROM assoc" |
140 | " FROM assoc" |
140 | " WHERE a_op=%Q AND a_handle=%Q" |
141 | " WHERE a_op=%Q AND a_handle=%Q" |
141 | " AND a_itime IS NULL AND NOT a_stateless" |
142 | " AND a_itime IS NULL AND NOT a_stateless" |
142 | " LIMIT 1", |
143 | " LIMIT 1", |
143 | OP.c_str(),handle.c_str()); |
144 | OP.c_str(),handle.c_str()); |
144 | sqlite3_table_t T; |
145 | sqlite3_table_t T; |
145 | int nr,nc; |
146 | int nr,nc; |
146 | db.get_table(S,T,&nr,&nc); |
147 | db.get_table(S,T,&nr,&nc); |
147 | if(nr<1) |
148 | if(nr<1) |
148 | throw opkele::failed_lookup(OPKELE_CP_ "couldn't retrieve valid association"); |
149 | throw opkele::failed_lookup(OPKELE_CP_ "couldn't retrieve valid association"); |
149 | assert(nr==1); assert(nc==5); |
150 | assert(nr==1); assert(nc==5); |
150 | secret_t secret; util::decode_base64(T.get(1,3,nc),secret); |
151 | secret_t secret; util::decode_base64(T.get(1,3,nc),secret); |
151 | DOUT_(" found. type=" << T.get(1,2,nc) << '\''); |
152 | DOUT_(" found. type=" << T.get(1,2,nc) << '\''); |
152 | return opkele::assoc_t(new opkele::association( |
153 | return opkele::assoc_t(new opkele::association( |
153 | T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), |
154 | T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), |
154 | secret, strtol(T.get(1,4,nc),0,0), false )); |
155 | secret, strtol(T.get(1,4,nc),0,0), false )); |
155 | } |
156 | } |
156 | |
157 | |
157 | void invalidate_assoc( |
158 | void invalidate_assoc( |
158 | const string& OP,const string& handle) { |
159 | const string& OP,const string& handle) { |
159 | DUMBTHROW; |
160 | DUMBTHROW; |
160 | DOUT_("Invalidating assoc '" << handle << "' with '" << OP << '\''); |
161 | DOUT_("Invalidating assoc '" << handle << "' with '" << OP << '\''); |
161 | sqlite3_mem_t<char*> |
162 | sqlite3_mem_t<char*> |
162 | S = sqlite3_mprintf( |
163 | S = sqlite3_mprintf( |
163 | "UPDATE assoc SET a_itime=datetime('now')" |
164 | "UPDATE assoc SET a_itime=datetime('now')" |
164 | " WHERE a_op=%Q AND a_handle=%Q", |
165 | " WHERE a_op=%Q AND a_handle=%Q", |
165 | OP.c_str(), handle.c_str() ); |
166 | OP.c_str(), handle.c_str() ); |
166 | db.exec(S); |
167 | db.exec(S); |
167 | } |
168 | } |
168 | |
169 | |
169 | void check_nonce(const string& OP,const string& nonce) { |
170 | void check_nonce(const string& OP,const string& nonce) { |
170 | DOUT_("Checking nonce '" << nonce << "' from '" << OP << '\''); |
171 | DOUT_("Checking nonce '" << nonce << "' from '" << OP << '\''); |
171 | sqlite3_mem_t<char*> |
172 | sqlite3_mem_t<char*> |
172 | S = sqlite3_mprintf( |
173 | S = sqlite3_mprintf( |
173 | "SELECT 1 FROM nonces WHERE n_op=%Q AND n_once=%Q", |
174 | "SELECT 1 FROM nonces WHERE n_op=%Q AND n_once=%Q", |
174 | OP.c_str(), nonce.c_str()); |
175 | OP.c_str(), nonce.c_str()); |
175 | sqlite3_table_t T; |
176 | sqlite3_table_t T; |
176 | int nr,nc; |
177 | int nr,nc; |
177 | db.get_table(S,T,&nr,&nc); |
178 | db.get_table(S,T,&nr,&nc); |
178 | if(nr) |
179 | if(nr) |
179 | throw opkele::id_res_bad_nonce(OPKELE_CP_ "already seen that nonce"); |
180 | throw opkele::id_res_bad_nonce(OPKELE_CP_ "already seen that nonce"); |
180 | sqlite3_mem_t<char*> |
181 | sqlite3_mem_t<char*> |
181 | SS = sqlite3_mprintf( |
182 | SS = sqlite3_mprintf( |
182 | "INSERT INTO nonces (n_op,n_once) VALUES (%Q,%Q)", |
183 | "INSERT INTO nonces (n_op,n_once) VALUES (%Q,%Q)", |
183 | OP.c_str(), nonce.c_str()); |
184 | OP.c_str(), nonce.c_str()); |
184 | db.exec(SS); |
185 | db.exec(SS); |
185 | } |
186 | } |
186 | |
187 | |
187 | /* Session perisistent store */ |
188 | /* Session perisistent store */ |
188 | |
189 | |
189 | void begin_queueing() { |
190 | void begin_queueing() { |
190 | assert(as_id>=0); |
191 | assert(as_id>=0); |
191 | DOUT_("Resetting queue for session '" << htc.get_value() << "'/" << as_id); |
192 | DOUT_("Resetting queue for session '" << htc.get_value() << "'/" << as_id); |
192 | sqlite3_mem_t<char*> S = sqlite3_mprintf( |
193 | sqlite3_mem_t<char*> S = sqlite3_mprintf( |
193 | "DELETE FROM endpoints_queue" |
194 | "DELETE FROM endpoints_queue" |
194 | " WHERE as_id=%ld", |
195 | " WHERE as_id=%ld", |
195 | as_id); |
196 | as_id); |
|