summaryrefslogtreecommitdiff
path: root/module/consumer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'module/consumer.cc')
-rw-r--r--module/consumer.cc243
1 files changed, 243 insertions, 0 deletions
diff --git a/module/consumer.cc b/module/consumer.cc
new file mode 100644
index 0000000..8ade43a
--- /dev/null
+++ b/module/consumer.cc
@@ -0,0 +1,243 @@
+
+#include "consumer.h"
+
+using opkele::assoc_t;
+using opkele::association;
+using opkele::endpoint_t;
+using opkele::failed_lookup;
+using opkele::params;
+using opkele::prequeue_RP;
+using opkele::secret_t;
+
+using std::string;
+using std::vector;
+
+class Consumer :
+ public prequeue_RP
+{
+private: // types
+ vector<endpoint_t> endpoints;
+
+public: // interface
+ Consumer(const char *url, singleid_board_t *board)
+ : _url(url), _board(board)
+ { }
+
+public: // overrides
+
+ virtual void begin_queueing() const
+ { _endpoints.clear(); }
+
+ virtual void queue_endpoint(const openid_endpoint_t& oep)
+ { _endpoints.push(oep); }
+
+ virtual void set_normalized_id(const string& nid)
+ { _normalized = nid; }
+
+ virtual const string get_normalized_id() const
+ { return _normalized; }
+
+ virtual const string get_this_url()
+ { return _url; }
+
+ virtual assoc_t store_assoc(const string& server, const string& handle,
+ const string& type, const secret_t& secret,
+ int expires_in);
+
+ virtual assoc_t find_assoc(const string& server);
+
+ virtual assoc_t retrieve_assoc(const string& server, const string& handle);
+
+ virtual assoc_t invalidate_assoc(const string& server, const string& handle);
+
+ virtual void check_nonce(const string& server, const string& nonce);
+
+private: // data
+ singleid_board_t _board;
+ endpoints _endpoints;
+ string _normalized;
+ string _url;
+};
+
+assoc_t
+Consumer::store_assoc(const string& server, const string& handle,
+ const string& type, const secret_t& secret,
+ int expires_in)
+{
+ singleid_assoc_t data;
+ int res;
+
+ data.server = server.c_str();
+ data.handle = handle.c_str();
+ data.type = type.c_str();
+ data.secret = secret.data();
+ data.n_secret = secret.size();
+ data.expires = expires_in;
+
+ {
+ LockShared lock; /* scoped lock */
+ res = singleid_board_store_assoc (_board, &data);
+ }
+
+ if (!res)
+ throw dump_RP("association data was too large to fit in shared storage");
+
+ return assoc_t(new association(server, handle, type, secret, expires_on, false));
+}
+
+assoc_t
+Consumer::find_assoc(const string& server)
+{
+ singleid_assoc_t data = { 0, };
+ association assoc = NULL;
+
+ {
+ LockShared lock;
+ if (singleid_board_find_assoc (_board, server.c_str(), NULL, &data))
+ assoc = new association(data.server, data.handle, data.type,
+ secret_t(data.secret, data.secret + data.n_secret),
+ data.expires, false);
+ }
+
+ if (!assoc)
+ throw failed_lookup("could not find association for server: " + server);
+
+ return assoc_t(assoc);
+}
+
+assoc_t
+Consumer::retrieve_assoc(const string& server, const string& handle)
+{
+ singleid_assoc_t data = { 0, };
+ association assoc = NULL;
+
+ {
+ LockShared lock;
+ if (singleid_board_find_assoc (_board, server.c_str(), handle.c_str(), &data))
+ assoc = new association(data.server, data.handle, data.type,
+ secret_t(data.secret, data.secret + data.n_secret),
+ data.expires, false);
+ }
+
+ if (!assoc)
+ throw failed_lookup("could not retrieve association for server: " + server);
+
+ return assoc_t(assoc);
+}
+
+assoc_t
+Consumer::invalidate_assoc(const string& server, const string& handle)
+{
+ LockShared lock;
+ singleid_board_invalidate_assoc (_board, server.c_str(), handle.c_str());
+}
+
+
+void
+Consumer::check_nonce(const string& server, const string& nonce)
+{
+ LockShared lock;
+ singleid_board_check_nonce (_board, server.c_str(), nonce.c_str());
+}
+
+/* -----------------------------------------------------------------------
+ * AUTHENTICATION
+ */
+
+static void
+filter_openid_params (params_t &params, params_t &extensions)
+{
+ for (params_t::iterator it = params.begin(); it != params.end(); ) {
+ const string& name = it->first;
+ if (name.find ("openid.") == 0) {
+ /* Extension params have at least a second dot */
+ if (name.find ('.', sizeof ("openid.")))
+ extensions.insert(*it);
+
+ /* We erase an increment together, must use post-increment operator */
+ it->erase(it++);
+ } else {
+ /* Did not match, just go to next element */
+ ++it;
+ }
+ }
+}
+
+static void
+start_auth (sid_request_t *req, Consumer &consumer, params_t &params,
+ const string& trust_root, const string &identity)
+{
+ /* Remove all openid params, and stash away extensions */
+ filter_openid_params (params);
+ string return_to = params.append_query (consumer.get_this_url(), "");
+
+ params_t result;
+
+ try {
+ openid_message_t cm;
+ consumer.initiate (identity);
+ result = consumer.checkid_ (cm, opkele::mode_checkid_setup, return_to, trust_root);
+ output = result.append_query (consumer.get_endpoint().uri);
+
+ } catch (failed_xri_resolution &ex) {
+ sid_request_respond (xxx, xxx, xxx);
+ return;
+
+ } catch (failed_discovery &ex) {
+ sid_request_respond (xxx, xxx, xxx);
+ return;
+
+ } catch (bad_input &ex) {
+ sid_request_respond (xxx, xxx, xxx);
+ return;
+
+ } catch (exception &ex) {
+ sid_request_respond (xxx, xxx, xxx);
+ xxx log xxx;
+ return;
+ }
+
+ sid_request_respond (xxx, xxx, xxx);
+}
+
+static void
+complete_auth (sid_request_t *req, Consumer &consumer, params_t &params)
+{
+ try {
+ consumer.id_res(AdaptorFix(params));
+ string identity = consumer.get_claimed_id();
+ sid_request_authenticated (req, identity.c_str());
+ } catch (exception &ex) {
+ sid_request_respond (xxx, xxx, xxx);
+ }
+}
+
+static void
+cancelled_auth (sid_request_t *req, Consumer &consumer, params_t &params)
+{
+ sid_request_respond (xxx, xxx, xxx);
+}
+
+void
+sid_consumer_authenticate(sid_request_t *req, sid_storage_t *store, const char *identity)
+{
+ params_t params;
+
+ assert (req);
+ assert (store);
+
+ const char *qs = sid_request_qs (req);
+ parse_query_string (qs, params);
+
+ const char *url = sid_request_url (req);
+ Consumer consumer(url, store);
+
+ if (params.has_param("openid.assoc_handle"))
+ complete_auth (req, consumer, params);
+ else if (params.has_param("openid.mode") && params.get_param("openid.mode") == "cancel")
+ cancelled_auth (req, consumer, params);
+ else
+ begin_auth (req, consumer, params, trust_root, identity);
+
+ consumer.close();
+}