wai-saml2-0.5: SAML2 assertion validation as WAI middleware
Safe HaskellSafe-Inferred
LanguageHaskell2010

Network.Wai.SAML2

Description

Implements WAI Middleware for SAML2 service providers. Two different interfaces are supported (with equivalent functionality): one which simply stores the outcome of the validation process in the request vault and one which passes the outcome to a callback.

Synopsis

Callback-based middleware

This Middleware provides a SAML2 service provider (SP) implementation that can be wrapped around an existing WAI Application. The middleware is parameterised over the SAML2 configuration and a callback. If the middleware intercepts a request made to the endpoint given by the SAML2 configuration, the result of validating the SAML2 response contained in the request body will be passed to the callback.

saml2Callback cfg callback mainApp
 where callback (Left err) app req sendResponse = do
           -- a POST request was made to the assertion endpoint, but
           -- something went wrong, details of which are provided by
           -- the error: this should probably be logged as it may
           -- indicate that an attack was attempted against the
           -- endpoint, but you *must* not show the error
           -- to the client as it would severely compromise
           -- system security
           --
           -- you may also want to return e.g. a HTTP 400 or 401 status

       callback (Right result) app req sendResponse = do
           -- a POST request was made to the assertion endpoint and the
           -- SAML2 response was successfully validated:
           -- you *must* check that you have not encountered the
           -- assertion ID before; we assume that there is a
           -- computation tryRetrieveAssertion which looks up
           -- assertions by ID in e.g. a database
           result <- tryRetrieveAssertion (assertionId (assertion result))

           case result of
               Just something -> -- a replay attack has occurred
               Nothing -> do
                   -- store the assertion id somewhere
                   storeAssertion (assertionId (assertion result))

                   -- the assertion is valid and you can now e.g.
                   -- retrieve user data from your database
                   -- before proceeding with the request by e.g.
                   -- redirecting them to the main view

data Result Source #

Represents the result of validating a SAML2 response.

Constructors

Result 

Fields

Instances

Instances details
Show Result Source # 
Instance details

Defined in Network.Wai.SAML2

Eq Result Source # 
Instance details

Defined in Network.Wai.SAML2

Methods

(==) :: Result -> Result -> Bool #

(/=) :: Result -> Result -> Bool #

saml2Callback :: SAML2Config -> (Either SAML2Error Result -> Middleware) -> Middleware Source #

saml2Callback config callback produces SAML2 Middleware for the given config. If the middleware intercepts a request to the endpoint given by config, the result will be passed to callback.

Vault-based middleware

This is a simpler-to-use Middleware which stores the outcome of a request made to the assertation endpoint in the request vault. The inner WAI application can then check of the presence of an assertion or an error with lookup and assertionKey or errorKey respectively. At most one of the two locations will be populated for a given request, i.e. it is not possible for an assertion to be validated and an error to occur.

saml2Vault cfg $ \app req sendResponse -> do
   case V.lookup errorKey (vault req) of
       Just err ->
           -- log the error, but you *must* not show the error
           -- to the client as it would severely compromise
           -- system security
       Nothing -> pure () -- carry on

   case V.lookup assertionKey (vault req) of
       Nothing -> pure () -- carry on
       Just assertion -> do
           -- a valid assertion was processed by the middleware,
           -- you *must* check that you have not encountered the
           -- assertion ID before; we assume that there is a
           -- computation tryRetrieveAssertion which looks up
           -- assertions by ID in e.g. a database
           result <- tryRetrieveAssertion (assertionId assertion)

           case result of
               Just something -> -- a replay attack has occurred
               Nothing -> do
                   -- store the assertion id somewhere
                   storeAssertion (assertionId assertion)

                   -- the assertion is valid

assertionKey :: Key Assertion Source #

assertionKey is a vault key for retrieving assertions from request vaults if the saml2Vault Middleware is used.

errorKey :: Key SAML2Error Source #

errorKey is a vault key for retrieving SAML2 errors from request vaults if the saml2Vault Middleware is used.

saml2Vault :: SAML2Config -> Middleware Source #

saml2Vault config produces SAML2 Middleware for the given config.

relayStateKey :: Key ByteString Source #

relayStateKey is a vault key for retrieving the relay state from request vaults if the saml2Vault Middleware is used and the assertion is valid.

Re-exports