summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--include/opkele/ax.h84
-rw-r--r--include/opkele/oauth_ext.h62
-rw-r--r--lib/ax.cc135
-rw-r--r--lib/oauth_ext.cc75
4 files changed, 356 insertions, 0 deletions
diff --git a/include/opkele/ax.h b/include/opkele/ax.h
new file mode 100644
index 0000000..996d756
--- a/dev/null
+++ b/include/opkele/ax.h
@@ -0,0 +1,84 @@
1#ifndef __OPKELE_AX_H
2#define __OPKELE_AX_H
3
4/**
5 * @file
6 * @brief Attribute Exchange extension
7 */
8
9#include <opkele/extension.h>
10
11namespace opkele {
12
13 /**
14 * OpenID simple registration extension implementation
15 * http://openid.net/specs/openid-simple-registration-extension-1_0.html
16 */
17 class ax_t : public extension_t {
18 public:
19 /** special "count" value for add_attribute to request fetching "as many values as possible". */
20 static const int UNLIMITED_COUNT = -1;
21
22 /**
23 * Optional URL for receiving future attribute updates.
24 * Set it before checkid_setup to send up the URL; read it after id_res to get it back.
25 */
26 std::string update_url;
27
28 /**
29 * Consumer constructor.
30 */
31 ax_t() : alias_count(0) { }
32
33 /** Adds an attribute to request during checkid_setup. */
34 void add_attribute(const char *uri, bool required, const char *alias = NULL, int count = 1);
35
36 /** Returns an attribute fetched for the given type-uri during id_res. */
37 std::string get_attribute(const char *uri, int index = 0);
38 /** Returns the number of values fetched for the given type-uri during id_res. */
39 size_t get_attribute_count(const char *uri);
40
41 virtual void rp_checkid_hook(basic_openid_message& om);
42 virtual void rp_id_res_hook(const basic_openid_message& om,
43 const basic_openid_message& sp);
44 virtual void op_checkid_hook(const basic_openid_message& inm);
45 virtual void op_id_res_hook(basic_openid_message& oum);
46
47 virtual void checkid_hook(basic_openid_message& om);
48 virtual void id_res_hook(const basic_openid_message& om,
49 const basic_openid_message& sp);
50 virtual void checkid_hook(const basic_openid_message& inm,
51 basic_openid_message& oum);
52
53 /**
54 * Function called after parsing sreg request to set up response
55 * fields. The default implementation tries to send as much fields
56 * as we have. The function is supposed to set the data and
57 * fields_response.
58 * @see fields_response
59 * @param inm incoming openid message
60 * @param oum outgoing openid message
61 */
62 virtual void setup_response(const basic_openid_message& inm,
63 basic_openid_message& oum);
64
65 virtual void setup_response();
66
67 protected:
68 /** Stores attributes to request fetching during checkid_setup. */
69 struct ax_attr_t {
70 std::string uri;
71 std::string alias;
72 bool required;
73 int count;
74 };
75 std::vector<ax_attr_t> attrs;
76 unsigned int alias_count; // auto-incr counter for auto-named aliases
77
78 /** Stores results from fetch response during id_res. */
79 std::map<std::string, std::vector<std::string> > response_attrs;
80 };
81}
82
83#endif /* __OPKELE_SREG_H */
84
diff --git a/include/opkele/oauth_ext.h b/include/opkele/oauth_ext.h
new file mode 100644
index 0000000..37a826b
--- a/dev/null
+++ b/include/opkele/oauth_ext.h
@@ -0,0 +1,62 @@
1#ifndef __OPKELE_OAUTH_EXT_H
2#define __OPKELE_OAUTH_EXT_H
3
4/**
5 * @file
6 * @brief OAuth extension
7 */
8
9#include <opkele/extension.h>
10
11namespace opkele {
12
13 /**
14 * OpenID OAuth extension
15 * http://step2.googlecode.com/svn/spec/openid_oauth_extension/latest/openid_oauth_extension.html
16 */
17 class oauth_ext_t : public extension_t {
18 public:
19 std::string m_consumer, m_scope, m_request_token;
20
21 /**
22 * Consumer constructor.
23 * @param fr required fields
24 * @see fields_required
25 * @param fo optional fields
26 * @see fields_optional
27 * @param pu policy url
28 * @see policy_url
29 */
30 oauth_ext_t(const char *consumer = "", const char *scope = "") : m_consumer(consumer), m_scope(scope) { }
31
32 virtual void rp_checkid_hook(basic_openid_message& om);
33 virtual void rp_id_res_hook(const basic_openid_message& om,
34 const basic_openid_message& sp);
35 virtual void op_checkid_hook(const basic_openid_message& inm);
36 virtual void op_id_res_hook(basic_openid_message& oum);
37
38 virtual void checkid_hook(basic_openid_message& om);
39 virtual void id_res_hook(const basic_openid_message& om,
40 const basic_openid_message& sp);
41 virtual void checkid_hook(const basic_openid_message& inm,
42 basic_openid_message& oum);
43
44 /**
45 * Function called after parsing sreg request to set up response
46 * fields. The default implementation tries to send as much fields
47 * as we have. The function is supposed to set the data and
48 * fields_response.
49 * @see fields_response
50 * @param inm incoming openid message
51 * @param oum outgoing openid message
52 */
53 virtual void setup_response(const basic_openid_message& inm,
54 basic_openid_message& oum);
55
56 virtual void setup_response();
57
58 };
59}
60
61#endif /* __OPKELE_OAUTH_EXT_H */
62
diff --git a/lib/ax.cc b/lib/ax.cc
new file mode 100644
index 0000000..ccdb706
--- a/dev/null
+++ b/lib/ax.cc
@@ -0,0 +1,135 @@
1#include <opkele/exception.h>
2#include <opkele/ax.h>
3#include <opkele/uris.h>
4#include <opkele/util.h>
5
6#include <map>
7#include <string>
8#include <vector>
9
10using namespace std;
11
12namespace opkele {
13
14 void ax_t::add_attribute(const char *uri, bool required, const char *alias /* = NULL */, int count /* = 1 */) {
15 assert(uri && *uri);
16 assert(count != 0);
17
18 ax_attr_t attr;
19 attr.uri = uri;
20 attr.required = required;
21 attr.count = count;
22 // if no alias is specified, generate one using an internal auto-incremented counter
23 attr.alias = alias ? alias : string("attr") + opkele::util::long_to_string(++alias_count);
24
25 attrs.push_back(attr);
26 }
27
28 void ax_t::rp_checkid_hook(basic_openid_message& om) {
29 if (attrs.size() == 0) return; // not asking for any attributes
30
31 string pfx = om.allocate_ns(OIURI_AX10,"ax");
32 om.set_field(pfx+".mode", "fetch_request"); // only supports fetch_request for now
33
34 string required_fields, optional_fields;
35 for (size_t i = 0; i < attrs.size(); i++) {
36 // build up list of required/optional aliases
37 if (attrs[i].required) required_fields += (required_fields.empty() ? "" : ",") + attrs[i].alias;
38 else optional_fields += (optional_fields.empty() ? "" : ",") + attrs[i].alias;
39
40 om.set_field(pfx+".type."+attrs[i].alias, attrs[i].uri);
41
42 // only specify count if it's >1 or unlimited
43 if (attrs[i].count == UNLIMITED_COUNT) {
44 om.set_field(pfx+".count."+attrs[i].alias, "unlimited");
45 } else if (attrs[i].count > 1) {
46 om.set_field(pfx+".count."+attrs[i].alias, opkele::util::long_to_string(attrs[i].count));
47 }
48 }
49
50 if (!required_fields.empty()) om.set_field(pfx+".required", required_fields);
51 if (!optional_fields.empty()) om.set_field(pfx+".if_available", optional_fields);
52
53 if (!update_url.empty()) om.set_field(pfx+".update_url", update_url);
54 }
55
56 void ax_t::checkid_hook(basic_openid_message& om) {
57 rp_checkid_hook(om); }
58
59 void ax_t::rp_id_res_hook(const basic_openid_message& om,
60 const basic_openid_message& sp) {
61 string pfx;
62 try {
63 pfx = om.find_ns(OIURI_AX10,"ax");
64 }catch(failed_lookup&) {
65 return;
66 }
67 pfx += '.';
68
69 // first look at all aliases and generate an internal uri->alias map
70 string fn;
71 map<string, string> aliases;
72 for (basic_openid_message::fields_iterator it = sp.fields_begin(); it != sp.fields_end(); ++it) {
73 fn = *it;
74 string type_pfx = pfx; type_pfx += "type.";
75 size_t pos = fn.find(type_pfx);
76 if (pos == string::npos) continue;
77 string alias = fn.substr(pos + type_pfx.size());
78 aliases[sp.get_field(fn)] = alias;
79 }
80
81 // now for each alias, pull out the count and value(s) and store uri->[value1, ...]
82 for (map<string, string>::iterator it = aliases.begin(); it != aliases.end(); ++it) {
83 vector<string> values;
84 fn = pfx; fn += "count." + it->second;
85 if (sp.has_field(fn)) {
86 int count = opkele::util::string_to_long(sp.get_field(fn));
87 for (int i = 1; i <= count; i++) {
88 fn = pfx; fn += "value." + it->second + "." + opkele::util::long_to_string(i);
89 values.push_back(sp.get_field(fn));
90 }
91 } else {
92 fn = pfx; fn += "value." + it->second;
93 values.push_back(sp.get_field(fn));
94 }
95 response_attrs[it->first] = values;
96 }
97
98 fn = pfx; fn += "update_url";
99 if (sp.has_field(fn)) update_url = sp.get_field(fn);
100 }
101
102 string ax_t::get_attribute(const char *uri, int index /* = 0 */) {
103 if (response_attrs.find(uri) == response_attrs.end()) return "";
104 return response_attrs[uri][index];
105 }
106
107 size_t ax_t::get_attribute_count(const char *uri) {
108 if (response_attrs.find(uri) == response_attrs.end()) return 0;
109 return response_attrs[uri].size();
110 }
111
112 void ax_t::id_res_hook(const basic_openid_message& om,
113 const basic_openid_message& sp) {
114 rp_id_res_hook(om,sp); }
115
116 void ax_t::op_checkid_hook(const basic_openid_message& inm) {
117 }
118
119 void ax_t::op_id_res_hook(basic_openid_message& oum) {
120 }
121
122 void ax_t::checkid_hook(const basic_openid_message& inm,
123 basic_openid_message& oum) {
124 op_checkid_hook(inm);
125 setup_response(inm,oum);
126 op_id_res_hook(oum);
127 }
128
129 void ax_t::setup_response(const basic_openid_message& /* inm */,basic_openid_message& /* oum */) {
130 setup_response();
131 }
132 void ax_t::setup_response() {
133 }
134}
135
diff --git a/lib/oauth_ext.cc b/lib/oauth_ext.cc
new file mode 100644
index 0000000..b728854
--- a/dev/null
+++ b/lib/oauth_ext.cc
@@ -0,0 +1,75 @@
1#include <opkele/exception.h>
2#include <opkele/oauth_ext.h>
3#include <opkele/uris.h>
4#include <algorithm>
5
6namespace opkele {
7 using std::find;
8
9 void oauth_ext_t::rp_checkid_hook(basic_openid_message& om) {
10
11 string pfx = om.allocate_ns(OIURI_OAUTH10,"oauth");
12 //required: openid.oauth.consumer=www.plaxo.com
13 //optional: openid.oauth.scope=http://www.google.com/m8/feeds/
14 if (m_consumer.empty()) throw bad_input(OPKELE_CP_ "Required consumer key is missing from OAuth extension");
15 om.set_field(pfx+".consumer", m_consumer);
16 if (!m_scope.empty()) om.set_field(pfx+".scope", m_scope);
17 }
18
19 void oauth_ext_t::checkid_hook(basic_openid_message& om) {
20 rp_checkid_hook(om); }
21
22 void oauth_ext_t::rp_id_res_hook(const basic_openid_message& om,
23 const basic_openid_message& sp) {
24 string pfx;
25 try {
26 pfx = om.get_ns(OIURI_OAUTH10);
27 }catch(failed_lookup&) {
28 return;
29 }
30 pfx += '.';
31 //required: openid.oauth.request_token=abcdefg
32 //optional: openid.oauth.consumer=www.plaxo.com
33 //optional: openid.oauth.scope=http://www.google.com/m8/feeds/
34 string fn;
35
36 fn = pfx + "request_token";
37 if (sp.has_field(fn)) {
38 m_request_token = sp.get_field(fn);
39 } else throw bad_input(OPKELE_CP_ "Missing required response field: "+fn);
40
41 fn = pfx + "consumer";
42 if (sp.has_field(fn)) {
43 m_consumer = sp.get_field(fn);
44 }
45
46 fn = pfx + "scope";
47 if (sp.has_field(fn)) {
48 m_scope = sp.get_field(fn);
49 }
50 }
51
52 void oauth_ext_t::id_res_hook(const basic_openid_message& om,
53 const basic_openid_message& sp) {
54 rp_id_res_hook(om,sp); }
55
56 void oauth_ext_t::op_checkid_hook(const basic_openid_message& inm) {
57 }
58
59 void oauth_ext_t::op_id_res_hook(basic_openid_message& oum) {
60 }
61
62 void oauth_ext_t::checkid_hook(const basic_openid_message& inm,
63 basic_openid_message& oum) {
64 op_checkid_hook(inm);
65 setup_response(inm,oum);
66 op_id_res_hook(oum);
67 }
68
69 void oauth_ext_t::setup_response(const basic_openid_message& /* inm */,basic_openid_message& /* oum */) {
70 setup_response();
71 }
72 void oauth_ext_t::setup_response() {
73 }
74}
75