wai-saml2-0.3.0.0: src/Network/Wai/SAML2/Signature.hs
--------------------------------------------------------------------------------
-- SAML2 Middleware for WAI --
--------------------------------------------------------------------------------
-- This source code is licensed under the MIT license found in the LICENSE --
-- file in the root directory of this source tree. --
--------------------------------------------------------------------------------
-- | SAML2 signatures.
module Network.Wai.SAML2.Signature (
CanonicalisationMethod(..),
SignatureMethod(..),
DigestMethod(..),
SignedInfo(..),
Reference(..),
Signature(..)
) where
--------------------------------------------------------------------------------
import qualified Data.ByteString as BS
import qualified Data.Text as T
import Data.Text.Encoding
import Text.XML.Cursor
import Network.Wai.SAML2.XML
--------------------------------------------------------------------------------
-- | Enumerates XML canonicalisation methods.
data CanonicalisationMethod
-- | Original C14N 1.0 specification.
= C14N_1_0
-- | Exclusive C14N 1.0 specification.
| C14N_EXC_1_0
-- | C14N 1.1 specification.
| C14N_1_1
deriving (Eq, Show)
instance FromXML CanonicalisationMethod where
parseXML cursor =
case T.concat $ attribute "Algorithm" cursor of
"http://www.w3.org/2001/10/xml-exc-c14n#" -> pure C14N_EXC_1_0
_ -> fail "Not a valid CanonicalisationMethod"
-- | Enumerates signature methods.
data SignatureMethod
-- | RSA with SHA256 digest
= RSA_SHA256
deriving (Eq, Show)
instance FromXML SignatureMethod where
parseXML cursor = case T.concat $ attribute "Algorithm" cursor of
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" -> pure RSA_SHA256
_ -> fail "Not a valid SignatureMethod"
--------------------------------------------------------------------------------
-- | Enumerates digest methods.
data DigestMethod
-- | SHA256
= DigestSHA256
deriving (Eq, Show)
instance FromXML DigestMethod where
parseXML cursor = case T.concat $ attribute "Algorithm" cursor of
"http://www.w3.org/2001/04/xmlenc#sha256" -> pure DigestSHA256
_ -> fail "Not a valid DigestMethod"
-- | Represents a reference to some entity along with a digest of it.
data Reference = Reference {
-- | The URI of the entity that is referenced.
referenceURI :: !T.Text,
-- | The method that was used to calculate the digest for the
-- entity that is referenced.
referenceDigestMethod :: !DigestMethod,
-- | The digest of the entity that was calculated by the IdP.
referenceDigestValue :: !BS.ByteString
} deriving (Eq, Show)
instance FromXML Reference where
parseXML cursor = do
-- the reference starts with a #, drop it
let uri = T.drop 1 $ T.concat $ attribute "URI" cursor
digestMethod <- oneOrFail "DigestMethod is required" (
cursor $/ element (dsName "DigestMethod")
) >>= parseXML
let digestValue = encodeUtf8 $ T.concat $
cursor $/ element (dsName "DigestValue") &/ content
pure Reference{
referenceURI = uri,
referenceDigestMethod = digestMethod,
referenceDigestValue = digestValue
}
--------------------------------------------------------------------------------
-- | Represents references to some entities for which the IdP has calculated
-- digests. The 'SignedInfo' component is then signed by the IdP.
data SignedInfo = SignedInfo {
-- | The XML canonicalisation method used.
signedInfoCanonicalisationMethod :: !CanonicalisationMethod,
-- | The method used to compute the signature for the referenced entity.
signedInfoSignatureMethod :: !SignatureMethod,
-- | The reference to some entity, along with a digest.
signedInfoReference :: !Reference
} deriving (Eq, Show)
instance FromXML SignedInfo where
parseXML cursor = do
canonicalisationMethod <-
oneOrFail "CanonicalizationMethod is required"
( cursor
$/ element (dsName "CanonicalizationMethod")
) >>= parseXML
signatureMethod <-
oneOrFail "SignatureMethod is required"
( cursor
$/ element (dsName "SignatureMethod")
) >>= parseXML
reference <-
oneOrFail "Reference is required"
( cursor
$/ element (dsName "Reference")
) >>= parseXML
pure SignedInfo{
signedInfoCanonicalisationMethod = canonicalisationMethod,
signedInfoSignatureMethod = signatureMethod,
signedInfoReference = reference
}
-- | Represents response signatures.
data Signature = Signature {
-- | Information about the data for which the IdP has computed digests.
signatureInfo :: !SignedInfo,
-- | The signature of the 'SignedInfo' value.
signatureValue :: !BS.ByteString
} deriving (Eq, Show)
instance FromXML Signature where
parseXML cursor = do
info <- oneOrFail "SignedInfo is required" (
cursor $/ element (dsName "SignedInfo") ) >>= parseXML
let value = encodeUtf8 $ T.concat $
cursor $/ element (dsName "SignatureValue") &/ content
pure Signature{
signatureInfo = info,
signatureValue = value
}
--------------------------------------------------------------------------------