comparison src/ur/openid.ur @ 11:e637249abfd2

Test with RP-side nonces
author Adam Chlipala <adam@chlipala.net>
date Wed, 29 Dec 2010 16:25:32 -0500
parents 194577b60771
children c778455fe570
comparison
equal deleted inserted replaced
10:194577b60771 11:e637249abfd2
1 val discoveryExpiry = 3600 1 val discoveryExpiry = 3600
2 val nonceExpiry = 3600 2 val nonceExpiry = 600
3 val nonceSkew = 3600 3 val nonceSkew = 600
4 4
5 task initialize = fn () => OpenidFfi.init 5 task initialize = fn () => OpenidFfi.init
6 6
7 table discoveries : { Identifier : string, Endpoint : string, Expires : time } 7 table discoveries : { Identifier : string, Endpoint : string, Expires : time }
8 PRIMARY KEY Identifier 8 PRIMARY KEY Identifier
225 | Some tm => 225 | Some tm =>
226 now <- now; 226 now <- now;
227 if tm < addSeconds now (-nonceExpiry) then 227 if tm < addSeconds now (-nonceExpiry) then
228 return (Some "Nonce timestamp is too old") 228 return (Some "Nonce timestamp is too old")
229 else if tm > addSeconds now nonceSkew then 229 else if tm > addSeconds now nonceSkew then
230 return (Some ("Nonce timestamp is too far in the future: " ^ show tm ^ " (from " ^ nonce ^ ")")) 230 return (Some "Nonce timestamp is too far in the future")
231 else 231 else
232 b <- oneRowE1 (SELECT COUNT( * ) > 0 232 b <- oneRowE1 (SELECT COUNT( * ) > 0
233 FROM nonces 233 FROM nonces
234 WHERE nonces.Endpoint = {[ep]} 234 WHERE nonces.Endpoint = {[ep]}
235 AND nonces.Nonce = {[nonce]}); 235 AND nonces.Nonce = {[nonce]});
289 | Some (left, _) => return (Some ("openid.signed is missing required fields: " ^ show left)) 289 | Some (left, _) => return (Some ("openid.signed is missing required fields: " ^ show left))
290 end 290 end
291 291
292 datatype authentication = AuthenticatedAs of string | Canceled | Failure of string 292 datatype authentication = AuthenticatedAs of string | Canceled | Failure of string
293 293
294 sequence nextNonce
295
294 fun authenticate after r = 296 fun authenticate after r =
295 let 297 let
296 fun returnTo (qs : option queryString) = 298 fun returnTo myNonce (qs : option queryString) =
297 case qs of 299 case qs of
298 None => after (Failure "Empty query string for OpenID callback") 300 None => after (Failure "Empty query string for OpenID callback")
299 | Some qs => 301 | Some qs =>
300 os <- OpenidFfi.indirect qs; 302 os <- OpenidFfi.indirect qs;
301 case OpenidFfi.getOutput os "openid.error" of 303 case OpenidFfi.getOutput os "openid.error" of
312 | Some id => 314 | Some id =>
313 errO <- verifyHandle os id; 315 errO <- verifyHandle os id;
314 case errO of 316 case errO of
315 HandleError s => after (Failure s) 317 HandleError s => after (Failure s)
316 | HandleOk {Endpoint = ep, Typ = atype, Key = key} => 318 | HandleOk {Endpoint = ep, Typ = atype, Key = key} =>
317 errO <- verifyReturnTo os; 319 errO <- verifyReturnTo os myNonce;
318 case errO of 320 case errO of
319 Some s => after (Failure s) 321 Some s => after (Failure s)
320 | None => 322 | None =>
321 errO <- verifyNonce os ep; 323 errO <- verifyNonce os ep;
322 case errO of 324 case errO of
326 case errO of 328 case errO of
327 Some s => after (Failure s) 329 Some s => after (Failure s)
328 | None => after (AuthenticatedAs id)) 330 | None => after (AuthenticatedAs id))
329 | _ => after (Failure ("Unexpected openid.mode: " ^ mode)) 331 | _ => after (Failure ("Unexpected openid.mode: " ^ mode))
330 332
331 and verifyReturnTo os = 333 and verifyReturnTo os myNonce =
332 case OpenidFfi.getOutput os "openid.return_to" of 334 case OpenidFfi.getOutput os "openid.return_to" of
333 None => return (Some "Missing return_to in OP response") 335 None => return (Some "Missing return_to in OP response")
334 | Some rt => 336 | Some rt =>
335 if rt <> show (effectfulUrl returnTo) then 337 if rt <> show (effectfulUrl (returnTo myNonce)) then
336 return (Some "Wrong return_to in OP response") 338 return (Some "Wrong return_to in OP response")
337 else 339 else
338 return None 340 return None
339 in 341 in
340 dy <- discover r.Identifier; 342 dy <- discover r.Identifier;
344 assoc <- association r.AssociationType r.AssociationSessionType dy; 346 assoc <- association r.AssociationType r.AssociationSessionType dy;
345 case assoc of 347 case assoc of
346 AssError msg => return ("Association failure: " ^ msg) 348 AssError msg => return ("Association failure: " ^ msg)
347 | AssAlternate _ => return "Association failure: server didn't accept its own alternate association modes" 349 | AssAlternate _ => return "Association failure: server didn't accept its own alternate association modes"
348 | Association assoc => 350 | Association assoc =>
351 myNonce <- nextval nextNonce;
349 redirect (bless (dy ^ "?openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup&openid.claimed_id=" 352 redirect (bless (dy ^ "?openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup&openid.claimed_id="
350 ^ r.Identifier ^ "&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.assoc_handle=" 353 ^ r.Identifier ^ "&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.assoc_handle="
351 ^ assoc.Handle ^ "&openid.return_to=" ^ show (effectfulUrl returnTo))) 354 ^ assoc.Handle ^ "&openid.return_to=" ^ show (effectfulUrl (returnTo myNonce))))
352 end 355 end
353 356
354 task periodic 1 = fn () => 357 task periodic 1 = fn () =>
355 dml (DELETE FROM discoveries WHERE Expires < CURRENT_TIMESTAMP); 358 dml (DELETE FROM discoveries WHERE Expires < CURRENT_TIMESTAMP);
356 dml (DELETE FROM associations WHERE Expires < CURRENT_TIMESTAMP); 359 dml (DELETE FROM associations WHERE Expires < CURRENT_TIMESTAMP);