author | Michael Krelin <hacker@klever.net> | 2008-01-23 21:13:27 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2008-01-23 21:13:27 (UTC) |
commit | dc5dad0709ae8dd0a4be74248a22a78e47ba90e2 (patch) (unidiff) | |
tree | eebd2a18bec33c4250036e1fd92d38cd4268777e | |
parent | 2a116bce75236e46946bb9564790c26c6a59b9a4 (diff) | |
download | libopkele-dc5dad0709ae8dd0a4be74248a22a78e47ba90e2.zip libopkele-dc5dad0709ae8dd0a4be74248a22a78e47ba90e2.tar.gz libopkele-dc5dad0709ae8dd0a4be74248a22a78e47ba90e2.tar.bz2 |
check associate reply for consistency
Reject associate replies returning secret of inconsistent with association type
length. This way severely broken OPs which return SHA1 association as SHA256
will still work in dumb mode.
Signed-off-by: Michael Krelin <hacker@klever.net>
-rw-r--r-- | lib/basic_rp.cc | 9 |
1 files changed, 6 insertions, 3 deletions
diff --git a/lib/basic_rp.cc b/lib/basic_rp.cc index 763a391..2da8416 100644 --- a/lib/basic_rp.cc +++ b/lib/basic_rp.cc | |||
@@ -1,311 +1,314 @@ | |||
1 | #include <openssl/sha.h> | 1 | #include <openssl/sha.h> |
2 | #include <openssl/hmac.h> | 2 | #include <openssl/hmac.h> |
3 | #include <opkele/basic_rp.h> | 3 | #include <opkele/basic_rp.h> |
4 | #include <opkele/exception.h> | 4 | #include <opkele/exception.h> |
5 | #include <opkele/uris.h> | 5 | #include <opkele/uris.h> |
6 | #include <opkele/data.h> | 6 | #include <opkele/data.h> |
7 | #include <opkele/util.h> | 7 | #include <opkele/util.h> |
8 | #include <opkele/curl.h> | 8 | #include <opkele/curl.h> |
9 | 9 | ||
10 | namespace opkele { | 10 | namespace opkele { |
11 | 11 | ||
12 | static void dh_get_secret( | 12 | static void dh_get_secret( |
13 | secret_t& secret, const basic_openid_message& om, | 13 | secret_t& secret, const basic_openid_message& om, |
14 | const char *exp_assoc, const char *exp_sess, | 14 | const char *exp_assoc, const char *exp_sess, |
15 | util::dh_t& dh, | 15 | util::dh_t& dh, |
16 | size_t d_len, unsigned char *(*d_fun)(const unsigned char*,size_t,unsigned char*) ) try { | 16 | size_t d_len, unsigned char *(*d_fun)(const unsigned char*,size_t,unsigned char*), |
17 | size_t exp_s_len) try { | ||
17 | if(om.get_field("assoc_type")!=exp_assoc || om.get_field("session_type")!=exp_sess) | 18 | if(om.get_field("assoc_type")!=exp_assoc || om.get_field("session_type")!=exp_sess) |
18 | throw bad_input(OPKELE_CP_ "Unexpected associate response"); | 19 | throw bad_input(OPKELE_CP_ "Unexpected associate response"); |
19 | util::bignum_t s_pub = util::base64_to_bignum(om.get_field("dh_server_public")); | 20 | util::bignum_t s_pub = util::base64_to_bignum(om.get_field("dh_server_public")); |
20 | vector<unsigned char> ck(DH_size(dh)+1); | 21 | vector<unsigned char> ck(DH_size(dh)+1); |
21 | unsigned char *ckptr = &(ck.front())+1; | 22 | unsigned char *ckptr = &(ck.front())+1; |
22 | int cklen = DH_compute_key(ckptr,s_pub,dh); | 23 | int cklen = DH_compute_key(ckptr,s_pub,dh); |
23 | if(cklen<0) | 24 | if(cklen<0) |
24 | throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); | 25 | throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); |
25 | if(cklen && (*ckptr)&0x80) { | 26 | if(cklen && (*ckptr)&0x80) { |
26 | (*(--ckptr))=0; ++cklen; } | 27 | (*(--ckptr))=0; ++cklen; } |
27 | unsigned char key_digest[d_len]; | 28 | unsigned char key_digest[d_len]; |
28 | secret.enxor_from_base64((*d_fun)(ckptr,cklen,key_digest),om.get_field("enc_mac_key")); | 29 | secret.enxor_from_base64((*d_fun)(ckptr,cklen,key_digest),om.get_field("enc_mac_key")); |
30 | if(secret.size()!=exp_s_len) | ||
31 | throw bad_input(OPKELE_CP_ "Secret length isn't consistent with association type"); | ||
29 | }catch(opkele::failed_lookup& ofl) { | 32 | }catch(opkele::failed_lookup& ofl) { |
30 | throw bad_input(OPKELE_CP_ "Incoherent response from OP"); | 33 | throw bad_input(OPKELE_CP_ "Incoherent response from OP"); |
31 | } OPKELE_RETHROW | 34 | } OPKELE_RETHROW |
32 | 35 | ||
33 | static void direct_request(basic_openid_message& oum,const basic_openid_message& inm,const string& OP) { | 36 | static void direct_request(basic_openid_message& oum,const basic_openid_message& inm,const string& OP) { |
34 | util::curl_pick_t curl = util::curl_pick_t::easy_init(); | 37 | util::curl_pick_t curl = util::curl_pick_t::easy_init(); |
35 | if(!curl) | 38 | if(!curl) |
36 | throw exception_curl(OPKELE_CP_ "failed to initialize curl"); | 39 | throw exception_curl(OPKELE_CP_ "failed to initialize curl"); |
37 | string request = inm.query_string(); | 40 | string request = inm.query_string(); |
38 | CURLcode r; | 41 | CURLcode r; |
39 | (r=curl.misc_sets()) | 42 | (r=curl.misc_sets()) |
40 | || (r=curl.easy_setopt(CURLOPT_URL,OP.c_str())) | 43 | || (r=curl.easy_setopt(CURLOPT_URL,OP.c_str())) |
41 | || (r=curl.easy_setopt(CURLOPT_POST,1)) | 44 | || (r=curl.easy_setopt(CURLOPT_POST,1)) |
42 | || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data())) | 45 | || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data())) |
43 | || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length())) | 46 | || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length())) |
44 | || (r=curl.set_write()); | 47 | || (r=curl.set_write()); |
45 | if(r) | 48 | if(r) |
46 | throw exception_curl(OPKELE_CP_ "failed to set curly options",r); | 49 | throw exception_curl(OPKELE_CP_ "failed to set curly options",r); |
47 | if( (r=curl.easy_perform()) ) | 50 | if( (r=curl.easy_perform()) ) |
48 | throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); | 51 | throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); |
49 | oum.from_keyvalues(curl.response); | 52 | oum.from_keyvalues(curl.response); |
50 | } | 53 | } |
51 | 54 | ||
52 | 55 | ||
53 | assoc_t basic_RP::associate(const string& OP) { | 56 | assoc_t basic_RP::associate(const string& OP) { |
54 | util::dh_t dh = DH_new(); | 57 | util::dh_t dh = DH_new(); |
55 | if(!dh) | 58 | if(!dh) |
56 | throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); | 59 | throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); |
57 | dh->p = util::dec_to_bignum(data::_default_p); | 60 | dh->p = util::dec_to_bignum(data::_default_p); |
58 | dh->g = util::dec_to_bignum(data::_default_g); | 61 | dh->g = util::dec_to_bignum(data::_default_g); |
59 | if(!DH_generate_key(dh)) | 62 | if(!DH_generate_key(dh)) |
60 | throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); | 63 | throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); |
61 | openid_message_t req; | 64 | openid_message_t req; |
62 | req.set_field("ns",OIURI_OPENID20); | 65 | req.set_field("ns",OIURI_OPENID20); |
63 | req.set_field("mode","associate"); | 66 | req.set_field("mode","associate"); |
64 | req.set_field("dh_modulus",util::bignum_to_base64(dh->p)); | 67 | req.set_field("dh_modulus",util::bignum_to_base64(dh->p)); |
65 | req.set_field("dh_gen",util::bignum_to_base64(dh->g)); | 68 | req.set_field("dh_gen",util::bignum_to_base64(dh->g)); |
66 | req.set_field("dh_consumer_public",util::bignum_to_base64(dh->pub_key)); | 69 | req.set_field("dh_consumer_public",util::bignum_to_base64(dh->pub_key)); |
67 | openid_message_t res; | 70 | openid_message_t res; |
68 | req.set_field("assoc_type","HMAC-SHA256"); | 71 | req.set_field("assoc_type","HMAC-SHA256"); |
69 | req.set_field("session_type","DH-SHA256"); | 72 | req.set_field("session_type","DH-SHA256"); |
70 | secret_t secret; | 73 | secret_t secret; |
71 | int expires_in; | 74 | int expires_in; |
72 | try { | 75 | try { |
73 | direct_request(res,req,OP); | 76 | direct_request(res,req,OP); |
74 | dh_get_secret( secret, res, | 77 | dh_get_secret( secret, res, |
75 | "HMAC-SHA256", "DH-SHA256", | 78 | "HMAC-SHA256", "DH-SHA256", |
76 | dh, SHA256_DIGEST_LENGTH, SHA256 ); | 79 | dh, SHA256_DIGEST_LENGTH, SHA256, SHA256_DIGEST_LENGTH ); |
77 | expires_in = util::string_to_long(res.get_field("expires_in")); | 80 | expires_in = util::string_to_long(res.get_field("expires_in")); |
78 | }catch(exception& e) { | 81 | }catch(exception& e) { |
79 | try { | 82 | try { |
80 | req.set_field("assoc_type","HMAC-SHA1"); | 83 | req.set_field("assoc_type","HMAC-SHA1"); |
81 | req.set_field("session_type","DH-SHA1"); | 84 | req.set_field("session_type","DH-SHA1"); |
82 | direct_request(res,req,OP); | 85 | direct_request(res,req,OP); |
83 | dh_get_secret( secret, res, | 86 | dh_get_secret( secret, res, |
84 | "HMAC-SHA1", "DH-SHA1", | 87 | "HMAC-SHA1", "DH-SHA1", |
85 | dh, SHA_DIGEST_LENGTH, SHA1 ); | 88 | dh, SHA_DIGEST_LENGTH, SHA1, SHA_DIGEST_LENGTH ); |
86 | expires_in = util::string_to_long(res.get_field("expires_in")); | 89 | expires_in = util::string_to_long(res.get_field("expires_in")); |
87 | }catch(bad_input& e) { | 90 | }catch(bad_input& e) { |
88 | throw dumb_RP(OPKELE_CP_ "OP failed to supply an association"); | 91 | throw dumb_RP(OPKELE_CP_ "OP failed to supply an association"); |
89 | } | 92 | } |
90 | } | 93 | } |
91 | return store_assoc( | 94 | return store_assoc( |
92 | OP, res.get_field("assoc_handle"), | 95 | OP, res.get_field("assoc_handle"), |
93 | res.get_field("assoc_type"), secret, | 96 | res.get_field("assoc_type"), secret, |
94 | expires_in ); | 97 | expires_in ); |
95 | } | 98 | } |
96 | 99 | ||
97 | basic_openid_message& basic_RP::checkid_( | 100 | basic_openid_message& basic_RP::checkid_( |
98 | basic_openid_message& rv, | 101 | basic_openid_message& rv, |
99 | mode_t mode, | 102 | mode_t mode, |
100 | const string& return_to,const string& realm, | 103 | const string& return_to,const string& realm, |
101 | extension_t *ext) { | 104 | extension_t *ext) { |
102 | rv.reset_fields(); | 105 | rv.reset_fields(); |
103 | rv.set_field("ns",OIURI_OPENID20); | 106 | rv.set_field("ns",OIURI_OPENID20); |
104 | if(mode==mode_checkid_immediate) | 107 | if(mode==mode_checkid_immediate) |
105 | rv.set_field("mode","checkid_immediate"); | 108 | rv.set_field("mode","checkid_immediate"); |
106 | else if(mode==mode_checkid_setup) | 109 | else if(mode==mode_checkid_setup) |
107 | rv.set_field("mode","checkid_setup"); | 110 | rv.set_field("mode","checkid_setup"); |
108 | else | 111 | else |
109 | throw bad_input(OPKELE_CP_ "unknown checkid_* mode"); | 112 | throw bad_input(OPKELE_CP_ "unknown checkid_* mode"); |
110 | if(realm.empty() && return_to.empty()) | 113 | if(realm.empty() && return_to.empty()) |
111 | throw bad_input(OPKELE_CP_ "At least one of realm and return_to must be non-empty"); | 114 | throw bad_input(OPKELE_CP_ "At least one of realm and return_to must be non-empty"); |
112 | if(!realm.empty()) { | 115 | if(!realm.empty()) { |
113 | rv.set_field("realm",realm); | 116 | rv.set_field("realm",realm); |
114 | rv.set_field("trust_root",realm); | 117 | rv.set_field("trust_root",realm); |
115 | } | 118 | } |
116 | if(!return_to.empty()) | 119 | if(!return_to.empty()) |
117 | rv.set_field("return_to",return_to); | 120 | rv.set_field("return_to",return_to); |
118 | const openid_endpoint_t& ep = get_endpoint(); | 121 | const openid_endpoint_t& ep = get_endpoint(); |
119 | rv.set_field("claimed_id",ep.claimed_id); | 122 | rv.set_field("claimed_id",ep.claimed_id); |
120 | rv.set_field("identity",ep.local_id); | 123 | rv.set_field("identity",ep.local_id); |
121 | try { | 124 | try { |
122 | rv.set_field("assoc_handle",find_assoc(ep.uri)->handle()); | 125 | rv.set_field("assoc_handle",find_assoc(ep.uri)->handle()); |
123 | }catch(dumb_RP& drp) { | 126 | }catch(dumb_RP& drp) { |
124 | }catch(failed_lookup& fl) { | 127 | }catch(failed_lookup& fl) { |
125 | try { | 128 | try { |
126 | rv.set_field("assoc_handle",associate(ep.uri)->handle()); | 129 | rv.set_field("assoc_handle",associate(ep.uri)->handle()); |
127 | }catch(dumb_RP& drp) { } | 130 | }catch(dumb_RP& drp) { } |
128 | } OPKELE_RETHROW | 131 | } OPKELE_RETHROW |
129 | if(ext) ext->checkid_hook(rv); | 132 | if(ext) ext->checkid_hook(rv); |
130 | return rv; | 133 | return rv; |
131 | } | 134 | } |
132 | 135 | ||
133 | class signed_part_message_proxy : public basic_openid_message { | 136 | class signed_part_message_proxy : public basic_openid_message { |
134 | public: | 137 | public: |
135 | const basic_openid_message& x; | 138 | const basic_openid_message& x; |
136 | set<string> signeds; | 139 | set<string> signeds; |
137 | 140 | ||
138 | signed_part_message_proxy(const basic_openid_message& xx) : x(xx) { | 141 | signed_part_message_proxy(const basic_openid_message& xx) : x(xx) { |
139 | const string& slist = x.get_field("signed"); | 142 | const string& slist = x.get_field("signed"); |
140 | string::size_type p = 0; | 143 | string::size_type p = 0; |
141 | while(true) { | 144 | while(true) { |
142 | string::size_type co = slist.find(',',p); | 145 | string::size_type co = slist.find(',',p); |
143 | string f = (co==string::npos) | 146 | string f = (co==string::npos) |
144 | ?slist.substr(p):slist.substr(p,co-p); | 147 | ?slist.substr(p):slist.substr(p,co-p); |
145 | signeds.insert(f); | 148 | signeds.insert(f); |
146 | if(co==string::npos) break; | 149 | if(co==string::npos) break; |
147 | p = co+1; | 150 | p = co+1; |
148 | } | 151 | } |
149 | } | 152 | } |
150 | 153 | ||
151 | bool has_field(const string& n) const { | 154 | bool has_field(const string& n) const { |
152 | return signeds.find(n)!=signeds.end() && x.has_field(n); } | 155 | return signeds.find(n)!=signeds.end() && x.has_field(n); } |
153 | const string& get_field(const string& n) const { | 156 | const string& get_field(const string& n) const { |
154 | if(signeds.find(n)==signeds.end()) | 157 | if(signeds.find(n)==signeds.end()) |
155 | throw failed_lookup(OPKELE_CP_ "The field isn't known to be signed"); | 158 | throw failed_lookup(OPKELE_CP_ "The field isn't known to be signed"); |
156 | return x.get_field(n); } | 159 | return x.get_field(n); } |
157 | 160 | ||
158 | fields_iterator fields_begin() const { | 161 | fields_iterator fields_begin() const { |
159 | return signeds.begin(); } | 162 | return signeds.begin(); } |
160 | fields_iterator fields_end() const { | 163 | fields_iterator fields_end() const { |
161 | return signeds.end(); } | 164 | return signeds.end(); } |
162 | }; | 165 | }; |
163 | 166 | ||
164 | static void parse_query(const string& u,string::size_type q, | 167 | static void parse_query(const string& u,string::size_type q, |
165 | map<string,string>& p) { | 168 | map<string,string>& p) { |
166 | if(q==string::npos) | 169 | if(q==string::npos) |
167 | return; | 170 | return; |
168 | assert(u[q]=='?'); | 171 | assert(u[q]=='?'); |
169 | ++q; | 172 | ++q; |
170 | string::size_type l = u.size(); | 173 | string::size_type l = u.size(); |
171 | while(q<l) { | 174 | while(q<l) { |
172 | string::size_type eq = u.find('=',q); | 175 | string::size_type eq = u.find('=',q); |
173 | string::size_type am = u.find('&',q); | 176 | string::size_type am = u.find('&',q); |
174 | if(am==string::npos) { | 177 | if(am==string::npos) { |
175 | if(eq==string::npos) { | 178 | if(eq==string::npos) { |
176 | p[""] = u.substr(q); | 179 | p[""] = u.substr(q); |
177 | }else{ | 180 | }else{ |
178 | p[u.substr(q,eq-q)] = u.substr(eq+1); | 181 | p[u.substr(q,eq-q)] = u.substr(eq+1); |
179 | } | 182 | } |
180 | break; | 183 | break; |
181 | }else{ | 184 | }else{ |
182 | if(eq==string::npos || eq>am) { | 185 | if(eq==string::npos || eq>am) { |
183 | p[""] = u.substr(q,eq-q); | 186 | p[""] = u.substr(q,eq-q); |
184 | }else{ | 187 | }else{ |
185 | p[u.substr(q,eq-q)] = u.substr(eq+1,am-eq-1); | 188 | p[u.substr(q,eq-q)] = u.substr(eq+1,am-eq-1); |
186 | } | 189 | } |
187 | q = ++am; | 190 | q = ++am; |
188 | } | 191 | } |
189 | } | 192 | } |
190 | } | 193 | } |
191 | 194 | ||
192 | void basic_RP::id_res(const basic_openid_message& om,extension_t *ext) { | 195 | void basic_RP::id_res(const basic_openid_message& om,extension_t *ext) { |
193 | bool o2 = om.has_field("ns") | 196 | bool o2 = om.has_field("ns") |
194 | && om.get_field("ns")==OIURI_OPENID20; | 197 | && om.get_field("ns")==OIURI_OPENID20; |
195 | if( (!o2) && om.has_field("user_setup_url")) | 198 | if( (!o2) && om.has_field("user_setup_url")) |
196 | throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided", | 199 | throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided", |
197 | om.get_field("user_setup_url")); | 200 | om.get_field("user_setup_url")); |
198 | string m = om.get_field("mode"); | 201 | string m = om.get_field("mode"); |
199 | if(o2 && m=="setup_needed") | 202 | if(o2 && m=="setup_needed") |
200 | throw id_res_setup(OPKELE_CP_ "setup needed, no setup url provided"); | 203 | throw id_res_setup(OPKELE_CP_ "setup needed, no setup url provided"); |
201 | if(m=="cancel") | 204 | if(m=="cancel") |
202 | throw id_res_cancel(OPKELE_CP_ "authentication cancelled"); | 205 | throw id_res_cancel(OPKELE_CP_ "authentication cancelled"); |
203 | bool go_dumb=false; | 206 | bool go_dumb=false; |
204 | try { | 207 | try { |
205 | string OP = o2 | 208 | string OP = o2 |
206 | ?om.get_field("op_endpoint") | 209 | ?om.get_field("op_endpoint") |
207 | :get_endpoint().uri; | 210 | :get_endpoint().uri; |
208 | assoc_t assoc = retrieve_assoc( | 211 | assoc_t assoc = retrieve_assoc( |
209 | OP,om.get_field("assoc_handle")); | 212 | OP,om.get_field("assoc_handle")); |
210 | if(om.get_field("sig")!=util::base64_signature(assoc,om)) | 213 | if(om.get_field("sig")!=util::base64_signature(assoc,om)) |
211 | throw id_res_mismatch(OPKELE_CP_ "signature mismatch"); | 214 | throw id_res_mismatch(OPKELE_CP_ "signature mismatch"); |
212 | }catch(dumb_RP& drp) { | 215 | }catch(dumb_RP& drp) { |
213 | go_dumb=true; | 216 | go_dumb=true; |
214 | }catch(failed_lookup& e) { | 217 | }catch(failed_lookup& e) { |
215 | go_dumb=true; | 218 | go_dumb=true; |
216 | } OPKELE_RETHROW | 219 | } OPKELE_RETHROW |
217 | if(go_dumb) { | 220 | if(go_dumb) { |
218 | try { | 221 | try { |
219 | string OP = o2 | 222 | string OP = o2 |
220 | ?om.get_field("op_endpoint") | 223 | ?om.get_field("op_endpoint") |
221 | :get_endpoint().uri; | 224 | :get_endpoint().uri; |
222 | check_authentication(OP,om); | 225 | check_authentication(OP,om); |
223 | }catch(failed_check_authentication& fca) { | 226 | }catch(failed_check_authentication& fca) { |
224 | throw id_res_failed(OPKELE_CP_ "failed to check_authentication()"); | 227 | throw id_res_failed(OPKELE_CP_ "failed to check_authentication()"); |
225 | } OPKELE_RETHROW | 228 | } OPKELE_RETHROW |
226 | } | 229 | } |
227 | signed_part_message_proxy signeds(om); | 230 | signed_part_message_proxy signeds(om); |
228 | if(o2) { | 231 | if(o2) { |
229 | check_nonce(om.get_field("op_endpoint"), | 232 | check_nonce(om.get_field("op_endpoint"), |
230 | om.get_field("response_nonce")); | 233 | om.get_field("response_nonce")); |
231 | static const char *mustsign[] = { | 234 | static const char *mustsign[] = { |
232 | "op_endpoint", "return_to", "response_nonce", "assoc_handle", | 235 | "op_endpoint", "return_to", "response_nonce", "assoc_handle", |
233 | "claimed_id", "identity" }; | 236 | "claimed_id", "identity" }; |
234 | for(int ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) { | 237 | for(int ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) { |
235 | if(om.has_field(mustsign[ms]) && !signeds.has_field(mustsign[ms])) | 238 | if(om.has_field(mustsign[ms]) && !signeds.has_field(mustsign[ms])) |
236 | throw bad_input(OPKELE_CP_ string("Field '")+mustsign[ms]+"' is not signed against the specs"); | 239 | throw bad_input(OPKELE_CP_ string("Field '")+mustsign[ms]+"' is not signed against the specs"); |
237 | } | 240 | } |
238 | if( ( | 241 | if( ( |
239 | (om.has_field("claimed_id")?1:0) | 242 | (om.has_field("claimed_id")?1:0) |
240 | ^ | 243 | ^ |
241 | (om.has_field("identity")?1:0) | 244 | (om.has_field("identity")?1:0) |
242 | )&1 ) | 245 | )&1 ) |
243 | throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent"); | 246 | throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent"); |
244 | 247 | ||
245 | string turl = util::rfc_3986_normalize_uri(get_this_url()); | 248 | string turl = util::rfc_3986_normalize_uri(get_this_url()); |
246 | util::strip_uri_fragment_part(turl); | 249 | util::strip_uri_fragment_part(turl); |
247 | string rurl = util::rfc_3986_normalize_uri(om.get_field("return_to")); | 250 | string rurl = util::rfc_3986_normalize_uri(om.get_field("return_to")); |
248 | util::strip_uri_fragment_part(rurl); | 251 | util::strip_uri_fragment_part(rurl); |
249 | string::size_type | 252 | string::size_type |
250 | tq = turl.find('?'), rq = rurl.find('?'); | 253 | tq = turl.find('?'), rq = rurl.find('?'); |
251 | if( | 254 | if( |
252 | ((tq==string::npos)?turl:turl.substr(0,tq)) | 255 | ((tq==string::npos)?turl:turl.substr(0,tq)) |
253 | != | 256 | != |
254 | ((rq==string::npos)?rurl:rurl.substr(0,rq)) | 257 | ((rq==string::npos)?rurl:rurl.substr(0,rq)) |
255 | ) | 258 | ) |
256 | throw id_res_bad_return_to(OPKELE_CP_ "return_to url doesn't match request url"); | 259 | throw id_res_bad_return_to(OPKELE_CP_ "return_to url doesn't match request url"); |
257 | map<string,string> tp; parse_query(turl,tq,tp); | 260 | map<string,string> tp; parse_query(turl,tq,tp); |
258 | map<string,string> rp; parse_query(rurl,rq,rp); | 261 | map<string,string> rp; parse_query(rurl,rq,rp); |
259 | for(map<string,string>::const_iterator rpi=rp.begin();rpi!=rp.end();++rpi) { | 262 | for(map<string,string>::const_iterator rpi=rp.begin();rpi!=rp.end();++rpi) { |
260 | map<string,string>::const_iterator tpi = tp.find(rpi->first); | 263 | map<string,string>::const_iterator tpi = tp.find(rpi->first); |
261 | if(tpi==tp.end()) | 264 | if(tpi==tp.end()) |
262 | throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to is missing from the request"); | 265 | throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to is missing from the request"); |
263 | if(tpi->second!=rpi->second) | 266 | if(tpi->second!=rpi->second) |
264 | throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to doesn't matche the request"); | 267 | throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to doesn't matche the request"); |
265 | } | 268 | } |
266 | 269 | ||
267 | if(om.has_field("claimed_id")) { | 270 | if(om.has_field("claimed_id")) { |
268 | verify_OP( | 271 | verify_OP( |
269 | om.get_field("op_endpoint"), | 272 | om.get_field("op_endpoint"), |
270 | om.get_field("claimed_id"), | 273 | om.get_field("claimed_id"), |
271 | om.get_field("identity") ); | 274 | om.get_field("identity") ); |
272 | } | 275 | } |
273 | 276 | ||
274 | } | 277 | } |
275 | if(ext) ext->id_res_hook(om,signeds); | 278 | if(ext) ext->id_res_hook(om,signeds); |
276 | } | 279 | } |
277 | 280 | ||
278 | class check_auth_message_proxy : public basic_openid_message { | 281 | class check_auth_message_proxy : public basic_openid_message { |
279 | public: | 282 | public: |
280 | const basic_openid_message& x; | 283 | const basic_openid_message& x; |
281 | 284 | ||
282 | check_auth_message_proxy(const basic_openid_message& xx) : x(xx) { } | 285 | check_auth_message_proxy(const basic_openid_message& xx) : x(xx) { } |
283 | 286 | ||
284 | bool has_field(const string& n) const { return x.has_field(n); } | 287 | bool has_field(const string& n) const { return x.has_field(n); } |
285 | const string& get_field(const string& n) const { | 288 | const string& get_field(const string& n) const { |
286 | static const string checkauthmode="check_authentication"; | 289 | static const string checkauthmode="check_authentication"; |
287 | return (n=="mode")?checkauthmode:x.get_field(n); } | 290 | return (n=="mode")?checkauthmode:x.get_field(n); } |
288 | bool has_ns(const string& uri) const {return x.has_ns(uri); } | 291 | bool has_ns(const string& uri) const {return x.has_ns(uri); } |
289 | string get_ns(const string& uri) const { return x.get_ns(uri); } | 292 | string get_ns(const string& uri) const { return x.get_ns(uri); } |
290 | fields_iterator fields_begin() const { | 293 | fields_iterator fields_begin() const { |
291 | return x.fields_begin(); } | 294 | return x.fields_begin(); } |
292 | fields_iterator fields_end() const { | 295 | fields_iterator fields_end() const { |
293 | return x.fields_end(); } | 296 | return x.fields_end(); } |
294 | }; | 297 | }; |
295 | 298 | ||
296 | void basic_RP::check_authentication(const string& OP, | 299 | void basic_RP::check_authentication(const string& OP, |
297 | const basic_openid_message& om){ | 300 | const basic_openid_message& om){ |
298 | openid_message_t res; | 301 | openid_message_t res; |
299 | direct_request(res,check_auth_message_proxy(om),OP); | 302 | direct_request(res,check_auth_message_proxy(om),OP); |
300 | if(res.has_field("is_valid")) { | 303 | if(res.has_field("is_valid")) { |
301 | if(res.get_field("is_valid")=="true") { | 304 | if(res.get_field("is_valid")=="true") { |
302 | if(res.has_field("invalidate_handle")) | 305 | if(res.has_field("invalidate_handle")) |
303 | invalidate_assoc(OP,res.get_field("invalidate_handle")); | 306 | invalidate_assoc(OP,res.get_field("invalidate_handle")); |
304 | return; | 307 | return; |
305 | } | 308 | } |
306 | } | 309 | } |
307 | throw failed_check_authentication( | 310 | throw failed_check_authentication( |
308 | OPKELE_CP_ "failed to verify response"); | 311 | OPKELE_CP_ "failed to verify response"); |
309 | } | 312 | } |
310 | 313 | ||
311 | } | 314 | } |