#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 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 ¶ms, 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 ¶ms, 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 ¶ms) { 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 ¶ms) { 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(); }