changeset 27:f129ddee75f3

Some XRDS fixes; ignore query strings in naming endpoints for association purposes
author Adam Chlipala <adam@chlipala.net>
date Sun, 23 Jan 2011 17:40:42 -0500
parents ee97bc0e08fa
children fcd3a977d77b
files include/openid.h src/c/openid.c src/ur/lib.urp src/ur/openid.ur src/ur/openidFfi.urs src/ur/openidUser.ur
diffstat 6 files changed, 70 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/include/openid.h	Sun Jan 23 14:57:49 2011 -0500
+++ b/include/openid.h	Sun Jan 23 17:40:42 2011 -0500
@@ -20,6 +20,7 @@
 uw_unit uw_OpenidFfi_addInput(uw_context, uw_OpenidFfi_inputs, uw_Basis_string key, uw_Basis_string value);
 
 uw_Basis_string uw_OpenidFfi_getOutput(uw_context, uw_OpenidFfi_outputs, uw_Basis_string key);
+uw_unit uw_OpenidFfi_printOutputs(uw_context, uw_OpenidFfi_outputs);
 
 uw_OpenidFfi_outputs uw_OpenidFfi_direct(uw_context, uw_Basis_string url, uw_OpenidFfi_inputs);
 uw_OpenidFfi_outputs uw_OpenidFfi_indirect(uw_context, uw_Basis_string fields);
--- a/src/c/openid.c	Sun Jan 23 14:57:49 2011 -0500
+++ b/src/c/openid.c	Sun Jan 23 17:40:42 2011 -0500
@@ -77,6 +77,7 @@
   uw_context ctx;
   uw_OpenidFfi_discovery *d;
   xrds_mode mode;
+  int cur_priority, max_priority;
 } endpoint;
 
 static void XMLCALL startElement(void *userData, const XML_Char *name, const XML_Char **atts) {
@@ -105,9 +106,18 @@
       }
     }
   }
-  else if (!strcmp(name, "Service"))
+  else if (!strcmp(name, "Service")) {
+    const XML_Char **attp;
+
+    ep->cur_priority = 0;
+    for (attp = atts; *attp; attp += 2)
+      if (!strcmp(attp[0], "priority")) {
+        ep->cur_priority = atoi(attp[1]);
+        break;
+      }
+
     ep->mode = SERVICE;
-  else if (!strcmp(name, "Type")) {
+  } else if (!strcmp(name, "Type")) {
     if (ep->mode == SERVICE)
       ep->mode = TYPE;
   }
@@ -130,9 +140,12 @@
       ep->mode = MATCHED;
     break;
   case URI:
-    ep->d->endpoint = uw_malloc(ep->ctx, len+1);
-    memcpy(ep->d->endpoint, s, len);
-    ep->d->endpoint[len] = 0;
+    if (ep->cur_priority < ep->max_priority) {
+      ep->d->endpoint = uw_malloc(ep->ctx, len+1);
+      memcpy(ep->d->endpoint, s, len);
+      ep->d->endpoint[len] = 0;
+      ep->max_priority = ep->cur_priority;
+    }
     break;
   default:
     break;
@@ -174,8 +187,9 @@
   CURL *c = curl(ctx);
   curl_discovery_data cd = {};
   uw_OpenidFfi_discovery *dy = uw_malloc(ctx, sizeof(uw_OpenidFfi_discovery));
-  endpoint ep = {ctx, dy, NONE};
+  endpoint ep = {ctx, dy, NONE, 0, INT_MAX};
   CURLcode code;
+  struct curl_slist *headers = NULL;
 
   dy->endpoint = dy->localId = NULL;
 
@@ -200,9 +214,13 @@
   curl_easy_setopt(c, CURLOPT_URL, id);
   curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, write_discovery_data);
   curl_easy_setopt(c, CURLOPT_WRITEDATA, &cd);
+  curl_slist_append(headers, "Accept: application/xrds+xml");
+  uw_push_cleanup(ctx, (void (*)(void *))curl_slist_free_all, headers);
+  curl_easy_setopt(c, CURLOPT_HTTPHEADER, headers);
 
   code = curl_easy_perform(c);
   uw_pop_cleanup(ctx);
+  uw_pop_cleanup(ctx);
 
   if (code || !dy->endpoint)
     return NULL;
@@ -250,6 +268,15 @@
   return NULL;
 }
 
+uw_unit uw_OpenidFfi_printOutputs(uw_context ctx, uw_OpenidFfi_outputs buf) {
+  char *s = buf->start;
+
+  for (; *s; s = strchr(strchr(s, 0)+1, 0)+1)
+    fprintf(stderr, "%s => %s\n", s, strchr(s, 0)+1);
+
+  return uw_unit_v;
+}
+
 static size_t write_buffer_data(void *buffer, size_t size, size_t nmemb, void *userp) {
   uw_buffer *buf = userp;
 
--- a/src/ur/lib.urp	Sun Jan 23 14:57:49 2011 -0500
+++ b/src/ur/lib.urp	Sun Jan 23 17:40:42 2011 -0500
@@ -5,6 +5,7 @@
 effectful OpenidFfi.discover
 effectful OpenidFfi.createInputs
 effectful OpenidFfi.addInput
+effectful OpenidFfi.printOutputs
 effectful OpenidFfi.direct
 effectful OpenidFfi.indirect
 effectful OpenidFfi.generate
--- a/src/ur/openid.ur	Sun Jan 23 14:57:49 2011 -0500
+++ b/src/ur/openid.ur	Sun Jan 23 17:40:42 2011 -0500
@@ -106,7 +106,13 @@
            | _ => Some (AssError ("OP error during association: " ^ v)))
       | None => None
 
