Copyright | (c) 2016 Al Zohali |
---|---|
License | BSD3 |
Maintainer | Al Zohali <zohl@fmap.me> |
Stability | experimental |
Safe Haskell | None |
Language | Haskell2010 |
Description
Authentication via encrypted client-side cookies, inspired by client-session library by Michael Snoyman and based on ideas of the paper "A Secure Cookie Protocol" by Alex Liu et al.
- type CipherAlgorithm c = c -> IV c -> ByteString -> ByteString
- type family AuthCookieData
- data AuthCookieException
- type AuthCookieExceptionHandler m = forall a. AuthCookieException -> m (Maybe (ExtendedPayloadWrapper a))
- type AuthCookieHandler a = forall k. ServerKeySet k => AuthCookieSettings -> k -> AuthHandler Request (ExtendedPayloadWrapper a)
- data PayloadWrapper a = PayloadWrapper {}
- data ExtendedPayloadWrapper a = ExtendedPayloadWrapper {
- epwSession :: a
- epwSettings :: SessionSettings
- epwExpiration :: UTCTime
- epwRenew :: Bool
- type Cookied a = Headers '[Header "Set-Cookie" EncryptedSession] a
- type CookiedWrapper c = forall f r. CookiedWrapperClass f r c => f -> r
- class CookiedWrapperClass f r c where
- cookied :: (ServerKeySet k, Serialize c) => AuthCookieSettings -> RandomSource -> k -> Proxy c -> CookiedWrapper c
- data RandomSource
- mkRandomSource :: (MonadIO m, DRG d) => IO d -> Int -> m RandomSource
- getRandomBytes :: MonadIO m => RandomSource -> Int -> m ByteString
- generateRandomBytes :: Int -> IO ByteString
- type ServerKey = ByteString
- class ServerKeySet k where
- data PersistentServerKey
- mkPersistentServerKey :: ByteString -> PersistentServerKey
- data RenewableKeySet s p
- data RenewableKeySetHooks s p = RenewableKeySetHooks {
- rkshNewState :: forall m. (MonadIO m, MonadThrow m) => p -> ([ServerKey], s) -> m ([ServerKey], s)
- rkshNeedUpdate :: forall m. (MonadIO m, MonadThrow m) => p -> ([ServerKey], s) -> m Bool
- rkshRemoveKey :: forall m. (MonadIO m, MonadThrow m) => p -> ServerKey -> m ()
- mkRenewableKeySet :: MonadIO m => RenewableKeySetHooks s p -> p -> s -> m (RenewableKeySet s p)
- data AuthCookieSettings where
- AuthCookieSettings :: (HashAlgorithm h, BlockCipher c) => {..} -> AuthCookieSettings
- data SessionSettings = SessionSettings {}
- data ExpirationType
- newtype EncryptedSession = EncryptedSession ByteString
- emptyEncryptedSession :: EncryptedSession
- encryptSession :: (MonadIO m, MonadThrow m, Serialize a, ServerKeySet k) => AuthCookieSettings -> RandomSource -> k -> SessionSettings -> a -> m (Tagged SerializedEncryptedCookie ByteString)
- decryptSession :: (MonadIO m, MonadThrow m, ServerKeySet k, Serialize a) => AuthCookieSettings -> k -> Tagged SerializedEncryptedCookie ByteString -> m (ExtendedPayloadWrapper a)
- addSession :: AddHeader (e :: Symbol) EncryptedSession r s => AddSession r s
- removeSession :: AddHeader (e :: Symbol) EncryptedSession r s => RemoveSession r s
- addSessionToErr :: AddSession ServantErr ServantErr
- removeSessionFromErr :: RemoveSession ServantErr ServantErr
- getSession :: (MonadIO m, MonadThrow m, Serialize a, ServerKeySet k) => AuthCookieSettings -> k -> Request -> m (Maybe (ExtendedPayloadWrapper a))
- getHeaderSession :: (MonadIO m, MonadThrow m, Serialize a, ServerKeySet k) => AuthCookieSettings -> k -> Text -> m (Maybe (ExtendedPayloadWrapper a))
- defaultAuthHandler :: Serialize a => AuthCookieHandler a
- data Cookie = Cookie {}
- data SerializedEncryptedCookie
- data EncryptedCookie
- data IVBytes
- data PayloadBytes
- data PaddingBytes
- data MACBytes
- base64Encode :: Tagged EncryptedCookie ByteString -> Tagged SerializedEncryptedCookie ByteString
- base64Decode :: MonadThrow m => Tagged SerializedEncryptedCookie ByteString -> m (Tagged EncryptedCookie ByteString)
- cerealEncode :: Serialize a => a -> Tagged b ByteString
- cerealDecode :: (Serialize a, MonadThrow m) => Tagged b ByteString -> m a
- renderSession :: AddSession () ByteString
- parseSessionRequest :: AuthCookieSettings -> RequestHeaders -> Maybe (Tagged SerializedEncryptedCookie ByteString)
- parseSessionResponse :: AuthCookieSettings -> ResponseHeaders -> Maybe (Tagged SerializedEncryptedCookie ByteString)
- unProxy :: Proxy a -> a
- mkCookieKey :: (MonadThrow m, HashAlgorithm h, BlockCipher c) => Proxy c -> Proxy h -> Tagged ServerKeyBytes ByteString -> Tagged IVBytes ByteString -> m (Tagged CookieKeyBytes ByteString)
- mkPadding :: (MonadIO m, BlockCipher c) => RandomSource -> Proxy c -> Tagged PayloadBytes ByteString -> m (Tagged PaddingBytes ByteString)
- mkMAC :: HashAlgorithm h => Proxy h -> Tagged ServerKeyBytes ByteString -> Cookie -> Tagged MACBytes ByteString
- applyCipherAlgorithm :: forall c m. (BlockCipher c, MonadThrow m) => CipherAlgorithm c -> Tagged IVBytes ByteString -> Tagged CookieKeyBytes ByteString -> Tagged PayloadBytes ByteString -> m (Tagged PayloadBytes ByteString)
Documentation
type CipherAlgorithm c = c -> IV c -> ByteString -> ByteString Source #
A type for encryption and decryption functions operating on ByteString
s.
type family AuthCookieData Source #
A type family that maps user-defined data to AuthServerData
.
data AuthCookieException Source #
The exception is thrown when something goes wrong with this package.
CannotMakeIV ByteString | Could not make |
BadProperKey CryptoError | Could not initialize a cipher context. |
TooShortProperKey Int Int | The key is too short for current cipher algorithm. Arguments of this constructor: minimal key length, actual key length. |
IncorrectMAC ByteString | Thrown when Message Authentication Code (MAC) is not correct. |
CookieExpired UTCTime UTCTime | Thrown when |
SessionDeserializationFailed String | This is thrown when |
type AuthCookieExceptionHandler m = forall a. AuthCookieException -> m (Maybe (ExtendedPayloadWrapper a)) Source #
Type for exception handler.
type AuthCookieHandler a Source #
= ServerKeySet k | |
=> AuthCookieSettings | Options, see |
-> k | Instance of |
-> AuthHandler Request (ExtendedPayloadWrapper a) | The result |
Type for cookied handler.
data PayloadWrapper a Source #
Wrapper for session value that goes into cookies' payload.
Generic (PayloadWrapper a) Source # | |
Serialize a => Serialize (PayloadWrapper a) Source # | |
type Rep (PayloadWrapper a) Source # | |
data ExtendedPayloadWrapper a Source #
Wrapper for session value with metadata that doesn't go into payload.
ExtendedPayloadWrapper | |
|
(Serialize c, CookiedWrapperClass b b' c) => CookiedWrapperClass (c -> b) (ExtendedPayloadWrapper c -> b') c Source # | |
type Cookied a = Headers '[Header "Set-Cookie" EncryptedSession] a Source #
Helper type to wrap endpoints.
type CookiedWrapper c = forall f r. CookiedWrapperClass f r c => f -> r Source #
Type for curried cookied
function (with fixed settings, random
source, keyset and session type).
class CookiedWrapperClass f r c where Source #
Class of functions that can be wrapped with cookied
.
:: ServerKeySet k | |
=> (AuthCookieSettings, RandomSource, k, Proxy c) | Environment |
-> Maybe (PayloadWrapper c) | Session value (if found) |
-> f | Tail of function to process |
-> r | Wrapped function |
(Serialize c, MonadIO m, MonadThrow m) => CookiedWrapperClass (m b) (m (Cookied b)) c Source # | |
(Serialize c, CookiedWrapperClass b b' c) => CookiedWrapperClass (a -> b) (a -> b') c Source # | |
(Serialize c, CookiedWrapperClass b b' c) => CookiedWrapperClass (c -> b) (ExtendedPayloadWrapper c -> b') c Source # | |
:: (ServerKeySet k, Serialize c) | |
=> AuthCookieSettings | Options, see |
-> RandomSource | Random source to use |
-> k | Instance of |
-> Proxy c | Type of session |
-> CookiedWrapper c | Wrapper that transforms given functions. |
Wrapper for endpoints that use cookies. It transforms function of type: >>> q1 -> q2 -> ... -> Session -> ... -> qN -> Handler r into >>> q1 -> q2 -> ... -> ExtendedPayloadWrapper Session -> ... qN -> Handler (Cookied r)
Non-session variables number can be arbitrary. It supposed to be
used in tandem with Cookied
type.
Using this wrapper requires FlexibleContexts extention to be turned
on. In case of curring cookied
function, it's highly recommended
to provide signature for this (see CookiedWrapper
).
data RandomSource Source #
A wrapper of self-resetting DRG
suitable for concurrent usage.
:: (MonadIO m, DRG d) | |
=> IO d | How to get deterministic random generator |
-> Int | Threshold (number of bytes to be generated before resetting) |
-> m RandomSource | New |
Constructor for RandomSource
value.
:: MonadIO m | |
=> RandomSource | The source of random numbers |
-> Int | How many random bytes to generate |
-> m ByteString | The generated bytes in form of a |
Extract pseudo-random bytes from RandomSource
.
generateRandomBytes :: Int -> IO ByteString Source #
Generates random sequence of bytes from new DRG
type ServerKey = ByteString Source #
Internal representation of a server key.
class ServerKeySet k where Source #
Interface for a set of server keys.
getKeys :: (MonadThrow m, MonadIO m) => k -> m (ServerKey, [ServerKey]) Source #
Retrieve current and rotated keys respectively.
removeKey :: (MonadThrow m, MonadIO m) => k -> ServerKey -> m () Source #
Non-graciously remove the key from a keyset.
ServerKeySet PersistentServerKey Source # | |
Eq s => ServerKeySet (RenewableKeySet s p) Source # | |
data PersistentServerKey Source #
A keyset containing only one key, that doesn't change.
mkPersistentServerKey :: ByteString -> PersistentServerKey Source #
Create instance of PersistentServerKey
.
data RenewableKeySet s p Source #
Customizable key set, that provides partial implementation of
ServerKeySet
.
Eq s => ServerKeySet (RenewableKeySet s p) Source # | |
data RenewableKeySetHooks s p Source #
Customizable actions for RenewableKeySet
.
RenewableKeySetHooks | |
|
:: MonadIO m | |
=> RenewableKeySetHooks s p | Hooks |
-> p | Parameters |
-> s | Initial state |
-> m (RenewableKeySet s p) |
Create instance of RenewableKeySet
.
data AuthCookieSettings where Source #
Options that determine authentication mechanisms. Use def
to get
default value of this type.
AuthCookieSettings :: (HashAlgorithm h, BlockCipher c) => {..} -> AuthCookieSettings | |
|
data SessionSettings Source #
Options that determine session mechanisms. Use def
to get
default value of this type.
SessionSettings | |
|
data ExpirationType Source #
How to represent expiration to the client's browser.
newtype EncryptedSession Source #
A newtype wrapper over ByteString
Eq EncryptedSession Source # | |
Show EncryptedSession Source # | |
ToHttpApiData EncryptedSession Source # | |
(Serialize c, MonadIO m, MonadThrow m) => CookiedWrapperClass (m b) (m (Cookied b)) c Source # | |
emptyEncryptedSession :: EncryptedSession Source #
An empty EncryptedSession
:: (MonadIO m, MonadThrow m, Serialize a, ServerKeySet k) | |
=> AuthCookieSettings | Options, see |
-> RandomSource | Random source to use |
-> k | Instance of |
-> SessionSettings | Session settings |
-> a | Session value |
-> m (Tagged SerializedEncryptedCookie ByteString) | Serialized and encrypted session |
Pack session object into a cookie.
The function can throw the following exceptions (of type
AuthCookieException
):
:: (MonadIO m, MonadThrow m, ServerKeySet k, Serialize a) | |
=> AuthCookieSettings | Options, see |
-> k | Instance of |
-> Tagged SerializedEncryptedCookie ByteString | The |
-> m (ExtendedPayloadWrapper a) | The decrypted |
Unpack session value from a cookie. The function can throw the same
exceptions as decryptCookie
.
The function can throw the following exceptions (of type
AuthCookieException
):
addSession :: AddHeader (e :: Symbol) EncryptedSession r s => AddSession r s Source #
Add cookie header to response. The function can throw the same
exceptions as encryptSession
.
removeSession :: AddHeader (e :: Symbol) EncryptedSession r s => RemoveSession r s Source #
Remove a session by invalidating the cookie.
addSessionToErr :: AddSession ServantErr ServantErr Source #
Add cookie session to error allowing to set cookie even if response is not 200.
removeSessionFromErr :: RemoveSession ServantErr ServantErr Source #
Remove a session by invalidating the cookie. Cookie expiry date is set at 0 and content is wiped
:: (MonadIO m, MonadThrow m, Serialize a, ServerKeySet k) | |
=> AuthCookieSettings | Options, see |
-> k |
|
-> Request | The request |
-> m (Maybe (ExtendedPayloadWrapper a)) | The result |
Request handler that checks cookies. If Cookie
is just missing, you
get Nothing
, but if something is wrong with its format, getSession
can throw the same exceptions as decryptSession
.
getHeaderSession :: (MonadIO m, MonadThrow m, Serialize a, ServerKeySet k) => AuthCookieSettings -> k -> Text -> m (Maybe (ExtendedPayloadWrapper a)) Source #
Get session from `Header "cookie" ByteString` in a route. Useful for checking authentication without denying access to route.
If Cookie
is missing, you get Nothing
, but but if something is
wrong with its format, getSession
can throw the same exceptions
as decryptSession
.
defaultAuthHandler :: Serialize a => AuthCookieHandler a Source #
Cookie authentication handler.
Representation of a cookie.
data SerializedEncryptedCookie Source #
Tag for base64 serialized and encrypted cookie.
data EncryptedCookie Source #
Tag for encrypted cookie.
data PayloadBytes Source #
Tag for encrypted or raw payload bytes.
data PaddingBytes Source #
Tag for pading bytes.
base64Encode :: Tagged EncryptedCookie ByteString -> Tagged SerializedEncryptedCookie ByteString Source #
Wrapper for encode
.
base64Decode :: MonadThrow m => Tagged SerializedEncryptedCookie ByteString -> m (Tagged EncryptedCookie ByteString) Source #
Wrapper for decode
.
cerealEncode :: Serialize a => a -> Tagged b ByteString Source #
Wrapper for encode
.
cerealDecode :: (Serialize a, MonadThrow m) => Tagged b ByteString -> m a Source #
Wrapper for decode
.
renderSession :: AddSession () ByteString Source #
Render session cookie to ByteString
.
parseSessionRequest :: AuthCookieSettings -> RequestHeaders -> Maybe (Tagged SerializedEncryptedCookie ByteString) Source #
Parse session cookie from RequestHeaders
.
parseSessionResponse :: AuthCookieSettings -> ResponseHeaders -> Maybe (Tagged SerializedEncryptedCookie ByteString) Source #
Parse session cookie from ResponseHeaders
.
mkCookieKey :: (MonadThrow m, HashAlgorithm h, BlockCipher c) => Proxy c -> Proxy h -> Tagged ServerKeyBytes ByteString -> Tagged IVBytes ByteString -> m (Tagged CookieKeyBytes ByteString) Source #
Derives key for a cookie based on server key and IV.
mkPadding :: (MonadIO m, BlockCipher c) => RandomSource -> Proxy c -> Tagged PayloadBytes ByteString -> m (Tagged PaddingBytes ByteString) Source #
Generates padding of random bytes to align payload's length.
mkMAC :: HashAlgorithm h => Proxy h -> Tagged ServerKeyBytes ByteString -> Cookie -> Tagged MACBytes ByteString Source #
Generates cookie's signature.
applyCipherAlgorithm :: forall c m. (BlockCipher c, MonadThrow m) => CipherAlgorithm c -> Tagged IVBytes ByteString -> Tagged CookieKeyBytes ByteString -> Tagged PayloadBytes ByteString -> m (Tagged PayloadBytes ByteString) Source #
Applies given encryption or decryption algorithm to given data.