Mercurial > openid
comparison src/ur/openid.ur @ 10:194577b60771
Call user-specified function after authentication
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Wed, 29 Dec 2010 14:38:56 -0500 |
parents | 426dd5c88df1 |
children | e637249abfd2 |
comparison
equal
deleted
inserted
replaced
9:426dd5c88df1 | 10:194577b60771 |
---|---|
180 newAssociation url alt.Atype alt.Stype | 180 newAssociation url alt.Atype alt.Stype |
181 | v => return v | 181 | v => return v |
182 | 182 |
183 fun eatFragment s = | 183 fun eatFragment s = |
184 case String.split s #"#" of | 184 case String.split s #"#" of |
185 Some (_, s') => s' | 185 Some (s', _) => s' |
186 | _ => s | 186 | _ => s |
187 | 187 |
188 datatype handle_result = HandleOk of {Endpoint : string, Typ : association_type, Key : string} | HandleError of string | 188 datatype handle_result = HandleOk of {Endpoint : string, Typ : association_type, Key : string} | HandleError of string |
189 | 189 |
190 fun verifyHandle os id = | 190 fun verifyHandle os id = |
191 ep <- discover (eatFragment id); | 191 id' <- return (eatFragment id); |
192 ep <- discover id'; | |
192 case ep of | 193 case ep of |
193 None => return (HandleError "Discovery failed on returned endpoint") | 194 None => return (HandleError ("Discovery failed on returned identifier: " ^ id')) |
194 | Some ep => | 195 | Some ep => |
195 case OpenidFfi.getOutput os "openid.assoc_handle" of | 196 case OpenidFfi.getOutput os "openid.assoc_handle" of |
196 None => return (HandleError "Missing association handle in response") | 197 None => return (HandleError "Missing association handle in response") |
197 | Some handle => | 198 | Some handle => |
198 assoc <- oldAssociation ep; | 199 assoc <- oldAssociation ep; |
286 return (Some "Signatures don't match") | 287 return (Some "Signatures don't match") |
287 end | 288 end |
288 | 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)) |
289 end | 290 end |
290 | 291 |
291 fun returnTo (qs : option queryString) = | 292 datatype authentication = AuthenticatedAs of string | Canceled | Failure of string |
292 case qs of | 293 |
293 None => error <xml>Empty query string for OpenID callback</xml> | 294 fun authenticate after r = |
294 | Some qs => | 295 let |
295 os <- OpenidFfi.indirect qs; | 296 fun returnTo (qs : option queryString) = |
296 case OpenidFfi.getOutput os "openid.error" of | 297 case qs of |
297 Some v => error <xml>Authentication failed: {[v]}</xml> | 298 None => after (Failure "Empty query string for OpenID callback") |
298 | None => | 299 | Some qs => |
299 case OpenidFfi.getOutput os "openid.mode" of | 300 os <- OpenidFfi.indirect qs; |
300 None => error <xml>No <tt>openid.mode</tt> in response ({[qs]})</xml> | 301 case OpenidFfi.getOutput os "openid.error" of |
301 | Some mode => | 302 Some v => after (Failure "Authentication failed: {[v]}") |
302 case mode of | 303 | None => |
303 "cancel" => error <xml>You canceled the authentication!</xml> | 304 case OpenidFfi.getOutput os "openid.mode" of |
304 | "id_res" => | 305 None => after (Failure "No openid.mode in response") |
305 (case OpenidFfi.getOutput os "openid.identity" of | 306 | Some mode => |
306 None => error <xml>Missing identity in OP response</xml> | 307 case mode of |
307 | Some id => | 308 "cancel" => after Canceled |
308 errO <- verifyHandle os id; | 309 | "id_res" => |
309 case errO of | 310 (case OpenidFfi.getOutput os "openid.claimed_id" of |
310 HandleError s => error <xml>{[s]}</xml> | 311 None => after (Failure "Missing identity in OP response") |
311 | HandleOk {Endpoint = ep, Typ = atype, Key = key} => | 312 | Some id => |
312 errO <- verifyReturnTo os; | 313 errO <- verifyHandle os id; |
313 case errO of | |
314 Some s => error <xml>{[s]}</xml> | |
315 | None => | |
316 errO <- verifyNonce os ep; | |
317 case errO of | 314 case errO of |
318 Some s => error <xml>{[s]}</xml> | 315 HandleError s => after (Failure s) |
319 | None => | 316 | HandleOk {Endpoint = ep, Typ = atype, Key = key} => |
320 errO <- verifySig os atype key; | 317 errO <- verifyReturnTo os; |
321 case errO of | 318 case errO of |
322 Some s => error <xml>{[s]}</xml> | 319 Some s => after (Failure s) |
323 | None => return <xml>Identity: {[id]}</xml>) | 320 | None => |
324 | _ => error <xml>Unexpected <tt>openid.mode</tt>: <tt>{[mode]}</tt></xml> | 321 errO <- verifyNonce os ep; |
325 | 322 case errO of |
326 and verifyReturnTo os = | 323 Some s => after (Failure s) |
327 case OpenidFfi.getOutput os "openid.return_to" of | 324 | None => |
328 None => return (Some "Missing return_to in OP response") | 325 errO <- verifySig os atype key; |
329 | Some rt => | 326 case errO of |
330 if rt <> show (effectfulUrl returnTo) then | 327 Some s => after (Failure s) |
331 return (Some "Wrong return_to in OP response") | 328 | None => after (AuthenticatedAs id)) |
332 else | 329 | _ => after (Failure ("Unexpected openid.mode: " ^ mode)) |
333 return None | 330 |
334 | 331 and verifyReturnTo os = |
335 fun authenticate atype stype id = | 332 case OpenidFfi.getOutput os "openid.return_to" of |
336 dy <- discover id; | 333 None => return (Some "Missing return_to in OP response") |
337 case dy of | 334 | Some rt => |
338 None => return "Discovery failed" | 335 if rt <> show (effectfulUrl returnTo) then |
339 | Some dy => | 336 return (Some "Wrong return_to in OP response") |
340 assoc <- association atype stype dy; | 337 else |
341 case assoc of | 338 return None |
342 AssError msg => return ("Association failure: " ^ msg) | 339 in |
343 | AssAlternate _ => return "Association failure: server didn't accept its own alternate association modes" | 340 dy <- discover r.Identifier; |
344 | Association assoc => | 341 case dy of |
345 redirect (bless (dy ^ "?openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup&openid.claimed_id=" | 342 None => return "Discovery failed" |
346 ^ id ^ "&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.assoc_handle=" | 343 | Some dy => |
347 ^ assoc.Handle ^ "&openid.return_to=" ^ show (effectfulUrl returnTo))) | 344 assoc <- association r.AssociationType r.AssociationSessionType dy; |
345 case assoc of | |
346 AssError msg => return ("Association failure: " ^ msg) | |
347 | AssAlternate _ => return "Association failure: server didn't accept its own alternate association modes" | |
348 | Association assoc => | |
349 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=" | |
351 ^ assoc.Handle ^ "&openid.return_to=" ^ show (effectfulUrl returnTo))) | |
352 end | |
348 | 353 |
349 task periodic 1 = fn () => | 354 task periodic 1 = fn () => |
350 dml (DELETE FROM discoveries WHERE Expires < CURRENT_TIMESTAMP); | 355 dml (DELETE FROM discoveries WHERE Expires < CURRENT_TIMESTAMP); |
351 dml (DELETE FROM associations WHERE Expires < CURRENT_TIMESTAMP); | 356 dml (DELETE FROM associations WHERE Expires < CURRENT_TIMESTAMP); |
352 dml (DELETE FROM nonces WHERE Expires < CURRENT_TIMESTAMP) | 357 dml (DELETE FROM nonces WHERE Expires < CURRENT_TIMESTAMP) |