diff src/ur/openid.ur @ 13:de04a3fc6b72

Stateless verification worked
author Adam Chlipala <adam@chlipala.net>
date Sun, 02 Jan 2011 10:11:38 -0500
parents c778455fe570
children 6b2a44da71b0
line wrap: on
line diff
--- a/src/ur/openid.ur	Sat Jan 01 14:00:52 2011 -0500
+++ b/src/ur/openid.ur	Sun Jan 02 10:11:38 2011 -0500
@@ -30,6 +30,10 @@
 
 datatype association_type = HMAC_SHA1 | HMAC_SHA256
 datatype association_session_type = NoEncryption | DH_SHA1 | DH_SHA256
+datatype association_mode =
+         Stateless
+       | Stateful of {AssociationType : association_type,
+                      AssociationSessionType : association_session_type}
 
 table associations : { Endpoint : string, Handle : string, Typ : serialized association_type, Key : string, Expires : time }
   PRIMARY KEY Endpoint
@@ -191,7 +195,9 @@
         Some (s', _) => s'
       | _ => s
 
-datatype handle_result = HandleOk of {Endpoint : string, Typ : association_type, Key : string} | HandleError of string
+datatype handle_result = HandleOk of {Endpoint : string, Typ : association_type, Key : string} | NoAssociation of string | HandleError of string
+
+datatype authentication = AuthenticatedAs of string | Canceled | Failure of string
 
 fun verifyHandle os id =
     id' <- return (eatFragment id);
@@ -204,13 +210,22 @@
           | Some handle =>
             assoc <- oldAssociation ep;
             case assoc of
-                None => return (HandleError "Couldn't find association handle")
+                None => return (NoAssociation ep)
               | Some assoc =>
                 if assoc.Handle <> handle then
                     return (HandleError "Association handles don't match")
                 else
                     return (HandleOk {Endpoint = ep, Typ = assoc.Typ, Key = assoc.Key})
 
+fun verifyStateless os ep id =
+    os' <- OpenidFfi.direct ep (OpenidFfi.remode os "check_authentication");
+    case OpenidFfi.getOutput os' "error" of
+        Some msg => return (Failure ("Failure confirming message contents with OP: " ^ msg))
+      | None =>
+        case OpenidFfi.getOutput os' "is_valid" of
+            Some "true" => return (AuthenticatedAs id)
+          | _ => return (Failure "OP does not confirm message contents")
+
 table nonces : { Endpoint : string, Nonce : string, Expires : time }
   PRIMARY KEY (Endpoint, Nonce)
 
@@ -295,8 +310,6 @@
                   | Some (left, _) => return (Some ("openid.signed is missing required fields: " ^ show left))
             end
 
-datatype authentication = AuthenticatedAs of string | Canceled | Failure of string
-
 fun authenticate after r =
     let
         fun returnTo (qs : option queryString) =
@@ -305,7 +318,7 @@
               | Some qs =>
                 os <- OpenidFfi.indirect qs;
                 case OpenidFfi.getOutput os "openid.error" of
-                    Some v => after (Failure "Authentication failed: {[v]}")
+                    Some v => after (Failure ("Authentication failed: " ^ v))
                   | None =>
                     case OpenidFfi.getOutput os "openid.mode" of
                         None => after (Failure "No openid.mode in response")
@@ -316,14 +329,17 @@
                             (case OpenidFfi.getOutput os "openid.claimed_id" of
                                  None => after (Failure "Missing identity in OP response")
                                | Some id =>
-                                 errO <- verifyHandle os id;
+                                 errO <- verifyReturnTo os;
                                  case errO of
-                                     HandleError s => after (Failure s)
-                                   | HandleOk {Endpoint = ep, Typ = atype, Key = key} =>
-                                     errO <- verifyReturnTo os;
+                                     Some s => after (Failure s)
+                                   | None =>
+                                     errO <- verifyHandle os id;
                                      case errO of
-                                         Some s => after (Failure s)
-                                       | None =>
+                                         HandleError s => after (Failure s)
+                                       | NoAssociation ep =>
+                                         r <- verifyStateless os ep id;
+                                         after r
+                                       | HandleOk {Endpoint = ep, Typ = atype, Key = key} =>
                                          errO <- verifyNonce os ep;
                                          case errO of
                                              Some s => after (Failure s)
@@ -347,14 +363,20 @@
         case dy of
             None => return "Discovery failed"
           | Some dy =>
-            assoc <- association r.AssociationType r.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 =>
+            case r.Association of
+                Stateless =>
                 redirect (bless (dy ^ "?openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup&openid.claimed_id="
-                                 ^ r.Identifier ^ "&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.assoc_handle="
-                                 ^ assoc.Handle ^ "&openid.return_to=" ^ show (effectfulUrl returnTo)))
+                                 ^ r.Identifier ^ "&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.return_to="
+                                 ^ show (effectfulUrl returnTo)))
+              | 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&openid.claimed_id="
+                                     ^ r.Identifier ^ "&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.assoc_handle="
+                                     ^ assoc.Handle ^ "&openid.return_to=" ^ show (effectfulUrl returnTo)))
     end
 
 task periodic 1 = fn () =>