]> code.citadel.org Git - citadel.git/blobdiff - citadel/modules/openid/serv_openid_rp.c
Fetch assoc_handles and use them in checkid_setup requests
[citadel.git] / citadel / modules / openid / serv_openid_rp.c
index 05dbbd6822bbb77178a176002e7178ccc07d938e..f12dddfd18ff9947b1c23915dc56db7c96243376 100644 (file)
 #include "ctdl_module.h"
 
 
+struct associate_handle {
+       char claimed_id[256];
+       char assoc_type[32];
+       time_t expiration_time;
+       char assoc_handle[128];
+       char mac_key[128];
+};
+
+HashList *HL = NULL;           // hash table of assoc_handle
+
 /* 
  * Locate a <link> tag and, given its 'rel=' parameter, return its 'href' parameter
  */
@@ -178,16 +188,84 @@ int fetch_http(char *url, char *target_buf, int maxbytes)
 }
 
 
+#define ASSOCIATE_RESPONSE_SIZE        4096
+
+/*
+ * libcurl callback function for prepare_openid_associate_request()
+ */
+size_t associate_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+       char *response = (char *) stream;
+       int got_bytes = (size * nmemb);
+       int len = strlen(response);
+
+       if ((len + got_bytes + 1) < ASSOCIATE_RESPONSE_SIZE) {
+               memcpy(&response[len], ptr, got_bytes);
+               response[len+got_bytes] = 0;
+       }
+
+       return got_bytes;
+}
+
+
+/*
+ * Process the response from an "associate" request
+ */
+struct associate_handle *process_associate_response(char *claimed_id, char *associate_response)
+{
+       struct associate_handle *h = NULL;
+       char *ptr = associate_response;
+       char thisline[256];
+       char thiskey[256];
+       char thisdata[256];
+
+       h = (struct associate_handle *) malloc(sizeof(struct associate_handle));
+       safestrncpy(h->claimed_id, claimed_id, sizeof h->claimed_id);
+
+       do {
+               ptr = memreadline(ptr, thisline, sizeof thisline);
+               extract_token(thiskey, thisline, 0, ':', sizeof thiskey);
+               extract_token(thisdata, thisline, 1, ':', sizeof thisdata);
+
+               if (!strcasecmp(thiskey, "assoc_type")) {
+                       safestrncpy(h->assoc_type, thisdata, sizeof h->assoc_type);
+               }
+               else if (!strcasecmp(thiskey, "expires_in")) {
+                       h->expiration_time = time(NULL) + atol(thisdata);
+               }
+               else if (!strcasecmp(thiskey, "assoc_handle")) {
+                       safestrncpy(h->assoc_handle, thisdata, sizeof h->assoc_handle);
+               }
+               else if (!strcasecmp(thiskey, "mac_key")) {
+                       safestrncpy(h->mac_key, thisdata, sizeof h->mac_key);
+               }
+
+       } while (*ptr);
+
+       // FIXME add this data structure into a hash table
+
+       // FIXME periodically purge the hash table of expired handles
+
+       return h;
+}
+
+
+
 /*
  * Establish a shared secret with an OpenID Identity Provider by sending
  * an "associate" request.
  */
-void prepare_openid_associate_request(char *openid_server, char *openid_delegate)
+struct associate_handle *prepare_openid_associate_request(
+               char *claimed_id, char *openid_server, char *openid_delegate)
 {
        CURL *curl;
        CURLcode res;
        struct curl_httppost *formpost=NULL;
        struct curl_httppost *lastptr=NULL;
+       char associate_response[ASSOCIATE_RESPONSE_SIZE];
+       struct associate_handle *h = NULL;
+
+       memset(associate_response, 0, ASSOCIATE_RESPONSE_SIZE);
 
        curl_formadd(&formpost,
                        &lastptr,
@@ -208,19 +286,18 @@ void prepare_openid_associate_request(char *openid_server, char *openid_delegate
                curl_easy_setopt(curl, CURLOPT_URL, openid_server);
                curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
                curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
-               //curl_easy_setopt(curl, CURLOPT_WRITEDATA, &fh);
-               //curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fh_callback);
-               //curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errmsg);
+               curl_easy_setopt(curl, CURLOPT_WRITEDATA, associate_response);
+               curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, associate_callback);
                curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
                        
                curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
                res = curl_easy_perform(curl);
-
-               // FIXME not finished
-
+               h = process_associate_response(claimed_id, associate_response);
                curl_easy_cleanup(curl);
        }
        curl_formfree(formpost);
+
+       return h;
 }
 
 
@@ -236,6 +313,7 @@ void cmd_oid1(char *argbuf) {
        char trust_root[1024];
        int i;
        char buf[SIZ];
+       struct associate_handle *h = NULL;
 
        if (CC->logged_in) {
                cprintf("%d Already logged in.\n", ERROR + ALREADY_LOGGED_IN);
@@ -265,17 +343,22 @@ void cmd_oid1(char *argbuf) {
                        safestrncpy(openid_delegate, openid_url, sizeof openid_delegate);
                }
 
-               /* Prepare an "associate" request */
-               prepare_openid_associate_request(openid_server, openid_delegate);
+               /*
+                * Prepare an "associate" request.  This contacts the IdP and fetches
+                * a data structure containing an assoc_handle plus a shared secret.
+                */
+               h = prepare_openid_associate_request(openid_url, openid_server, openid_delegate);
 
-               /* Now we know where to redirect to. */
+               /* Assemble a URL to which the user-agent will be redirected. */
                char redirect_string[4096];
                char escaped_identity[1024];
                char escaped_return_to[1024];
                char escaped_trust_root[1024];
                char escaped_sreg_optional[256];
+               char escaped_assoc_handle[256];
 
                urlesc(escaped_identity, sizeof escaped_identity, openid_delegate);
+               urlesc(escaped_assoc_handle, sizeof escaped_assoc_handle, h->assoc_handle);
                urlesc(escaped_return_to, sizeof escaped_return_to, return_to);
                urlesc(escaped_trust_root, sizeof escaped_trust_root, trust_root);
                urlesc(escaped_sreg_optional, sizeof escaped_sreg_optional,
@@ -284,13 +367,18 @@ void cmd_oid1(char *argbuf) {
                snprintf(redirect_string, sizeof redirect_string,
                        "%s"
                        "?openid.mode=checkid_setup"
-                       "&openid_identity=%s"
+                       "&openid.identity=%s"
+                       "&openid.assoc_handle=%s"
                        "&openid.return_to=%s"
                        "&openid.trust_root=%s"
                        "&openid.sreg.optional=%s"
                        ,
-                       openid_server, escaped_identity, escaped_return_to,
-                       escaped_trust_root, escaped_sreg_optional
+                       openid_server,
+                       escaped_identity,
+                       escaped_assoc_handle,
+                       escaped_return_to,
+                       escaped_trust_root,
+                       escaped_sreg_optional
                );
                cprintf("%d %s\n", CIT_OK, redirect_string);
                return;
@@ -301,17 +389,15 @@ void cmd_oid1(char *argbuf) {
 
 
 
-
-
-/* To insert this module into the server activate the next block by changing the #if 0 to #if 1 */
 CTDL_MODULE_INIT(openid_rp)
 {
        if (!threading)
        {
                curl_global_init(CURL_GLOBAL_ALL);
+               HL = NewHash(1, NULL);
                CtdlRegisterProtoHook(cmd_oid1, "OID1", "Begin OpenID checkid_setup operation");
        }
 
-   /* return our Subversion id for the Log */
-   return "$Id$";
+       /* return our Subversion id for the Log */
+       return "$Id$";
 }