servant-auth-token-0.4.4.0: Servant based API and server for token based authorisation

Copyright(c) Anton Gushcha 2016
LicenseMIT
Maintainerncrashed@gmail.com
Stabilityexperimental
PortabilityPortable
Safe HaskellNone
LanguageHaskell2010

Servant.Server.Auth.Token

Contents

Description

The module is server side implementation of Servant.API.Auth.Token API and intended to be used as drop in module for user servers or as external micro service.

Use guardAuthToken to check authorisation headers in endpoints of your server:

-- | Read a single customer from DB
customerGet :: CustomerId -- ^ Customer unique id
  -> MToken' '["customer-read"] -- ^ Required permissions for auth token
  -> ServerM Customer -- ^ Customer data
customerGet i token = do
  guardAuthToken token
  guard404 "customer" $ getCustomer i

Synopsis

Implementation

authServer :: AuthHandler m => ServerT AuthAPI m Source #

Implementation of AuthAPI

Server API

class MonadIO m => HasStorage m where Source #

Abstract storage interface. External libraries can implement this in terms of PostgreSQL or acid-state.

Methods

getUserImpl :: UserImplId -> m (Maybe UserImpl) Source #

Getting user from storage

getUserImplByLogin :: Login -> m (Maybe (WithId UserImplId UserImpl)) Source #

Getting user from storage by login

listUsersPaged :: Page -> PageSize -> m ([WithId UserImplId UserImpl], Word) Source #

Get paged list of users and total count of users

getUserImplPermissions :: UserImplId -> m [WithId UserPermId UserPerm] Source #

Get user permissions, ascending by tag

deleteUserPermissions :: UserImplId -> m () Source #

Delete user permissions

insertUserPerm :: UserPerm -> m UserPermId Source #

Insertion of new user permission

insertUserImpl :: UserImpl -> m UserImplId Source #

Insertion of new user

replaceUserImpl :: UserImplId -> UserImpl -> m () Source #

Replace user with new value

deleteUserImpl :: UserImplId -> m () Source #

Delete user by id

hasPerm :: UserImplId -> Permission -> m Bool Source #

Check whether the user has particular permission

getFirstUserByPerm :: Permission -> m (Maybe (WithId UserImplId UserImpl)) Source #

Get any user with given permission

selectUserImplGroups :: UserImplId -> m [WithId AuthUserGroupUsersId AuthUserGroupUsers] Source #

Select user groups and sort them by ascending name

clearUserImplGroups :: UserImplId -> m () Source #

Remove user from all groups

insertAuthUserGroup :: AuthUserGroup -> m AuthUserGroupId Source #

Add new user group

insertAuthUserGroupUsers :: AuthUserGroupUsers -> m AuthUserGroupUsersId Source #

Add user to given group

insertAuthUserGroupPerms :: AuthUserGroupPerms -> m AuthUserGroupPermsId Source #

Add permission to given group

getAuthUserGroup :: AuthUserGroupId -> m (Maybe AuthUserGroup) Source #

Find user group by id

listAuthUserGroupPermissions :: AuthUserGroupId -> m [WithId AuthUserGroupPermsId AuthUserGroupPerms] Source #

Get list of permissions of given group

listAuthUserGroupUsers :: AuthUserGroupId -> m [WithId AuthUserGroupUsersId AuthUserGroupUsers] Source #

Get list of all users of the group

replaceAuthUserGroup :: AuthUserGroupId -> AuthUserGroup -> m () Source #

Replace record of user group

clearAuthUserGroupUsers :: AuthUserGroupId -> m () Source #

Remove all users from group

clearAuthUserGroupPerms :: AuthUserGroupId -> m () Source #

Remove all permissions from group

deleteAuthUserGroup :: AuthUserGroupId -> m () Source #

Delete user group from storage

listGroupsPaged :: Page -> PageSize -> m ([WithId AuthUserGroupId AuthUserGroup], Word) Source #

Get paged list of user groups with total count

setAuthUserGroupName :: AuthUserGroupId -> Text -> m () Source #

Set group name

setAuthUserGroupParent :: AuthUserGroupId -> Maybe AuthUserGroupId -> m () Source #

Set group parent

insertSingleUseCode :: UserSingleUseCode -> m UserSingleUseCodeId Source #

Add new single use code

setSingleUseCodeUsed :: UserSingleUseCodeId -> Maybe UTCTime -> m () Source #

Set usage time of the single use code

getUnusedCode :: SingleUseCode -> UserImplId -> UTCTime -> m (Maybe (WithId UserSingleUseCodeId UserSingleUseCode)) Source #