+fun eatQstring s =
+    case String.split s #"?" of
+        Some (s', _) => s'
+      | _ => s
+
 fun associateNoEncryption url atype =
+    url <- return (eatQstring url);
     is <- createInputs;
     OpenidFfi.addInput is "openid.mode" "associate";
     OpenidFfi.addInput is "openid.assoc_type" (show atype);
@@ -130,6 +136,7 @@
           | _ => return (AssError "Missing expires_in")
 
 fun associateDh url atype stype =
+    url <- return (eatQstring url);
     dh <- OpenidFfi.generate;
 
     is <- createInputs;
@@ -166,6 +173,7 @@
               | _ => return (AssError "Missing expires_in")
 
 fun oldAssociation url =
+    url <- return (eatQstring url);
     secret <- oneOrNoRows1 (SELECT associations.Handle, associations.Typ, associations.Key
                             FROM associations
                             WHERE associations.Endpoint = {[url]});
@@ -381,22 +389,28 @@
         case dy of
             None => return "Discovery failed"
           | Some dy =>
-            case r.Association of
-                Stateless =>
-                redirect (bless (dy ^ "?openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup"
-                                 ^ "&openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select"
-                                 ^ "&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.assoc_handle="
-                                 ^ "&openid.return_to=" ^ show (effectfulUrl returnTo) ^ realmString))
-              | Stateful ar =>
-                assoc <- association ar.AssociationType ar.AssociationSessionType dy;
-                case assoc of
-                    AssError msg => return ("Association failure: " ^ msg)
-                  | AssAlternate _ => return "Association failure: server didn't accept its own alternate association modes"
-                  | Association assoc =>
-                    redirect (bless (dy ^ "?openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup"
+            let
+                val begin = case String.index dy #"?" of
+                                None => "?"
+                              | Some _ => "&"
+            in
+                case r.Association of
+                    Stateless =>
+                    redirect (bless (dy ^ begin ^ "openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup"
                                      ^ "&openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select"
                                      ^ "&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.assoc_handle="
-                                     ^ assoc.Handle ^ "&openid.return_to=" ^ show (effectfulUrl returnTo) ^ realmString))
+                                     ^ "&openid.return_to=" ^ show (effectfulUrl returnTo) ^ realmString))
+                  | Stateful ar =>
+                    assoc <- association ar.AssociationType ar.AssociationSessionType dy;
+                    case assoc of
+                        AssError msg => return ("Association failure: " ^ msg)
+                      | AssAlternate _ => return "Association failure: server didn't accept its own alternate association modes"
+                      | Association assoc =>
+                        redirect (bless (dy ^ begin ^ "openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup"
+                                         ^ "&openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select"
+                                         ^ "&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.assoc_handle="
+                                         ^ assoc.Handle ^ "&openid.return_to=" ^ show (effectfulUrl returnTo) ^ realmString))
+            end
     end
 
 task periodic 60 = fn () =>
--- a/src/ur/openidFfi.urs	Sun Jan 23 14:57:49 2011 -0500
+++ b/src/ur/openidFfi.urs	Sun Jan 23 17:40:42 2011 -0500
@@ -11,6 +11,7 @@
 
 type outputs
 val getOutput : outputs -> string -> option string
+val printOutputs : outputs -> transaction {}
 
 val direct : string -> inputs -> transaction outputs
 val indirect : queryString -> transaction outputs
--- a/src/ur/openidUser.ur	Sun Jan 23 14:57:49 2011 -0500
+++ b/src/ur/openidUser.ur	Sun Jan 23 17:40:42 2011 -0500
@@ -259,13 +259,13 @@
 
             fun signup after =
                 let
-                    fun fixed cls label url =
+                    fun fixed cls url =
                         let
                             fun doFixedButton () =
                                 doSignup after {Identifier = url}
                         in
                             <xml><form class={provider}>
-                              <submit class={cls} value={label} action={doFixedButton}/>
+                              <submit class={cls} value="" action={doFixedButton}/>
                             </form></xml>
                         end
                 in
@@ -273,10 +273,10 @@
                       <p>This web site uses the <b><a href="http://openid.net/">OpenID</a></b> standard, which lets you log in using your account from one of several popular web sites, without revealing your password to us.</p>
 
                       <p>You may click one of these buttons to choose to use your account from that site:</p>
-                      {fixed aol "AOL" "https://openid.aol.com/"}
-                      {fixed google "Google" "https://www.google.com/accounts/o8/id"}
-                      {fixed myspace "Myspace" "https://www.myspace.com/openid"}
-                      {fixed yahoo "Yahoo!" "https://me.yahoo.com/"}
+                      {fixed aol "https://openid.aol.com/"}
+                      {fixed google "https://www.google.com/accounts/o8/id"}
+                      {fixed myspace "https://www.myspace.com/openid"}
+                      {fixed yahoo "https://me.yahoo.com/"}
 
                       <p>Visitors familiar with the details of OpenID may also enter their own identifiers:</p>
                       <form>