Skip to content

Commit

Permalink
put Joseph's files into repository
Browse files Browse the repository at this point in the history
Thanks to Joseph Smarr (now) of Plaxo for contributing these extensions!

Signed-off-by: Michael Krelin <hacker@klever.net>
  • Loading branch information
Joseph Smarr authored and hacker committed Dec 22, 2009
1 parent bd4c671 commit 142ca30
Show file tree
Hide file tree
Showing 4 changed files with 356 additions and 0 deletions.
84 changes: 84 additions & 0 deletions include/opkele/ax.h
@@ -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 */

62 changes: 62 additions & 0 deletions include/opkele/oauth_ext.h
@@ -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 */

135 changes: 135 additions & 0 deletions lib/ax.cc
@@ -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() {
}
}

75 changes: 75 additions & 0 deletions lib/oauth_ext.cc
@@ -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() {
}
}

0 comments on commit 142ca30

Please sign in to comment.