forked from hacker/libopkele
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Thanks to Joseph Smarr (now) of Plaxo for contributing these extensions! Signed-off-by: Michael Krelin <hacker@klever.net>
- Loading branch information
Showing
4 changed files
with
356 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
#ifndef __OPKELE_AX_H | ||
#define __OPKELE_AX_H | ||
|
||
/** | ||
* @file | ||
* @brief Attribute Exchange extension | ||
*/ | ||
|
||
#include <opkele/extension.h> | ||
|
||
namespace opkele { | ||
|
||
/** | ||
* OpenID simple registration extension implementation | ||
* http://openid.net/specs/openid-simple-registration-extension-1_0.html | ||
*/ | ||
class ax_t : public extension_t { | ||
public: | ||
/** special "count" value for add_attribute to request fetching "as many values as possible". */ | ||
static const int UNLIMITED_COUNT = -1; | ||
|
||
/** | ||
* Optional URL for receiving future attribute updates. | ||
* Set it before checkid_setup to send up the URL; read it after id_res to get it back. | ||
*/ | ||
std::string update_url; | ||
|
||
/** | ||
* Consumer constructor. | ||
*/ | ||
ax_t() : alias_count(0) { } | ||
|
||
/** Adds an attribute to request during checkid_setup. */ | ||
void add_attribute(const char *uri, bool required, const char *alias = NULL, int count = 1); | ||
|
||
/** Returns an attribute fetched for the given type-uri during id_res. */ | ||
std::string get_attribute(const char *uri, int index = 0); | ||
/** Returns the number of values fetched for the given type-uri during id_res. */ | ||
size_t get_attribute_count(const char *uri); | ||
|
||
virtual void rp_checkid_hook(basic_openid_message& om); | ||
virtual void rp_id_res_hook(const basic_openid_message& om, | ||
const basic_openid_message& sp); | ||
virtual void op_checkid_hook(const basic_openid_message& inm); | ||
virtual void op_id_res_hook(basic_openid_message& oum); | ||
|
||
virtual void checkid_hook(basic_openid_message& om); | ||
virtual void id_res_hook(const basic_openid_message& om, | ||
const basic_openid_message& sp); | ||
virtual void checkid_hook(const basic_openid_message& inm, | ||
basic_openid_message& oum); | ||
|
||
/** | ||
* Function called after parsing sreg request to set up response | ||
* fields. The default implementation tries to send as much fields | ||
* as we have. The function is supposed to set the data and | ||
* fields_response. | ||
* @see fields_response | ||
* @param inm incoming openid message | ||
* @param oum outgoing openid message | ||
*/ | ||
virtual void setup_response(const basic_openid_message& inm, | ||
basic_openid_message& oum); | ||
|
||
virtual void setup_response(); | ||
|
||
protected: | ||
/** Stores attributes to request fetching during checkid_setup. */ | ||
struct ax_attr_t { | ||
std::string uri; | ||
std::string alias; | ||
bool required; | ||
int count; | ||
}; | ||
std::vector<ax_attr_t> attrs; | ||
unsigned int alias_count; // auto-incr counter for auto-named aliases | ||
|
||
/** Stores results from fetch response during id_res. */ | ||
std::map<std::string, std::vector<std::string> > response_attrs; | ||
}; | ||
} | ||
|
||
#endif /* __OPKELE_SREG_H */ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#ifndef __OPKELE_OAUTH_EXT_H | ||
#define __OPKELE_OAUTH_EXT_H | ||
|
||
/** | ||
* @file | ||
* @brief OAuth extension | ||
*/ | ||
|
||
#include <opkele/extension.h> | ||
|
||
namespace opkele { | ||
|
||
/** | ||
* OpenID OAuth extension | ||
* http://step2.googlecode.com/svn/spec/openid_oauth_extension/latest/openid_oauth_extension.html | ||
*/ | ||
class oauth_ext_t : public extension_t { | ||
public: | ||
std::string m_consumer, m_scope, m_request_token; | ||
|
||
/** | ||
* Consumer constructor. | ||
* @param fr required fields | ||
* @see fields_required | ||
* @param fo optional fields | ||
* @see fields_optional | ||
* @param pu policy url | ||
* @see policy_url | ||
*/ | ||
oauth_ext_t(const char *consumer = "", const char *scope = "") : m_consumer(consumer), m_scope(scope) { } | ||
|
||
virtual void rp_checkid_hook(basic_openid_message& om); | ||
virtual void rp_id_res_hook(const basic_openid_message& om, | ||
const basic_openid_message& sp); | ||
virtual void op_checkid_hook(const basic_openid_message& inm); | ||
virtual void op_id_res_hook(basic_openid_message& oum); | ||
|
||
virtual void checkid_hook(basic_openid_message& om); | ||
virtual void id_res_hook(const basic_openid_message& om, | ||
const basic_openid_message& sp); | ||
virtual void checkid_hook(const basic_openid_message& inm, | ||
basic_openid_message& oum); | ||
|
||
/** | ||
* Function called after parsing sreg request to set up response | ||
* fields. The default implementation tries to send as much fields | ||
* as we have. The function is supposed to set the data and | ||
* fields_response. | ||
* @see fields_response | ||
* @param inm incoming openid message | ||
* @param oum outgoing openid message | ||
*/ | ||
virtual void setup_response(const basic_openid_message& inm, | ||
basic_openid_message& oum); | ||
|
||
virtual void setup_response(); | ||
|
||
}; | ||
} | ||
|
||
#endif /* __OPKELE_OAUTH_EXT_H */ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
#include <opkele/exception.h> | ||
#include <opkele/ax.h> | ||
#include <opkele/uris.h> | ||
#include <opkele/util.h> | ||
|
||
#include <map> | ||
#include <string> | ||
#include <vector> | ||
|
||
using namespace std; | ||
|
||
namespace opkele { | ||
|
||
void ax_t::add_attribute(const char *uri, bool required, const char *alias /* = NULL */, int count /* = 1 */) { | ||
assert(uri && *uri); | ||
assert(count != 0); | ||
|
||
ax_attr_t attr; | ||
attr.uri = uri; | ||
attr.required = required; | ||
attr.count = count; | ||
// if no alias is specified, generate one using an internal auto-incremented counter | ||
attr.alias = alias ? alias : string("attr") + opkele::util::long_to_string(++alias_count); | ||
|
||
attrs.push_back(attr); | ||
} | ||
|
||
void ax_t::rp_checkid_hook(basic_openid_message& om) { | ||
if (attrs.size() == 0) return; // not asking for any attributes | ||
|
||
string pfx = om.allocate_ns(OIURI_AX10,"ax"); | ||
om.set_field(pfx+".mode", "fetch_request"); // only supports fetch_request for now | ||
|
||
string required_fields, optional_fields; | ||
for (size_t i = 0; i < attrs.size(); i++) { | ||
// build up list of required/optional aliases | ||
if (attrs[i].required) required_fields += (required_fields.empty() ? "" : ",") + attrs[i].alias; | ||
else optional_fields += (optional_fields.empty() ? "" : ",") + attrs[i].alias; | ||
|
||
om.set_field(pfx+".type."+attrs[i].alias, attrs[i].uri); | ||
|
||
// only specify count if it's >1 or unlimited | ||
if (attrs[i].count == UNLIMITED_COUNT) { | ||
om.set_field(pfx+".count."+attrs[i].alias, "unlimited"); | ||
} else if (attrs[i].count > 1) { | ||
om.set_field(pfx+".count."+attrs[i].alias, opkele::util::long_to_string(attrs[i].count)); | ||
} | ||
} | ||
|
||
if (!required_fields.empty()) om.set_field(pfx+".required", required_fields); | ||
if (!optional_fields.empty()) om.set_field(pfx+".if_available", optional_fields); | ||
|
||
if (!update_url.empty()) om.set_field(pfx+".update_url", update_url); | ||
} | ||
|
||
void ax_t::checkid_hook(basic_openid_message& om) { | ||
rp_checkid_hook(om); } | ||
|
||
void ax_t::rp_id_res_hook(const basic_openid_message& om, | ||
const basic_openid_message& sp) { | ||
string pfx; | ||
try { | ||
pfx = om.find_ns(OIURI_AX10,"ax"); | ||
}catch(failed_lookup&) { | ||
return; | ||
} | ||
pfx += '.'; | ||
|
||
// first look at all aliases and generate an internal uri->alias map | ||
string fn; | ||
map<string, string> aliases; | ||
for (basic_openid_message::fields_iterator it = sp.fields_begin(); it != sp.fields_end(); ++it) { | ||
fn = *it; | ||
string type_pfx = pfx; type_pfx += "type."; | ||
size_t pos = fn.find(type_pfx); | ||
if (pos == string::npos) continue; | ||
string alias = fn.substr(pos + type_pfx.size()); | ||
aliases[sp.get_field(fn)] = alias; | ||
} | ||
|
||
// now for each alias, pull out the count and value(s) and store uri->[value1, ...] | ||
for (map<string, string>::iterator it = aliases.begin(); it != aliases.end(); ++it) { | ||
vector<string> values; | ||
fn = pfx; fn += "count." + it->second; | ||
if (sp.has_field(fn)) { | ||
int count = opkele::util::string_to_long(sp.get_field(fn)); | ||
for (int i = 1; i <= count; i++) { | ||
fn = pfx; fn += "value." + it->second + "." + opkele::util::long_to_string(i); | ||
values.push_back(sp.get_field(fn)); | ||
} | ||
} else { | ||
fn = pfx; fn += "value." + it->second; | ||
values.push_back(sp.get_field(fn)); | ||
} | ||
response_attrs[it->first] = values; | ||
} | ||
|
||
fn = pfx; fn += "update_url"; | ||
if (sp.has_field(fn)) update_url = sp.get_field(fn); | ||
} | ||
|
||
string ax_t::get_attribute(const char *uri, int index /* = 0 */) { | ||
if (response_attrs.find(uri) == response_attrs.end()) return ""; | ||
return response_attrs[uri][index]; | ||
} | ||
|
||
size_t ax_t::get_attribute_count(const char *uri) { | ||
if (response_attrs.find(uri) == response_attrs.end()) return 0; | ||
return response_attrs[uri].size(); | ||
} | ||
|
||
void ax_t::id_res_hook(const basic_openid_message& om, | ||
const basic_openid_message& sp) { | ||
rp_id_res_hook(om,sp); } | ||
|
||
void ax_t::op_checkid_hook(const basic_openid_message& inm) { | ||
} | ||
|
||
void ax_t::op_id_res_hook(basic_openid_message& oum) { | ||
} | ||
|
||
void ax_t::checkid_hook(const basic_openid_message& inm, | ||
basic_openid_message& oum) { | ||
op_checkid_hook(inm); | ||
setup_response(inm,oum); | ||
op_id_res_hook(oum); | ||
} | ||
|
||
void ax_t::setup_response(const basic_openid_message& /* inm */,basic_openid_message& /* oum */) { | ||
setup_response(); | ||
} | ||
void ax_t::setup_response() { | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
#include <opkele/exception.h> | ||
#include <opkele/oauth_ext.h> | ||
#include <opkele/uris.h> | ||
#include <algorithm> | ||
|
||
namespace opkele { | ||
using std::find; | ||
|
||
void oauth_ext_t::rp_checkid_hook(basic_openid_message& om) { | ||
|
||
string pfx = om.allocate_ns(OIURI_OAUTH10,"oauth"); | ||
//required: openid.oauth.consumer=www.plaxo.com | ||
//optional: openid.oauth.scope=http://www.google.com/m8/feeds/ | ||
if (m_consumer.empty()) throw bad_input(OPKELE_CP_ "Required consumer key is missing from OAuth extension"); | ||
om.set_field(pfx+".consumer", m_consumer); | ||
if (!m_scope.empty()) om.set_field(pfx+".scope", m_scope); | ||
} | ||
|
||
void oauth_ext_t::checkid_hook(basic_openid_message& om) { | ||
rp_checkid_hook(om); } | ||
|
||
void oauth_ext_t::rp_id_res_hook(const basic_openid_message& om, | ||
const basic_openid_message& sp) { | ||
string pfx; | ||
try { | ||
pfx = om.get_ns(OIURI_OAUTH10); | ||
}catch(failed_lookup&) { | ||
return; | ||
} | ||
pfx += '.'; | ||
//required: openid.oauth.request_token=abcdefg | ||
//optional: openid.oauth.consumer=www.plaxo.com | ||
//optional: openid.oauth.scope=http://www.google.com/m8/feeds/ | ||
string fn; | ||
|
||
fn = pfx + "request_token"; | ||
if (sp.has_field(fn)) { | ||
m_request_token = sp.get_field(fn); | ||
} else throw bad_input(OPKELE_CP_ "Missing required response field: "+fn); | ||
|
||
fn = pfx + "consumer"; | ||
if (sp.has_field(fn)) { | ||
m_consumer = sp.get_field(fn); | ||
} | ||
|
||
fn = pfx + "scope"; | ||
if (sp.has_field(fn)) { | ||
m_scope = sp.get_field(fn); | ||
} | ||
} | ||
|
||
void oauth_ext_t::id_res_hook(const basic_openid_message& om, | ||
const basic_openid_message& sp) { | ||
rp_id_res_hook(om,sp); } | ||
|
||
void oauth_ext_t::op_checkid_hook(const basic_openid_message& inm) { | ||
} | ||
|
||
void oauth_ext_t::op_id_res_hook(basic_openid_message& oum) { | ||
} | ||
|
||
void oauth_ext_t::checkid_hook(const basic_openid_message& inm, | ||
basic_openid_message& oum) { | ||
op_checkid_hook(inm); | ||
setup_response(inm,oum); | ||
op_id_res_hook(oum); | ||
} | ||
|
||
void oauth_ext_t::setup_response(const basic_openid_message& /* inm */,basic_openid_message& /* oum */) { | ||
setup_response(); | ||
} | ||
void oauth_ext_t::setup_response() { | ||
} | ||
} | ||
|