saml2-web-sso-0.20: Library and example web app for the SAML Web-based SSO profile.
Safe HaskellSafe-Inferred
LanguageHaskell2010

SAML2.WebSSO.API

Description

This is a partial implementation of Web SSO using the HTTP Post Binding [2/3.5].

The default API offers 3 end-points: one for retrieving the AuthnRequest in a redirect to the IdP; one for delivering the AuthnResponse that will re-direct to some fixed landing page; and one for retrieving the SP's metadata.

There are other scenarios, e.g. all resources on the page could be guarded with an authentication check and redirect the client to the IdP, and make sure that the client lands on the initally requested resource after successful authentication. With the building blocks provided by this module, it should be straight-forward to implemented all of these scenarios.

This module works best if imported qualified.

FUTUREWORK: servant-server is quite heavy. we should have a cabal flag to exclude it.

Synopsis

Documentation

type API = APIMeta' :<|> (APIAuthReq' :<|> APIAuthResp') Source #

Consider rate-limiting these end-points to mitigate DOS attacks. APIAuthReq uses database space, and APIAuthResp uses both database space and CPU.

data FormRedirect xml Source #

2/3.5.4

Constructors

FormRedirect URI xml 

Instances

Instances details
HasXMLRoot xml => MimeRender HTML (FormRedirect xml) Source # 
Instance details

Defined in SAML2.WebSSO.API

HasXMLRoot xml => MimeUnrender HTML (FormRedirect xml) Source # 
Instance details

Defined in SAML2.WebSSO.API

Arbitrary a => Arbitrary (FormRedirect a) Source # 
Instance details

Defined in SAML2.WebSSO.Test.Arbitrary

Generic (FormRedirect xml) Source # 
Instance details

Defined in SAML2.WebSSO.API

Associated Types

type Rep (FormRedirect xml) :: Type -> Type #

Methods

from :: FormRedirect xml -> Rep (FormRedirect xml) x #

to :: Rep (FormRedirect xml) x -> FormRedirect xml #

Show xml => Show (FormRedirect xml) Source # 
Instance details

Defined in SAML2.WebSSO.API

Eq xml => Eq (FormRedirect xml) Source # 
Instance details

Defined in SAML2.WebSSO.API

Methods

(==) :: FormRedirect xml -> FormRedirect xml -> Bool #

(/=) :: FormRedirect xml -> FormRedirect xml -> Bool #

type Rep (FormRedirect xml) Source # 
Instance details

Defined in SAML2.WebSSO.API

type Rep (FormRedirect xml) = D1 ('MetaData "FormRedirect" "SAML2.WebSSO.API" "saml2-web-sso-0.20-JnyBok8kx0LFwqAg1j3uky" 'False) (C1 ('MetaCons "FormRedirect" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 URI) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 xml)))

data AuthnResponseBody Source #

An AuthnResponseBody contains a AuthnResponse, but you need to give it an SPId for IdP lookup and trust base for signature verification first, plus you may get an error when you're looking at it.

Constructors

AuthnResponseBody 

Fields

Instances

Instances details
FromMultipart Mem AuthnResponseBody Source # 
Instance details

Defined in SAML2.WebSSO.API

type WithCookieAndLocation = Headers '[Header "Set-Cookie" Cky, Header "Location" URI] Source #

type APIMeta' = "meta" :> APIMeta Source #

type APIAuthReq' = "authreq" :> APIAuthReq Source #

type APIAuthResp' = "authresp" :> APIAuthResp Source #

data HandleVerdict m Source #

We support two cases: redirect with a cookie, and a generic response with arbitrary status, headers, and body. The latter case fits the ServerError type well, but we give it a more suitable name here.

class HasXML xml => HasFormRedirect xml where Source #

Methods

formRedirectFieldName :: xml -> ST Source #

type CookieName = "saml2-web-sso" Source #

meta :: forall m err. (SPStore m, MonadError err m, HasConfig m) => ST -> m Issuer -> m URI -> m SPMetadata Source #

api :: forall err m. SPHandler (Error err) m => ST -> HandleVerdict m -> ServerT API m Source #

defSPIssuer :: (Functor m, HasConfig m) => m Issuer Source #

The Issuer is an identifier of a SAML participant. In this case, it's the SP, ie., ourselves. For simplicity, we re-use the response URI here.

defResponseURI :: (Functor m, HasConfig m) => m URI Source #

The URI that AuthnResponse values are delivered to (APIAuthResp).

authreq' :: (SPStore m, SPStoreIdP err m, MonadError err m) => m Issuer -> IdPId -> m (FormRedirect AuthnRequest) Source #

authreq with request life expectancy defaulting to 8 hours.

authresp' :: (SP m, SPStoreIdP (Error err) m, SPStoreID Assertion m, SPStoreID AuthnRequest m) => Maybe (IdPConfigSPId m) -> m Issuer -> m URI -> HandleVerdict m -> AuthnResponseBody -> m (WithCookieAndLocation ST) Source #

a variant of authresp with a less general verdict handler.

parseAuthnResponseBody :: forall m err spid extra. (SPStoreIdP (Error err) m, spid ~ IdPConfigSPId m, extra ~ IdPConfigExtra m) => Maybe spid -> ST -> m (AuthnResponse, IdPConfig extra) Source #

Implies verification, hence the constraints.

idpToCreds :: forall m err extra. (SPStoreIdP (Error err) m, extra ~ IdPConfigExtra m) => Issuer -> IdPConfig extra -> m (NonEmpty SignCreds) Source #

simpleVerifyAuthnResponse :: forall m err. MonadError (Error err) m => NonEmpty SignCreds -> LBS -> m () Source #

Pull assertions sub-forest and pass unparsed xml input to verify with a reference to each assertion individually. The input must be a valid AuthnResponse. All assertions need to be signed by the issuer given in the arguments using the same key.

allVerifies :: forall m err. MonadError (Error err) m => NonEmpty SignCreds -> LBS -> [String] -> m () Source #

Call verify and, if that fails, any work-arounds we have. Discard all errors from work-arounds, and throw the error from the regular verification.

verifyADFS :: MonadError String m => NonEmpty SignCreds -> LBS -> [String] -> m () Source #

ADFS illegally breaks whitespace after signing documents; here we try to fix that. https://github.com/wireapp/wire-server/issues/656 (This may also have been a copy&paste issue in customer support, but let's just leave it in just in case.)

enterH :: SP m => String -> m () Source #

authreq :: (SPStore m, SPStoreIdP err m, MonadError err m) => NominalDiffTime -> m Issuer -> IdPId -> m (FormRedirect AuthnRequest) Source #

Create authnreq, store it for comparison against assertions later, and return it in an HTTP redirect together with the IdP's URI.

leaveH :: (Monad m, Show a, SP m) => a -> m a Source #

authresp :: (SP m, SPStoreIdP (Error err) m, extra ~ IdPConfigExtra m, SPStoreID Assertion m, SPStoreID AuthnRequest m) => Maybe (IdPConfigSPId m) -> m Issuer -> m URI -> (AuthnResponse -> IdPConfig extra -> AccessVerdict -> m resp) -> AuthnResponseBody -> m resp Source #

parse and validate response, and pass the verdict to a user-provided verdict handler. the handler takes a response and a verdict (provided by this package), and can cause any effects in m and return anything it likes.

crash :: (SP m, MonadError (Error err) m) => String -> m a Source #

Write error info to log, and apologise to client.