chore(model)!: separate user authentication data from User table; add ExternalAuth and InternalAuth models

This commit is contained in:
Sarah Vaupel 2024-02-11 17:36:57 +01:00
parent 2e47df00b9
commit 54f2430b3e
2 changed files with 54 additions and 51 deletions

View File

@ -13,13 +13,11 @@
--
User json -- Each Uni2work user has a corresponding row in this table; created upon first login.
ident UserIdent -- Case-insensitive user-identifier
surname UserSurname -- Display user names always through 'nameWidget displayName surname'
displayName UserDisplayName
displayEmail UserEmail
email UserEmail -- Case-insensitive eMail address, used for sending TODO: make this nullable
ident UserIdent -- Case-insensitive user-identifier
authentication AuthenticationMode -- 'AuthLDAP' or ('AuthPWHash'+password-hash) -- TODO: redo (add InternalUser table for password hash)
lastAuthentication UTCTime Maybe -- last login date
created UTCTime default=now()
tokensIssuedAfter UTCTime Maybe -- do not accept bearer tokens issued before this time (accept all tokens if null)
matrikelnummer UserMatriculation Maybe -- usually a number; AVS Personalnummer; nicht Fraport Personalnummer!
@ -49,18 +47,33 @@ User json -- Each Uni2work user has a corresponding row in this table; create
prefersPostal Bool default=false -- user prefers letters by post instead of email
examOfficeGetSynced Bool default=true -- whether synced status should be displayed for exam results by default
examOfficeGetLabels Bool default=true -- whether labels should be displayed for exam results by default
UniqueAuthentication ident -- Column 'ident' can be used as a row-key in this table
UniqueUser ident -- Column 'ident' can be used as a row-key in this table
UniqueEmail email -- Column 'email' can be used as a row-key in this table
deriving Show Eq Ord Generic -- Haskell-specific settings for runtime-value representing a row in memory
-- User authentication data fetched from external sources
ExternalUser
source Text -- External source ID
ident UserIdent -- External user ID
data Value "default='{}'::jsonb" -- Raw user data from external source
lastSourceSync UTCTime -- When was the entry last synced with the external source?
lastUserSync UTCTime Maybe -- When was the corresponding User entry last synced with this entry? TODO: maybe move to User instead
UniqueExternalUser source ident
-- | User authentication data, source-agnostic data
UserAuth
ident UserIdent -- Human-readable text uniquely identifying a user
lastLogin UTCTime -- When did the corresponding User last authenticate using this entry?
Primary ident
UniqueAuthentication ident
deriving Show Eq Ord Generic
-- | User authentication data fetched from external user sources
ExternalAuth
ident UserIdent
source AuthenticationSourceIdent -- Identifier of the external source in the config
data Value "default='{}'::jsonb" -- Raw user data from external source
lastSync UTCTime -- When was the corresponding User entry last synced with this external source?
UniqueExternalAuth ident source -- At most one entry of this user per source
deriving Show Eq Ord Generic
-- | FraDrive-specific user authentication data, internal logins have precedence over external authentication
InternalAuth
ident UserIdent
hash Text -- Hashed password
Primary ident
UniqueInternalAuth ident
deriving Show Eq Ord Generic
UserFunction -- Administratively assigned functions (lecturer, admin, evaluation, ...)

View File

@ -15,61 +15,51 @@ module Model.Types.Auth
import ClassyPrelude.Yesod hiding (derivePersistFieldJSON, Proxy(..))
import Utils
import Data.Aeson
import Data.Aeson.TH
import Model.Types.TH.JSON
import Data.Universe
import Data.Universe.Instances.Reverse ()
import Data.Proxy
import Data.Data (Data)
import Model.Types.TH.PathPiece
import Utils
import Utils.Lens.TH
import Control.Lens
import qualified Data.Set as Set
import qualified Data.Text as Text
import qualified Data.HashMap.Strict as HashMap
import Data.Aeson
import Data.Aeson.TH
import qualified Data.Aeson.Types as Aeson
import Data.CaseInsensitive (CI)
import qualified Data.Binary as Binary
import Data.Binary (Binary)
import Data.Binary.Instances.UnorderedContainers ()
import qualified Data.CaseInsensitive as CI
import Data.CaseInsensitive (CI)
import Data.CaseInsensitive.Instances ()
import Data.Set.Instances ()
import Data.Data (Data)
import qualified Data.HashMap.Strict as HashMap
import Data.NonNull.Instances ()
import Data.Proxy
import qualified Data.Set as Set
import Data.Set.Instances ()
import qualified Data.Text as Text
import Data.Universe
import Data.Universe.Instances.Reverse ()
import Data.Universe.Instances.Reverse.MonoTraversable ()
import Model.Types.TH.PathPiece
import Database.Persist.Sql
import Servant.Docs (ToSample(..), samples)
import Utils.Lens.TH
import Data.Binary (Binary)
import qualified Data.Binary as Binary
import Data.Binary.Instances.UnorderedContainers ()
data AuthenticationMode = AuthLDAP
| AuthAzure
| AuthPWHash { authPWHash :: Text }
| AuthNoLogin
deriving (Eq, Ord, Read, Show, Generic)
-- | Supported protocols for external user sources used for authentication queries
data AuthenticationProtocol
= AuthAzure -- ^ Azure ADv2 (OAuth2)
| AuthLdap -- ^ LDAP
deriving (Eq, Ord, Enum, Bounded, Read, Show, Data, Generic)
deriving anyclass (Universe, Finite, Hashable, NFData)
instance Hashable AuthenticationMode
instance NFData AuthenticationMode
nullaryPathPiece ''AuthenticationProtocol $ camelToPathPiece' 1
pathPieceJSON ''AuthenticationProtocol
deriveJSON defaultOptions
{ constructorTagModifier = camelToPathPiece' 1
, fieldLabelModifier = camelToPathPiece' 1
, sumEncoding = UntaggedValue
} ''AuthenticationMode
derivePersistFieldJSON ''AuthenticationMode
type AuthenticationSourceIdent = Text
data AuthTag -- sortiert nach gewünschter Reihenfolge auf /authpreds, d.h. Prädikate sind sortier nach Relevanz für Benutzer
@ -106,8 +96,8 @@ data AuthTag -- sortiert nach gewünschter Reihenfolge auf /authpreds, d.h. Prä
| AuthRegisterGroup
| AuthEmpty
| AuthSelf
| AuthIsLDAP
| AuthIsPWHash
| AuthIsExternal -- TODO: maybe distinguish between AuthenticationProtocols
| AuthIsInternal
| AuthAuthentication
| AuthNoEscalation
| AuthRead