feat(auth): WIP authorization function
This commit is contained in:
parent
2351388826
commit
9b9370fed0
@ -5,7 +5,7 @@
|
||||
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
||||
|
||||
module Auth.OAuth2
|
||||
( OAuthUserException(..)
|
||||
( AzureUserException(..)
|
||||
, oauth2MockServer
|
||||
, mockPluginName
|
||||
) where
|
||||
@ -18,11 +18,12 @@ import Yesod.Auth.OAuth2
|
||||
import Yesod.Auth.OAuth2.Prelude
|
||||
|
||||
|
||||
data OAuthUserException = OAuthUserError
|
||||
| OAuthUserAmbiguous -- TODO
|
||||
data AzureUserException = AzureUserError
|
||||
| AzureUserNoResult
|
||||
| AzureUserAmbiguous -- TODO
|
||||
deriving (Show, Eq, Generic)
|
||||
|
||||
instance Exception OAuthUserException
|
||||
instance Exception AzureUserException
|
||||
|
||||
----------------------------------------
|
||||
---- OAuth2 development auth plugin ----
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
-- SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>
|
||||
-- SPDX-FileCopyrightText: 2023 Gregor Kleen <gregor.kleen@ifi.lmu.de>,David Mosbach <david.mosbach@uniworx.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -6,6 +6,9 @@ module Foundation.Types
|
||||
( UpsertCampusUserMode(..)
|
||||
, _UpsertCampusUserLoginLdap, _UpsertCampusUserLoginDummy, _UpsertCampusUserLoginOther, _UpsertCampusUserLdapSync, _UpsertCampusUserGuessUser
|
||||
, _upsertCampusUserIdent
|
||||
, UpsertAzureUserMode(..)
|
||||
, _UpsertAzureUserLoginOAuth, _UpsertAzureUserLoginDummy, _UpsertAzureUserLoginOther, _UpsertAzureUserOAuthSync, _UpsertAzureUserGuessUser
|
||||
, _upsertAzureUserIdent
|
||||
) where
|
||||
|
||||
import Import.NoFoundation
|
||||
@ -21,3 +24,16 @@ data UpsertCampusUserMode
|
||||
|
||||
makeLenses_ ''UpsertCampusUserMode
|
||||
makePrisms ''UpsertCampusUserMode
|
||||
|
||||
|
||||
-- Azure users logging in via OAuth2
|
||||
data UpsertAzureUserMode
|
||||
= UpsertAzureUserLoginOAuth
|
||||
| UpsertAzureUserLoginDummy { upsertAzureUserIdent :: UserIdent }
|
||||
| UpsertAzureUserLoginOther { upsertAzureUserIdent :: UserIdent }
|
||||
| UpsertAzureUserOAuthSync { upsertAzureUserIdent :: UserIdent }
|
||||
| UpsertAzureUserGuessUser
|
||||
deriving (Eq, Ord, Read, Show, Generic)
|
||||
|
||||
makeLenses_ ''UpsertAzureUserMode
|
||||
makePrisms ''UpsertAzureUserMode
|
||||
|
||||
@ -25,6 +25,7 @@ import Foundation.Authorization (AuthorizationCacheKey(..))
|
||||
|
||||
import Yesod.Auth.Message
|
||||
import Auth.LDAP
|
||||
import Auth.OAuth2
|
||||
import Auth.PWHash (apHash)
|
||||
import Auth.Dummy (apDummy)
|
||||
|
||||
@ -122,22 +123,22 @@ authenticate creds@Creds{..} = liftHandler . runDB . withReaderT projectBackend
|
||||
-> acceptExisting
|
||||
|
||||
|
||||
-- | Authentication via OAuth 2
|
||||
-- | Authentication via AzureADv2 / OAuth 2
|
||||
oAuthenticate :: ( MonadHandler m, HandlerSite m ~ UniWorX
|
||||
, YesodPersist UniWorX, BackendCompatible SqlBackend (YesodPersistBackend UniWorX)
|
||||
, YesodAuth UniWorX, UserId ~ AuthId UniWorX
|
||||
)
|
||||
=> Creds UniWorX -> m (AuthenticationResult UniWorX)
|
||||
oAuthenticate creds@Creds{..} = liftHandler . runDB . withReaderT projectBackend $ do
|
||||
$logErrorS "Auth" $ "\a\27[31m" <> tshow creds <> "\27[0m"
|
||||
$logErrorS "OAuth" $ "\a\27[31m" <> tshow creds <> "\27[0m"
|
||||
now <- liftIO getCurrentTime
|
||||
|
||||
let
|
||||
uAuth = UniqueAuthentication $ CI.mk credsIdent
|
||||
upsertMode = creds ^? _upsertCampusUserMode -- TODO adjust do OAuth
|
||||
upsertMode = creds ^? _upsertAzureUserMode
|
||||
|
||||
isDummy = is (_Just . _UpsertCampusUserLoginDummy) upsertMode
|
||||
isOther = is (_Just . _UpsertCampusUserLoginOther) upsertMode
|
||||
isDummy = is (_Just . _UpsertAzureUserLoginDummy) upsertMode -- mock server
|
||||
isOther = is (_Just . _UpsertAzureUserLoginOther) upsertMode
|
||||
|
||||
excRecovery res
|
||||
| isDummy || isOther
|
||||
@ -152,18 +153,18 @@ oAuthenticate creds@Creds{..} = liftHandler . runDB . withReaderT projectBackend
|
||||
|
||||
excHandlers =
|
||||
[ C.Handler $ \case
|
||||
CampusUserNoResult -> do
|
||||
$logWarnS "LDAP" $ "User lookup failed after successful login for " <> credsIdent
|
||||
AzureUserNoResult -> do
|
||||
$logWarnS "OAuth" $ "User lookup failed after successful login for " <> credsIdent
|
||||
excRecovery . UserError $ IdentifierNotFound credsIdent
|
||||
CampusUserAmbiguous -> do
|
||||
$logWarnS "LDAP" $ "Multiple LDAP results for " <> credsIdent
|
||||
AzureUserAmbiguous -> do
|
||||
$logWarnS "OAuth" $ "Multiple OAuth results for " <> credsIdent
|
||||
excRecovery . UserError $ IdentifierNotFound credsIdent
|
||||
err -> do
|
||||
$logErrorS "LDAP" $ tshow err
|
||||
$logErrorS "OAuth" $ tshow err
|
||||
mr <- getMessageRender
|
||||
excRecovery . ServerError $ mr MsgInternalLdapError
|
||||
, C.Handler $ \(cExc :: CampusUserConversionException) -> do
|
||||
$logErrorS "LDAP" $ tshow cExc
|
||||
excRecovery . ServerError $ mr MsgInternalLdapError -- TODO where does this come from?
|
||||
, C.Handler $ \(cExc :: CampusUserConversionException) -> do -- TODO new exception type or not?
|
||||
$logErrorS "OAuth" $ tshow cExc
|
||||
mr <- getMessageRender
|
||||
excRecovery . ServerError $ mr cExc
|
||||
]
|
||||
@ -181,12 +182,15 @@ oAuthenticate creds@Creds{..} = liftHandler . runDB . withReaderT projectBackend
|
||||
| not isDummy -> res <$ update uid [ UserLastAuthentication =. Just now ]
|
||||
_other -> return res
|
||||
|
||||
$logDebugS "auth" $ tshow Creds{..}
|
||||
pool <- getsYesod $ view _appLdapPool {-(case credsPlugin of
|
||||
"azureadv2" -> getsYesod $ view _appLdapPool -- TODO
|
||||
mockPluginName -> getsYesod $ view _appLdapPool -- TODO
|
||||
_ -> error "undefined" -- TODO
|
||||
)-}
|
||||
$logDebugS "oauth" $ tshow Creds{..}
|
||||
-- TODO look user up in DB
|
||||
-- If not in DB then put (maybe prompt for email)
|
||||
-- If in DB but first time oauth then prompt for password & update entry
|
||||
-- Now user should be in DB -> authenticated
|
||||
flip catches excHandlers $ case upsertMode of
|
||||
Just upsertMode' -> error $ show upsertMode' --TODO
|
||||
Nothing -> error "nothing" --TODO
|
||||
{-pool <- getsYesod $ view _appLdapPool
|
||||
flip catches excHandlers $ case pool of
|
||||
Just ldapPool
|
||||
| Just upsertMode' <- upsertMode -> do
|
||||
@ -194,7 +198,7 @@ oAuthenticate creds@Creds{..} = liftHandler . runDB . withReaderT projectBackend
|
||||
$logDebugS "LDAP" $ "Successful LDAP lookup: " <> tshow ldapData
|
||||
Authenticated . entityKey <$> upsertCampusUser upsertMode' ldapData
|
||||
_other
|
||||
-> acceptExisting
|
||||
-> acceptExisting-}
|
||||
|
||||
|
||||
|
||||
@ -231,6 +235,29 @@ _upsertCampusUserMode mMode cs@Creds{..}
|
||||
|
||||
defaultOther = apHash
|
||||
|
||||
|
||||
_upsertAzureUserMode :: Traversal' (Creds UniWorX) UpsertAzureUserMode
|
||||
_upsertAzureUserMode mMode cs@Creds{..}
|
||||
| credsPlugin == mockPluginName = setMode <$> mMode (UpsertAzureUserLoginDummy $ CI.mk credsIdent)
|
||||
| credsPlugin == "azureadv2" = setMode <$> mMode UpsertAzureUserLoginOAuth
|
||||
| otherwise = setMode <$> mMode (UpsertAzureUserLoginOther $ CI.mk credsIdent)
|
||||
where
|
||||
setMode UpsertAzureUserLoginOAuth
|
||||
= cs{ credsPlugin = "azureadv2" }
|
||||
setMode (UpsertAzureUserLoginDummy ident)
|
||||
= cs{ credsPlugin = mockPluginName
|
||||
, credsIdent = CI.original ident
|
||||
}
|
||||
setMode (UpsertAzureUserLoginOther ident)
|
||||
= cs{ credsPlugin = bool defaultOther credsPlugin (credsPlugin /= mockPluginName && credsPlugin /= "azureadv2")
|
||||
, credsIdent = CI.original ident
|
||||
}
|
||||
setMode _ = cs
|
||||
|
||||
defaultOther = apHash
|
||||
|
||||
|
||||
|
||||
ldapLookupAndUpsert :: forall m. (MonadHandler m, HandlerSite m ~ UniWorX, MonadMask m, MonadUnliftIO m) => Text -> SqlPersistT m (Entity User)
|
||||
ldapLookupAndUpsert ident =
|
||||
getsYesod (view _appLdapPool) >>= \case
|
||||
|
||||
Reference in New Issue
Block a user