summaryrefslogtreecommitdiffabout
authorMichael Krelin <hacker@klever.net>2008-02-02 21:10:12 (UTC)
committer Michael Krelin <hacker@klever.net>2008-02-02 21:10:12 (UTC)
commit3658759966cbadb7b50457d446f3436b6f7987da (patch) (unidiff)
treeb215da5b5212b60aa1ec965df28070b4bff587bc
parenta8f733c88d87abe422ecaa405df385bad562e60f (diff)
downloadlibopkele-3658759966cbadb7b50457d446f3436b6f7987da.zip
libopkele-3658759966cbadb7b50457d446f3436b6f7987da.tar.gz
libopkele-3658759966cbadb7b50457d446f3436b6f7987da.tar.bz2
moved uri matching into separate procedure
Signed-off-by: Michael Krelin <hacker@klever.net>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/opkele/util.h8
-rw-r--r--lib/basic_op.cc35
-rw-r--r--lib/util.cc30
3 files changed, 41 insertions, 32 deletions
diff --git a/include/opkele/util.h b/include/opkele/util.h
index 719f951..bc1a0ea 100644
--- a/include/opkele/util.h
+++ b/include/opkele/util.h
@@ -124,48 +124,56 @@ namespace opkele {
124 /** 124 /**
125 * Encode binary data using base64. 125 * Encode binary data using base64.
126 * @param data pointer to binary data 126 * @param data pointer to binary data
127 * @param length length of data 127 * @param length length of data
128 * @return encoded data 128 * @return encoded data
129 */ 129 */
130 string encode_base64(const void *data,size_t length); 130 string encode_base64(const void *data,size_t length);
131 /** 131 /**
132 * Decode binary data from base64 representation. 132 * Decode binary data from base64 representation.
133 * @param data base64-encoded data 133 * @param data base64-encoded data
134 * @param rv container for decoded binary 134 * @param rv container for decoded binary
135 */ 135 */
136 void decode_base64(const string& data,vector<unsigned char>& rv); 136 void decode_base64(const string& data,vector<unsigned char>& rv);
137 137
138 /** 138 /**
139 * Normalize http(s) URI according to RFC3986, section 6. URI is 139 * Normalize http(s) URI according to RFC3986, section 6. URI is
140 * expected to have scheme: in front of it. 140 * expected to have scheme: in front of it.
141 * @param uri URI 141 * @param uri URI
142 * @return normalized URI 142 * @return normalized URI
143 * @throw not_implemented in case of non-httpi(s) URI 143 * @throw not_implemented in case of non-httpi(s) URI
144 * @throw bad_input in case of malformed URI 144 * @throw bad_input in case of malformed URI
145 */ 145 */
146 string rfc_3986_normalize_uri(const string& uri); 146 string rfc_3986_normalize_uri(const string& uri);
147 147
148 /**
149 * Match URI against realm
150 * @param uri URI to match
151 * @param realm realm to match against
152 * @return true if URI matches realm
153 */
154 bool uri_matches_realm(const string& uri,const string& realm);
155
148 string& strip_uri_fragment_part(string& uri); 156 string& strip_uri_fragment_part(string& uri);
149 157
150 string abi_demangle(const char* mn); 158 string abi_demangle(const char* mn);
151 159
152 string base64_signature(const assoc_t& assoc,const basic_openid_message& om); 160 string base64_signature(const assoc_t& assoc,const basic_openid_message& om);
153 161
154 class change_mode_message_proxy : public basic_openid_message { 162 class change_mode_message_proxy : public basic_openid_message {
155 public: 163 public:
156 const basic_openid_message& x; 164 const basic_openid_message& x;
157 const string& mode; 165 const string& mode;
158 166
159 change_mode_message_proxy(const basic_openid_message& xx,const string& m) : x(xx), mode(m) { } 167 change_mode_message_proxy(const basic_openid_message& xx,const string& m) : x(xx), mode(m) { }
160 168
161 bool has_field(const string& n) const { return x.has_field(n); } 169 bool has_field(const string& n) const { return x.has_field(n); }
162 const string& get_field(const string& n) const { 170 const string& get_field(const string& n) const {
163 return (n=="mode")?mode:x.get_field(n); } 171 return (n=="mode")?mode:x.get_field(n); }
164 bool has_ns(const string& uri) const {return x.has_ns(uri); } 172 bool has_ns(const string& uri) const {return x.has_ns(uri); }
165 string get_ns(const string& uri) const { return x.get_ns(uri); } 173 string get_ns(const string& uri) const { return x.get_ns(uri); }
166 fields_iterator fields_begin() const { 174 fields_iterator fields_begin() const {
167 return x.fields_begin(); } 175 return x.fields_begin(); }
168 fields_iterator fields_end() const { 176 fields_iterator fields_end() const {
169 return x.fields_end(); } 177 return x.fields_end(); }
170 }; 178 };
171 179
diff --git a/lib/basic_op.cc b/lib/basic_op.cc
index f7573aa..11ffb48 100644
--- a/lib/basic_op.cc
+++ b/lib/basic_op.cc
@@ -1,38 +1,35 @@
1#include <time.h> 1#include <time.h>
2#include <cassert> 2#include <cassert>
3#include <algorithm>
4#include <openssl/sha.h> 3#include <openssl/sha.h>
5#include <openssl/hmac.h> 4#include <openssl/hmac.h>
6#include <opkele/data.h> 5#include <opkele/data.h>
7#include <opkele/basic_op.h> 6#include <opkele/basic_op.h>
8#include <opkele/exception.h> 7#include <opkele/exception.h>
9#include <opkele/util.h> 8#include <opkele/util.h>
10#include <opkele/uris.h> 9#include <opkele/uris.h>
11 10
12namespace opkele { 11namespace opkele {
13 using std::pair;
14 using std::mismatch;
15 12
16 void basic_op::reset_vars() { 13 void basic_op::reset_vars() {
17 assoc.reset(); 14 assoc.reset();
18 return_to.clear(); realm.clear(); 15 return_to.clear(); realm.clear();
19 claimed_id.clear(); identity.clear(); 16 claimed_id.clear(); identity.clear();
20 invalidate_handle.clear(); 17 invalidate_handle.clear();
21 } 18 }
22 19
23 bool basic_op::has_return_to() const { 20 bool basic_op::has_return_to() const {
24 return !return_to.empty(); 21 return !return_to.empty();
25 } 22 }
26 const string& basic_op::get_return_to() const { 23 const string& basic_op::get_return_to() const {
27 if(return_to.empty()) 24 if(return_to.empty())
28 throw no_return_to(OPKELE_CP_ "No return_to URL provided with request"); 25 throw no_return_to(OPKELE_CP_ "No return_to URL provided with request");
29 return return_to; 26 return return_to;
30 } 27 }
31 28
32 const string& basic_op::get_realm() const { 29 const string& basic_op::get_realm() const {
33 assert(!realm.empty()); 30 assert(!realm.empty());
34 return realm; 31 return realm;
35 } 32 }
36 33
37 bool basic_op::has_identity() const { 34 bool basic_op::has_identity() const {
38 return !identity.empty(); 35 return !identity.empty();
@@ -300,57 +297,31 @@ namespace opkele {
300 throw failed_check_authentication(OPKELE_CP_ "failed to calculate signature"); 297 throw failed_check_authentication(OPKELE_CP_ "failed to calculate signature");
301 } 298 }
302 oum.set_field("is_valid","true"); 299 oum.set_field("is_valid","true");
303 try { 300 try {
304 string h = inm.get_field("invalidate_handle"); 301 string h = inm.get_field("invalidate_handle");
305 try { 302 try {
306 assoc_t ih = retrieve_assoc(h); 303 assoc_t ih = retrieve_assoc(h);
307 }catch(invalid_handle& ih) { 304 }catch(invalid_handle& ih) {
308 oum.set_field("invalidate_handle",h); 305 oum.set_field("invalidate_handle",h);
309 }catch(failed_lookup& ih) { 306 }catch(failed_lookup& ih) {
310 oum.set_field("invalidate_handle",h); 307 oum.set_field("invalidate_handle",h);
311 } 308 }
312 }catch(failed_lookup&) { } 309 }catch(failed_lookup&) { }
313 if(o2) { 310 if(o2) {
314 assert(!nonce.empty()); 311 assert(!nonce.empty());
315 invalidate_nonce(nonce); 312 invalidate_nonce(nonce);
316 } 313 }
317 return oum; 314 return oum;
318 }catch(failed_check_authentication& ) { 315 }catch(failed_check_authentication& ) {
319 oum.set_field("is_valid","false"); 316 oum.set_field("is_valid","false");
320 return oum; 317 return oum;
321 } 318 }
322 319
323 void basic_op::verify_return_to() { 320 void basic_op::verify_return_to() {
324 string nrealm = opkele::util::rfc_3986_normalize_uri(realm); 321 if(realm.find('#')!=string::npos)
325 if(nrealm.find('#')!=string::npos)
326 throw opkele::bad_realm(OPKELE_CP_ "authentication realm contains URI fragment"); 322 throw opkele::bad_realm(OPKELE_CP_ "authentication realm contains URI fragment");
327 string nrt = opkele::util::rfc_3986_normalize_uri(return_to); 323 if(!util::uri_matches_realm(return_to,realm))
328 string::size_type pr = nrealm.find("://"); 324 throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match realm");
329 string::size_type prt = nrt.find("://");
330 assert(!(pr==string::npos || prt==string::npos));
331 pr += sizeof("://")-1;
332 prt += sizeof("://")-1;
333 if(!strncmp(nrealm.c_str()+pr,"*.",2)) {
334 pr = nrealm.find('.',pr);
335 prt = nrt.find('.',prt);
336 assert(pr!=string::npos);
337 if(prt==string::npos)
338 throw bad_return_to(
339 OPKELE_CP_ "return_to URL doesn't match realm");
340 // TODO: check for overgeneralized realm
341 }
342 string::size_type lr = nrealm.length();
343 string::size_type lrt = nrt.length();
344 if( (lrt-prt) < (lr-pr) )
345 throw bad_return_to(
346 OPKELE_CP_ "return_to URL doesn't match realm");
347 pair<const char*,const char*> mp = mismatch(
348 nrealm.c_str()+pr,nrealm.c_str()+lr,
349 nrt.c_str()+prt);
350 if( (*(mp.first-1))!='/'
351 && !strchr("/?#",*mp.second) )
352 throw bad_return_to(
353 OPKELE_CP_ "return_to URL doesn't match realm");
354 } 325 }
355 326
356} 327}
diff --git a/lib/util.cc b/lib/util.cc
index b7bc437..b85a377 100644
--- a/lib/util.cc
+++ b/lib/util.cc
@@ -1,31 +1,32 @@
1#include <errno.h> 1#include <errno.h>
2#include <cassert> 2#include <cassert>
3#include <cctype> 3#include <cctype>
4#include <cstring> 4#include <cstring>
5#include <vector> 5#include <vector>
6#include <string> 6#include <string>
7#include <stack> 7#include <stack>
8#include <algorithm>
8#include <openssl/bio.h> 9#include <openssl/bio.h>
9#include <openssl/evp.h> 10#include <openssl/evp.h>
10#include <openssl/hmac.h> 11#include <openssl/hmac.h>
11#include <curl/curl.h> 12#include <curl/curl.h>
12#include "opkele/util.h" 13#include "opkele/util.h"
13#include "opkele/exception.h" 14#include "opkele/exception.h"
14 15
15#include <config.h> 16#include <config.h>
16#ifdef HAVE_DEMANGLE 17#ifdef HAVE_DEMANGLE
17# include <cxxabi.h> 18# include <cxxabi.h>
18#endif 19#endif
19 20
20namespace opkele { 21namespace opkele {
21 using namespace std; 22 using namespace std;
22 23
23 namespace util { 24 namespace util {
24 25
25 /* 26 /*
26 * base64 27 * base64
27 */ 28 */
28 string encode_base64(const void *data,size_t length) { 29 string encode_base64(const void *data,size_t length) {
29 BIO *b64 = 0, *bmem = 0; 30 BIO *b64 = 0, *bmem = 0;
30 try { 31 try {
31 b64 = BIO_new(BIO_f_base64()); 32 b64 = BIO_new(BIO_f_base64());
@@ -330,48 +331,77 @@ namespace opkele {
330 } 331 }
331 if(!pseg.empty()) { 332 if(!pseg.empty()) {
332 if(!qf) rv += '/'; 333 if(!qf) rv += '/';
333 rv += pseg; 334 rv += pseg;
334 } 335 }
335 return rv; 336 return rv;
336 } 337 }
337 338
338 string& strip_uri_fragment_part(string& u) { 339 string& strip_uri_fragment_part(string& u) {
339 string::size_type q = u.find('?'), f = u.find('#'); 340 string::size_type q = u.find('?'), f = u.find('#');
340 if(q==string::npos) { 341 if(q==string::npos) {
341 if(f!=string::npos) 342 if(f!=string::npos)
342 u.erase(f); 343 u.erase(f);
343 }else{ 344 }else{
344 if(f!=string::npos) { 345 if(f!=string::npos) {
345 if(f<q) 346 if(f<q)
346 u.erase(f,q-f); 347 u.erase(f,q-f);
347 else 348 else
348 u.erase(f); 349 u.erase(f);
349 } 350 }
350 } 351 }
351 return u; 352 return u;
352 } 353 }
353 354
355 bool uri_matches_realm(const string& uri,const string& realm) {
356 string nrealm = opkele::util::rfc_3986_normalize_uri(realm);
357 string nu = opkele::util::rfc_3986_normalize_uri(uri);
358 string::size_type pr = nrealm.find("://");
359 string::size_type pu = nu.find("://");
360 assert(!(pr==string::npos || pu==string::npos));
361 pr += sizeof("://")-1;
362 pu += sizeof("://")-1;
363 if(!strncmp(nrealm.c_str()+pr,"*.",2)) {
364 pr = nrealm.find('.',pr);
365 pu = nu.find('.',pu);
366 assert(pr!=string::npos);
367 if(pu==string::npos)
368 return false;
369 // TODO: check for overgeneralized realm
370 }
371 string::size_type lr = nrealm.length();
372 string::size_type lu = nu.length();
373 if( (lu-pu) < (lr-pr) )
374 return false;
375 pair<const char*,const char*> mp = mismatch(
376 nrealm.c_str()+pr,nrealm.c_str()+lr,
377 nu.c_str()+pu);
378 if( (*(mp.first-1))!='/'
379 && !strchr("/?#",*mp.second) )
380 return false;
381 return true;
382 }
383
354 string abi_demangle(const char *mn) { 384 string abi_demangle(const char *mn) {
355#ifndef HAVE_DEMANGLE 385#ifndef HAVE_DEMANGLE
356 return mn; 386 return mn;
357#else /* !HAVE_DEMANGLE */ 387#else /* !HAVE_DEMANGLE */
358 int dstat; 388 int dstat;
359 char *demangled = abi::__cxa_demangle(mn,0,0,&dstat); 389 char *demangled = abi::__cxa_demangle(mn,0,0,&dstat);
360 if(dstat) 390 if(dstat)
361 return mn; 391 return mn;
362 string rv = demangled; 392 string rv = demangled;
363 free(demangled); 393 free(demangled);
364 return rv; 394 return rv;
365#endif /* !HAVE_DEMANGLE */ 395#endif /* !HAVE_DEMANGLE */
366 } 396 }
367 397
368 string base64_signature(const assoc_t& assoc,const basic_openid_message& om) { 398 string base64_signature(const assoc_t& assoc,const basic_openid_message& om) {
369 const string& slist = om.get_field("signed"); 399 const string& slist = om.get_field("signed");
370 string kv; 400 string kv;
371 string::size_type p=0; 401 string::size_type p=0;
372 while(true) { 402 while(true) {
373 string::size_type co = slist.find(',',p); 403 string::size_type co = slist.find(',',p);
374 string f = (co==string::npos) 404 string f = (co==string::npos)
375 ?slist.substr(p):slist.substr(p,co-p); 405 ?slist.substr(p):slist.substr(p,co-p);
376 kv += f; 406 kv += f;
377 kv += ':'; 407 kv += ':';