summaryrefslogtreecommitdiffabout
authorMichael Krelin <hacker@klever.net>2008-02-02 19:57:52 (UTC)
committer Michael Krelin <hacker@klever.net>2008-02-02 19:57:52 (UTC)
commit529c53f0eb63040735b4cad7806cef6d5e65144b (patch) (side-by-side diff)
tree711cd9e8d30a9f251de529cdfcfcd05ac0e871b3
parent4efb668baed49ede14846c3cdac31cc561451cd1 (diff)
downloadlibopkele-529c53f0eb63040735b4cad7806cef6d5e65144b.zip
libopkele-529c53f0eb63040735b4cad7806cef6d5e65144b.tar.gz
libopkele-529c53f0eb63040735b4cad7806cef6d5e65144b.tar.bz2
check if return_to matches realm
Signed-off-by: Michael Krelin <hacker@klever.net>
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--include/opkele/exception.h9
-rw-r--r--lib/basic_op.cc36
2 files changed, 45 insertions, 0 deletions
diff --git a/include/opkele/exception.h b/include/opkele/exception.h
index 5c8418e..33f89cc 100644
--- a/include/opkele/exception.h
+++ b/include/opkele/exception.h
@@ -312,51 +312,60 @@ namespace opkele {
};
/**
* thrown by associations store related functions in case of dumb RP.
*/
class dumb_RP : public exception {
public:
dumb_RP(OPKELE_E_PARS)
: exception(OPKELE_E_CONS) { }
};
/**
* thrown by endpoint-queue related function if endpoint is being
* accessed but there's no endpoint available.
*/
class no_endpoint : public exception {
public:
no_endpoint(OPKELE_E_PARS)
: exception(OPKELE_E_CONS) { }
};
/**
* thrown while processing OpenID request in OP. Signifies invalid realm
*/
class bad_realm : public exception {
public:
bad_realm(OPKELE_E_PARS)
: exception(OPKELE_E_CONS) { }
};
/**
* thrown when attempting to retrieve return_to of one-way request
*/
class no_return_to : public exception {
public:
no_return_to(OPKELE_E_PARS)
: exception(OPKELE_E_CONS) { }
};
/**
* thrown when querying identity of non-identity related request
*/
class non_identity : public exception {
public:
non_identity(OPKELE_E_PARS)
: exception(OPKELE_E_CONS) { }
};
+ /**
+ * thrown if return_to URL doesn't match realm
+ */
+ class bad_return_to : public exception {
+ public:
+ bad_return_to(OPKELE_E_PARS)
+ : exception(OPKELE_E_CONS) { }
+ };
+
}
#endif /* __OPKELE_EXCEPTION_H */
diff --git a/lib/basic_op.cc b/lib/basic_op.cc
index 22012bc..f7573aa 100644
--- a/lib/basic_op.cc
+++ b/lib/basic_op.cc
@@ -1,59 +1,62 @@
#include <time.h>
#include <cassert>
+#include <algorithm>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <opkele/data.h>
#include <opkele/basic_op.h>
#include <opkele/exception.h>
#include <opkele/util.h>
#include <opkele/uris.h>
namespace opkele {
+ using std::pair;
+ using std::mismatch;
void basic_op::reset_vars() {
assoc.reset();
return_to.clear(); realm.clear();
claimed_id.clear(); identity.clear();
invalidate_handle.clear();
}
bool basic_op::has_return_to() const {
return !return_to.empty();
}
const string& basic_op::get_return_to() const {
if(return_to.empty())
throw no_return_to(OPKELE_CP_ "No return_to URL provided with request");
return return_to;
}
const string& basic_op::get_realm() const {
assert(!realm.empty());
return realm;
}
bool basic_op::has_identity() const {
return !identity.empty();
}
const string& basic_op::get_claimed_id() const {
if(claimed_id.empty())
throw non_identity(OPKELE_CP_ "attempting to retrieve claimed_id of non-identity related request");
assert(!identity.empty());
return claimed_id;
}
const string& basic_op::get_identity() const {
if(identity.empty())
throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related request");
assert(!claimed_id.empty());
return identity;
}
bool basic_op::is_id_select() const {
return identity==IDURI_SELECT20;
}
void basic_op::select_identity(const string& c,const string& i) {
claimed_id = c; identity = i;
}
void basic_op::set_claimed_id(const string& c) {
claimed_id = c;
}
@@ -272,49 +275,82 @@ namespace opkele {
bool o2;
try {
o2 = (inm.get_field("ns")==OIURI_OPENID20);
}catch(failed_lookup&) { o2 = false; }
string nonce;
if(o2) {
try {
if(!check_nonce(nonce = inm.get_field("response_nonce")))
throw failed_check_authentication(OPKELE_CP_ "Invalid nonce");
}catch(failed_lookup&) {
throw failed_check_authentication(OPKELE_CP_ "No nonce provided with check_authentication request");
}
}
try {
assoc = retrieve_assoc(inm.get_field("assoc_handle"));
if(!assoc->stateless())
throw failed_check_authentication(OPKELE_CP_ "Will not do check_authentication on a stateful handle");
}catch(failed_lookup&) {
throw failed_check_authentication(OPKELE_CP_ "No assoc_handle or invalid assoc_handle specified with check_authentication request");
}
static const string idresmode = "id_res";
try {
if(util::base64_signature(assoc,util::change_mode_message_proxy(inm,idresmode))!=inm.get_field("sig"))
throw failed_check_authentication(OPKELE_CP_ "Signature mismatch");
}catch(failed_lookup&) {
throw failed_check_authentication(OPKELE_CP_ "failed to calculate signature");
}
oum.set_field("is_valid","true");
try {
string h = inm.get_field("invalidate_handle");
try {
assoc_t ih = retrieve_assoc(h);
}catch(invalid_handle& ih) {
oum.set_field("invalidate_handle",h);
}catch(failed_lookup& ih) {
oum.set_field("invalidate_handle",h);
}
}catch(failed_lookup&) { }
if(o2) {
assert(!nonce.empty());
invalidate_nonce(nonce);
}
return oum;
}catch(failed_check_authentication& ) {
oum.set_field("is_valid","false");
return oum;
}
+ void basic_op::verify_return_to() {
+ string nrealm = opkele::util::rfc_3986_normalize_uri(realm);
+ if(nrealm.find('#')!=string::npos)
+ throw opkele::bad_realm(OPKELE_CP_ "authentication realm contains URI fragment");
+ string nrt = opkele::util::rfc_3986_normalize_uri(return_to);
+ string::size_type pr = nrealm.find("://");
+ string::size_type prt = nrt.find("://");
+ assert(!(pr==string::npos || prt==string::npos));
+ pr += sizeof("://")-1;
+ prt += sizeof("://")-1;
+ if(!strncmp(nrealm.c_str()+pr,"*.",2)) {
+ pr = nrealm.find('.',pr);
+ prt = nrt.find('.',prt);
+ assert(pr!=string::npos);
+ if(prt==string::npos)
+ throw bad_return_to(
+ OPKELE_CP_ "return_to URL doesn't match realm");
+ // TODO: check for overgeneralized realm
+ }
+ string::size_type lr = nrealm.length();
+ string::size_type lrt = nrt.length();
+ if( (lrt-prt) < (lr-pr) )
+ throw bad_return_to(
+ OPKELE_CP_ "return_to URL doesn't match realm");
+ pair<const char*,const char*> mp = mismatch(
+ nrealm.c_str()+pr,nrealm.c_str()+lr,
+ nrt.c_str()+prt);
+ if( (*(mp.first-1))!='/'
+ && !strchr("/?#",*mp.second) )
+ throw bad_return_to(
+ OPKELE_CP_ "return_to URL doesn't match realm");
+ }
+
}