extending AuthResult

27 views
Skip to first unread message

Bryan Richter

unread,
Feb 2, 2012, 5:23:58 PM2/2/12
to yeso...@googlegroups.com
Hi,

While diving into isAuthorized and Felipe's abstraction thereof, I ran
into a difficulty with Yesod itself. After many false starts, I
finally figured out that just one change would do what I want. That
change is adding a new data constructor to AuthResult:

> data AuthResult url = Authorized | AuthenticationRequired | Unauthorized Text | NeedsAction url Text

This would allow AuthResult to express the notion, "Do this action to
acquire the necessary credentials." It would be handled by
yesodDefaultRunner something like this:

> ar <- isAuthorized (toMasterRoute url) isWrite
> case ar of
> Authorized -> return ()
> ...
> NeedsAction url t -> do
> setMessage $ toHtml t
> setUltDestCurrent
> redirect url

Unfortunately, trying to throw the "url" type variable on to
AuthResult results in type complexity that goes over my head.

Is this a thing that others would want, though?

Michael Snoyman

unread,
Feb 2, 2012, 11:41:08 PM2/2/12
to yeso...@googlegroups.com

Another possibility: since isAuthorized lives in GHandler, you could
technically do the redirect straight from there. Would that work for
you?

Michael

Bryan Richter

unread,
Feb 3, 2012, 1:41:42 AM2/3/12
to yeso...@googlegroups.com
I actually had a separate proposal that used that fact. :) But by
going that route, I found that AuthenticationRequired became
superfluous. That is, why treat these cases differently?

1. user needs authentication? return AuthenticationRequired.
defaultRunner performs 'setultdest >> redirect AuthR'
2. user needs credential foo? do not return anything, but short
circuit with 'setultdest >> redirect getCredFooR'.

In case 1, you could do without AuthenticationRequired and call
'requireAuth' yourself!

Going that route actually adds yet another, somewhat radical
modification of Felipe's proposal. It would look something like:

> isAuthorized route iswrite = runDB $ foldM hasCred Authorized $ requiredCredentials route iswrite
> where
> hasCred Authorized c = hasCredential c
> hasCred badAuth = return badAuth
>
> hasCredential LoggedIn = void requireAuth >> return Authorized
> hasCredential IsAdmin = do
> u <- requireAuth
> return $ if isAdmin u then Authorized else unauthorizedI MsgNotADmin

This is pretty beard-twiddly though. If nobody feels a need for
NeedsAction I think I'll give it a rest.

Michael Snoyman

unread,
Feb 3, 2012, 6:37:35 AM2/3/12
to yeso...@googlegroups.com
You're absolutely right: we could just have the return type of
isAuthorized be () and require user code to correctly call redirect
and family. The reason for this approach is merely convenience.
However, for more complicated requirements (like what you're laying
out), I think it makes more sense to push the complexity into
isAuthorized than to try and have a data type that models everything.

In other words: optimize for the normal case, and make the corner case possible.

Michael

Felipe Almeida Lessa

unread,
Feb 3, 2012, 7:24:08 AM2/3/12
to yeso...@googlegroups.com
On Fri, Feb 3, 2012 at 9:37 AM, Michael Snoyman <mic...@snoyman.com> wrote:
> You're absolutely right: we could just have the return type of
> isAuthorized be () and require user code to correctly call redirect
> and family. The reason for this approach is merely convenience.
> However, for more complicated requirements (like what you're laying
> out), I think it makes more sense to push the complexity into
> isAuthorized than to try and have a data type that models everything.
>
> In other words: optimize for the normal case, and make the corner case possible.

I've linked this thread to the related issue [1]. I think that it
makes sense to rethink AuthResult when biting the bullet on
YesodPermissions (or YesodCredentials).

[1] https://github.com/yesodweb/yesod/issues/236

--
Felipe.

Reply all
Reply to author
Forward
0 new messages