Find unused code for the user and expiration time greater than the given time

invalidatePermamentCodes :: UserImplId -> UTCTime -> m () Source #

Invalidate all permament codes for user and set use time for them

selectLastRestoreCode :: UserImplId -> UTCTime -> m (Maybe (WithId UserRestoreId UserRestore)) Source #

Select last valid restoration code by the given current time

insertUserRestore :: UserRestore -> m UserRestoreId Source #

Insert new restore code

findRestoreCode :: UserImplId -> RestoreCode -> UTCTime -> m (Maybe (WithId UserRestoreId UserRestore)) Source #

Find unexpired by the time restore code

replaceRestoreCode :: UserRestoreId -> UserRestore -> m () Source #

Replace restore code with new value

findAuthToken :: UserImplId -> UTCTime -> m (Maybe (WithId AuthTokenId AuthToken)) Source #

Find first non-expired by the time token for user

findAuthTokenByValue :: SimpleToken -> m (Maybe (WithId AuthTokenId AuthToken)) Source #

Find token by value

insertAuthToken :: AuthToken -> m AuthTokenId Source #

Insert new token

replaceAuthToken :: AuthTokenId -> AuthToken -> m () Source #

Replace auth token with new value

type AuthHandler m = (HasAuthConfig m, MonadError ServantErr m, MonadIO m, HasStorage m) Source #

Context that is needed to run the auth server

Helpers

guardAuthToken :: forall perms m. (PermsList perms, AuthHandler m) => MToken perms -> m () Source #

If the token is missing or the user of the token doesn't have needed permissions, throw 401 response

ensureAdmin :: HasStorage m => Int -> Login -> Password -> Email -> m () Source #

Ensures that DB has at leas one admin, if not, creates a new one with specified info.

authUserByToken :: AuthHandler m => MToken '[] -> m UserImplId Source #

Getting user id by token

API methods

authSignin Source #

Arguments

:: AuthHandler m 
=> Maybe Login

Login query parameter

-> Maybe Password

Password query parameter

-> Maybe Seconds

Expire query parameter, how many seconds the token is valid

-> m (OnlyField "token" SimpleToken)

If everything is OK, return token

Implementation of "signin" method

authSigninGetCode Source #

Arguments

:: AuthHandler m 
=> Maybe Login

User login, required

-> m Unit 

Authorisation via code of single usage.

Implementation of AuthSigninGetCodeMethod endpoint.

Logic of authorisation via this method is:

See also: authSigninPostCode

authSigninPostCode Source #

Arguments

:: AuthHandler m 
=> Maybe Login

User login, required

-> Maybe SingleUseCode

Received single usage code, required

-> Maybe Seconds

Time interval after which the token expires, Nothing means some default value

-> m (OnlyField "token" SimpleToken) 

Authorisation via code of single usage.

Logic of authorisation via this method is:

See also: authSigninGetCode

authTouch Source #

Arguments

:: AuthHandler m 
=> Maybe Seconds

Expire query parameter, how many seconds the token should be valid by now. Nothing means default value defined in server config.

-> MToken '[]

Authorisation header with token

-> m Unit 

Implementation of "touch" method

authToken Source #

Arguments

:: AuthHandler m 
=> MToken '[]

Authorisation header with token

-> m RespUserInfo 

Implementation of "token" method, return info about user binded to the token

authSignout Source #

Arguments

