Mercurial > openid
view src/ur/openidUser.ur @ 16:9851bc87b0d7
Beginning of OpenidUser
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Thu, 06 Jan 2011 12:48:13 -0500 |
parents | |
children | df2eb629f21a |
line wrap: on
line source
functor Make(M: sig con cols :: {Type} constraint [Id] ~ cols val sessionLifetime : int val afterLogout : url val secureCookies : bool val association : Openid.association_mode val realm : option string end) = struct type user = string val show_user = _ val inj_user = _ table user : ([Id = user] ++ M.cols) PRIMARY KEY Id table identity : {User : user, Identifier : string} PRIMARY KEY (User, Identifier) sequence sessionIds table session : {Id : int, Key : int, Identifier : option string, Expires : time} PRIMARY KEY Id cookie signingUp : {Session : int, Key : int} cookie login : {User : user, Session : int, Key : int} val current = login <- getCookie login; case login of None => return None | Some login => ident <- oneOrNoRowsE1 (SELECT (session.Identifier) FROM session WHERE session.Id = {[login.Session]} AND session.Key = {[login.Key]}); case ident of None => error <xml>Invalid or expired session</xml> | Some None => return None | Some (Some ident) => valid <- oneRowE1 (SELECT COUNT( * ) > 0 FROM identity WHERE identity.User = {[login.User]} AND identity.Identifier = {[ident]}); if valid then return (Some login.User) else error <xml>Session not authorized to act as user</xml> fun main wrap = let fun logout () = clearCookie login; redirect M.afterLogout fun opCallback after ses res = case res of Openid.Canceled => error <xml>You canceled the login process.</xml> | Openid.Failure s => error <xml>Login failed: {[s]}</xml> | Openid.AuthenticatedAs ident => signup <- getCookie signingUp; case signup of Some signup => if signup.Session <> ses then error <xml>Session has changed suspiciously</xml> else invalid <- oneRowE1 (SELECT COUNT( * ) = 0 FROM session WHERE session.Id = {[signup.Session]} AND session.Key = {[signup.Key]}); if invalid then error <xml>Invalid or expired session</xml> else return <xml>I now believe that you are {[ident]}.</xml> | None => login <- getCookie login; case login of None => error <xml>Missing session cookie</xml> | Some login => if login.Session <> ses then error <xml>Session has changed suspiciously</xml> else invalid <- oneRowE1 (SELECT COUNT( * ) = 0 FROM session WHERE session.Id = {[login.Session]} AND session.Key = {[login.Key]}); if invalid then error <xml>Invalid or expired session</xml> else dml (UPDATE session SET Identifier = {[Some ident]} WHERE Key = {[login.Key]}); redirect (bless after) fun newSession () = ses <- nextval sessionIds; now <- now; key <- rand; dml (INSERT INTO session (Id, Key, Identifier, Expires) VALUES ({[ses]}, {[key]}, NULL, {[addSeconds now M.sessionLifetime]})); return {Session = ses, Key = key} fun logon r = ident <- oneOrNoRowsE1 (SELECT (identity.Identifier) FROM identity WHERE identity.User = {[r.User]} LIMIT 1); case ident of None => error <xml>Username not found</xml> | Some ident => ses <- newSession (); setCookie login {Value = r ++ ses, Expires = None, Secure = M.secureCookies}; after <- currentUrl; after <- return (show after); ses <- return ses.Session; msg <- Openid.authenticate (opCallback after ses) {Association = M.association, Realm = M.realm, Identifier = ident}; error <xml>Login with your identity provider failed: {[msg]}</xml> fun doSignup after r = ses <- newSession (); setCookie signingUp {Value = ses, Expires = None, Secure = M.secureCookies}; ses <- return ses.Session; msg <- Openid.authenticate (opCallback after ses) {Association = M.association, Realm = M.realm, Identifier = r.Identifier}; error <xml>Login with your identity provider failed: {[msg]}</xml> fun signup () = after <- currentUrl; wrap "Account Signup" <xml> <form> OpenID Identifier: <textbox{#Identifier}/><br/> <submit value="Sign Up" action={doSignup (show after)}/> </form> </xml> in cur <- current; case cur of Some cur => return <xml>Logged in as {[cur]}. <a link={logout ()}>[Log out]</a></xml> | None => return <xml> <form><textbox{#User}/> <submit value="Log In" action={logon}/></form> <a link={signup ()}>Sign up</a> </xml> end task periodic 60 = fn () => dml (DELETE FROM session WHERE Expires >= CURRENT_TIMESTAMP) end