comparison 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
comparison
equal deleted inserted replaced
12:c778455fe570 13:de04a3fc6b72
28 OpenidFfi.addInput is "openid.ns" "http://specs.openid.net/auth/2.0"; 28 OpenidFfi.addInput is "openid.ns" "http://specs.openid.net/auth/2.0";
29 return is 29 return is
30 30
31 datatype association_type = HMAC_SHA1 | HMAC_SHA256 31 datatype association_type = HMAC_SHA1 | HMAC_SHA256
32 datatype association_session_type = NoEncryption | DH_SHA1 | DH_SHA256 32 datatype association_session_type = NoEncryption | DH_SHA1 | DH_SHA256
33 datatype association_mode =
34 Stateless
35 | Stateful of {AssociationType : association_type,
36 AssociationSessionType : association_session_type}
33 37
34 table associations : { Endpoint : string, Handle : string, Typ : serialized association_type, Key : string, Expires : time } 38 table associations : { Endpoint : string, Handle : string, Typ : serialized association_type, Key : string, Expires : time }
35 PRIMARY KEY Endpoint 39 PRIMARY KEY Endpoint
36 40
37 datatype association = Association of {Handle : string, Typ : association_type, Key : string} 41 datatype association = Association of {Handle : string, Typ : association_type, Key : string}
189 fun eatFragment s = 193 fun eatFragment s =
190 case String.split s #"#" of 194 case String.split s #"#" of
191 Some (s', _) => s' 195 Some (s', _) => s'
192 | _ => s 196 | _ => s
193 197
194 datatype handle_result = HandleOk of {Endpoint : string, Typ : association_type, Key : string} | HandleError of string 198 datatype handle_result = HandleOk of {Endpoint : string, Typ : association_type, Key : string} | NoAssociation of string | HandleError of string
199
200 datatype authentication = AuthenticatedAs of string | Canceled | Failure of string
195 201
196 fun verifyHandle os id = 202 fun verifyHandle os id =
197 id' <- return (eatFragment id); 203 id' <- return (eatFragment id);
198 ep <- discover id'; 204 ep <- discover id';
199 case ep of 205 case ep of
202 case OpenidFfi.getOutput os "openid.assoc_handle" of 208 case OpenidFfi.getOutput os "openid.assoc_handle" of
203 None => return (HandleError "Missing association handle in response") 209 None => return (HandleError "Missing association handle in response")
204 | Some handle => 210 | Some handle =>
205 assoc <- oldAssociation ep; 211 assoc <- oldAssociation ep;
206 case assoc of 212 case assoc of
207 None => return (HandleError "Couldn't find association handle") 213 None => return (NoAssociation ep)
208 | Some assoc => 214 | Some assoc =>
209 if assoc.Handle <> handle then 215 if assoc.Handle <> handle then
210 return (HandleError "Association handles don't match") 216 return (HandleError "Association handles don't match")
211 else 217 else
212 return (HandleOk {Endpoint = ep, Typ = assoc.Typ, Key = assoc.Key}) 218 return (HandleOk {Endpoint = ep, Typ = assoc.Typ, Key = assoc.Key})
219
220 fun verifyStateless os ep id =
221 os' <- OpenidFfi.direct ep (OpenidFfi.remode os "check_authentication");
222 case OpenidFfi.getOutput os' "error" of
223 Some msg => return (Failure ("Failure confirming message contents with OP: " ^ msg))
224 | None =>
225 case OpenidFfi.getOutput os' "is_valid" of
226 Some "true" => return (AuthenticatedAs id)
227 | _ => return (Failure "OP does not confirm message contents")
213 228
214 table nonces : { Endpoint : string, Nonce : string, Expires : time } 229 table nonces : { Endpoint : string, Nonce : string, Expires : time }
215 PRIMARY KEY (Endpoint, Nonce) 230 PRIMARY KEY (Endpoint, Nonce)
216 231
217 fun timeOfNonce s = 232 fun timeOfNonce s =
293 return (Some "Signatures don't match") 308 return (Some "Signatures don't match")
294 end 309 end
295 | Some (left, _) => return (Some ("openid.signed is missing required fields: " ^ show left)) 310 | Some (left, _) => return (Some ("openid.signed is missing required fields: " ^ show left))
296 end 311 end
297 312
298 datatype authentication = AuthenticatedAs of string | Canceled | Failure of string
299
300 fun authenticate after r = 313 fun authenticate after r =
301 let 314 let
302 fun returnTo (qs : option queryString) = 315 fun returnTo (qs : option queryString) =
303 case qs of 316 case qs of
304 None => after (Failure "Empty query string for OpenID callback") 317 None => after (Failure "Empty query string for OpenID callback")
305 | Some qs => 318 | Some qs =>
306 os <- OpenidFfi.indirect qs; 319 os <- OpenidFfi.indirect qs;
307 case OpenidFfi.getOutput os "openid.error" of 320 case OpenidFfi.getOutput os "openid.error" of
308 Some v => after (Failure "Authentication failed: {[v]}") 321 Some v => after (Failure ("Authentication failed: " ^ v))
309 | None => 322 | None =>
310 case OpenidFfi.getOutput os "openid.mode" of 323 case OpenidFfi.getOutput os "openid.mode" of
311 None => after (Failure "No openid.mode in response") 324 None => after (Failure "No openid.mode in response")
312 | Some mode => 325 | Some mode =>
313 case mode of 326 case mode of
314 "cancel" => after Canceled 327 "cancel" => after Canceled
315 | "id_res" => 328 | "id_res" =>
316 (case OpenidFfi.getOutput os "openid.claimed_id" of 329 (case OpenidFfi.getOutput os "openid.claimed_id" of
317 None => after (Failure "Missing identity in OP response") 330 None => after (Failure "Missing identity in OP response")
318 | Some id => 331 | Some id =>
319 errO <- verifyHandle os id; 332 errO <- verifyReturnTo os;
320 case errO of 333 case errO of
321 HandleError s => after (Failure s) 334 Some s => after (Failure s)
322 | HandleOk {Endpoint = ep, Typ = atype, Key = key} => 335 | None =>
323 errO <- verifyReturnTo os; 336 errO <- verifyHandle os id;
324 case errO of 337 case errO of
325 Some s => after (Failure s) 338 HandleError s => after (Failure s)
326 | None => 339 | NoAssociation ep =>
340 r <- verifyStateless os ep id;
341 after r
342 | HandleOk {Endpoint = ep, Typ = atype, Key = key} =>
327 errO <- verifyNonce os ep; 343 errO <- verifyNonce os ep;
328 case errO of 344 case errO of
329 Some s => after (Failure s) 345 Some s => after (Failure s)
330 | None => 346 | None =>
331 errO <- verifySig os atype key; 347 errO <- verifySig os atype key;
345 in 361 in
346 dy <- discover r.Identifier; 362 dy <- discover r.Identifier;
347 case dy of 363 case dy of
348 None => return "Discovery failed" 364 None => return "Discovery failed"
349 | Some dy => 365 | Some dy =>
350 assoc <- association r.AssociationType r.AssociationSessionType dy; 366 case r.Association of
351 case assoc of 367 Stateless =>
352 AssError msg => return ("Association failure: " ^ msg)
353 | AssAlternate _ => return "Association failure: server didn't accept its own alternate association modes"
354 | Association assoc =>
355 redirect (bless (dy ^ "?openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup&openid.claimed_id=" 368 redirect (bless (dy ^ "?openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup&openid.claimed_id="
356 ^ r.Identifier ^ "&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.assoc_handle=" 369 ^ r.Identifier ^ "&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.return_to="
357 ^ assoc.Handle ^ "&openid.return_to=" ^ show (effectfulUrl returnTo))) 370 ^ show (effectfulUrl returnTo)))
371 | Stateful ar =>
372 assoc <- association ar.AssociationType ar.AssociationSessionType dy;
373 case assoc of
374 AssError msg => return ("Association failure: " ^ msg)
375 | AssAlternate _ => return "Association failure: server didn't accept its own alternate association modes"
376 | Association assoc =>
377 redirect (bless (dy ^ "?openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup&openid.claimed_id="
378 ^ r.Identifier ^ "&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.assoc_handle="
379 ^ assoc.Handle ^ "&openid.return_to=" ^ show (effectfulUrl returnTo)))
358 end 380 end
359 381
360 task periodic 1 = fn () => 382 task periodic 1 = fn () =>
361 dml (DELETE FROM discoveries WHERE Expires < CURRENT_TIMESTAMP); 383 dml (DELETE FROM discoveries WHERE Expires < CURRENT_TIMESTAMP);
362 dml (DELETE FROM associations WHERE Expires < CURRENT_TIMESTAMP); 384 dml (DELETE FROM associations WHERE Expires < CURRENT_TIMESTAMP);