:: AuthHandler m 
=> Maybe (Token '[])

Authorisation header with token

-> m Unit 

Implementation of "signout" method

authSignup Source #

Arguments

:: AuthHandler m 
=> ReqRegister

Registration info

-> MToken' '["auth-register"]

Authorisation header with token

-> m (OnlyField "user" UserId) 

Implementation of "signup" method

authUsersInfo Source #

Arguments

:: AuthHandler m 
=> Maybe Page

Page num parameter

-> Maybe PageSize

Page size parameter

-> MToken' '["auth-info"]

Authorisation header with token

-> m RespUsersInfo 

Implementation of get "users" method

authUserInfo Source #

Arguments

:: AuthHandler m 
=> UserId

User id

-> MToken' '["auth-info"]

Authorisation header with token

-> m RespUserInfo 

Implementation of get "user" method

authUserPatch Source #

Arguments

:: AuthHandler m 
=> UserId

User id

-> PatchUser

JSON with fields for patching

-> MToken' '["auth-update"]

Authorisation header with token

-> m Unit 

Implementation of patch "user" method

authUserPut Source #

Arguments

:: AuthHandler m 
=> UserId

User id

-> ReqRegister

New user

-> MToken' '["auth-update"]

Authorisation header with token

-> m Unit 

Implementation of put "user" method

authUserDelete Source #

Arguments

:: AuthHandler m 
=> UserId

User id

-> MToken' '["auth-delete"]

Authorisation header with token

-> m Unit 

Implementation of patch "user" method

authRestore Source #

Arguments

:: AuthHandler m 
=> UserId

User id

-> Maybe RestoreCode 
-> Maybe Password 
-> m Unit 

authGetSingleUseCodes Source #

Arguments

:: AuthHandler m 
=> UserId

Id of user

-> Maybe Word

Number of codes. Nothing means that server generates some default count of codes. And server can define maximum count of codes that user can have at once.

-> MToken' '["auth-single-codes"] 
-> m (OnlyField "codes" [SingleUseCode]) 

Implementation of AuthGetSingleUseCodes endpoint.

authGroupGet Source #

Arguments

:: AuthHandler m 
=> UserGroupId 
-> MToken' '["auth-info"]

Authorisation header with token

-> m UserGroup 

Getting info about user group, requires authInfoPerm for token

authGroupPost Source #

Arguments

:: AuthHandler m 
=> UserGroup 
-> MToken' '["auth-update"]

Authorisation header with token

-> m (OnlyId UserGroupId) 

Inserting new user group, requires authUpdatePerm for token

authGroupPut Source #

Arguments

:: AuthHandler m 
=> UserGroupId 
-> UserGroup 
-> MToken' '["auth-update"]

Authorisation header with token

-> m Unit 

Replace info about given user group, requires authUpdatePerm for token

authGroupPatch Source #

Arguments

:: AuthHandler m 
=> UserGroupId 
-> PatchUserGroup 
-> MToken' '["auth-update"]

Authorisation header with token

-> m Unit 

Patch info about given user group, requires authUpdatePerm for token

authGroupDelete Source #

Arguments

:: AuthHandler m 
=> UserGroupId 
-> MToken' '["auth-delete"]

Authorisation header with token

-> m Unit 

Delete all info about given user group, requires authDeletePerm for token

authGroupList Source #

Arguments

:: AuthHandler m 
=> Maybe Page 
-> Maybe PageSize 
-> MToken' '["auth-info"]

Authorisation header with token

-> m (PagedList UserGroupId UserGroup) 

Get list of user groups, requires authInfoPerm for token

authCheckPermissionsMethod Source #

Arguments

:: AuthHandler m 
=> MToken' '["auth-check"]

Authorisation header with token

-> OnlyField "permissions" [Permission]

Body with permissions to check

-> m Bool

True if all permissions are OK, False if some permissions are not set for token and 401 error if the token doesn't have 'auth-check' permission.

Check that the token has required permissions and return False if it doesn't.

authGetUserIdMethod Source #

Arguments

:: AuthHandler m 
=> MToken' '["auth-userid"]

Authorisation header with token

-> m (OnlyId UserId) 

Get user ID for the owner of the speified token.

authFindUserByLogin Source #

Arguments

:: AuthHandler m 
=> Maybe Login

Login, Nothing will cause 400 error.

-> MToken' '["auth-info"] 
-> m RespUserInfo 

Implementation of AuthFindUserByLogin. Find user by login, throw 404 error if cannot find user by such login.

Low-level API

getAuthToken Source #

Arguments

:: AuthHandler m 
=> UserImplId

User for whom we want token

-> Maybe Seconds

Expiration duration, Nothing means default

-> m SimpleToken

Old token (if it doesn't expire) or new one

Helper to get or generate new token for user

hashPassword :: AuthHandler m => Password -> m Text Source #

Generate hash from given password and return it as text. May be useful if you don't like storing unencrypt passwords in config files.

setUserPasswordHash :: AuthHandler m => Text -> UserId -> m () Source #

Update password hash of user. Can be used to set direct hash for user password when it is taken from config file.

ensureAdminHash :: AuthHandler m => Int -> Login -> Text -> Email -> m () Source #

Ensures that DB has at least one admin, if not, creates a new one with specified info and direct password hash. May be useful if you don't like storing unencrypt passwords in config files.

signinByHashUnsafe Source #

Arguments

:: AuthHandler m 
=> Login

User login

-> Text

Hash of admin password

-> Maybe Seconds

Expire

-> m SimpleToken 

If you use password hash in configs, you cannot use them in signin method. This helper allows to get token by password hash and the function is not available for remote call (no endpoint).

Throws 401 if cannot find user or authorisation is failed.

WARNING: Do not expose the function to end user, never!