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?
Another possibility: since isAuthorized lives in GHandler, you could
technically do the redirect straight from there. Would that work for
you?
Michael
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.
In other words: optimize for the normal case, and make the corner case possible.
Michael
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.