Skip to content

Commit b91a743

Browse files
committed
Implement a parser for NameIDFormat
1 parent 6e21b92 commit b91a743

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

src/Network/Wai/SAML2/Assertion.hs

+5-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import Data.Time
2929

3030
import Text.XML.Cursor
3131

32+
import Network.Wai.SAML2.NameIDFormat
3233
import Network.Wai.SAML2.XML
3334

3435
--------------------------------------------------------------------------------
@@ -95,19 +96,21 @@ data NameId = NameId {
9596
nameIdSPProvidedID :: !(Maybe T.Text),
9697
-- | A URI reference describing the format of the value. If not specified it
9798
-- defaults to @urn:oasis:names:tc:SAML:1.0:nameid-format:unspecified@
98-
nameIdFormat :: !(Maybe T.Text),
99+
nameIdFormat :: !(Maybe NameIDFormat),
99100
-- | Some textual identifier for the subject, such as an email address.
100101
nameIdValue :: !T.Text
101102
} deriving (Eq, Show)
102103

103104
instance FromXML NameId where
104105
parseXML cursor = do
106+
nameIdFormat <- traverse parseNameIDFormat
107+
$ listToMaybe (attribute "Format" cursor)
105108
pure NameId {
106109
nameIdQualifier = listToMaybe $ attribute "NameQualifier" cursor,
107110
nameIdSPNameQualifier =
108111
listToMaybe $ attribute "SPNameQualifier" cursor,
109112
nameIdSPProvidedID = listToMaybe $ attribute "SPProvidedID" cursor,
110-
nameIdFormat = listToMaybe $ attribute "Format" cursor,
113+
nameIdFormat = nameIdFormat,
111114
nameIdValue = T.concat $ cursor $/ content
112115
}
113116

src/Network/Wai/SAML2/NameIDFormat.hs

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--------------------------------------------------------------------------------
2+
-- SAML2 Middleware for WAI --
3+
--------------------------------------------------------------------------------
4+
-- This source code is licensed under the MIT license found in the LICENSE --
5+
-- file in the root directory of this source tree. --
6+
--------------------------------------------------------------------------------
7+
{-# LANGUAGE DeriveGeneric #-}
8+
{-# LANGUAGE LambdaCase #-}
9+
10+
-- | This modules defines 'NameIDFormat', the datatype specifying the format
11+
-- of the identifier in an assertion.
12+
module Network.Wai.SAML2.NameIDFormat (
13+
NameIDFormat(..),
14+
parseNameIDFormat
15+
) where
16+
17+
import Data.Text (Text, unpack)
18+
import GHC.Generics (Generic)
19+
20+
-- | Format of the subject identifier.
21+
-- See 8.3 Name Identifier Format Identifiers in https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
22+
data NameIDFormat
23+
-- | The interpretation is left to individual implementations
24+
= Unspecified
25+
-- | @addr-spec@ as defined in IETF RFC 2822
26+
| EmailAddress
27+
-- | contents of the @<ds:X509SubjectName>@ element in the XML Signature Recommendation
28+
| X509SubjectName
29+
-- | String of the form @DomainName\UserName@
30+
| WindowsDomainQualifiedName
31+
-- | Kerberos principal name using the format @name[/instance]@REALM@
32+
| KerberosPrincipalName
33+
-- | identifier of an entity that provides SAML-based services
34+
-- (such as a SAML authority, requester, or responder) or is a participant in SAML profiles (such as a service
35+
-- provider supporting the browser SSO profile)
36+
| Entity
37+
-- | identifier of a provider of SAML-based services
38+
-- (such as a SAML authority) or a participant in SAML
39+
-- profiles (such as a service provider supporting the browser profiles)
40+
| Provider
41+
-- | persistent opaque identifier that corresponds to an identity
42+
-- federation between an identity provider and a service provider
43+
| Federated
44+
-- | an identifier with transient semantics and SHOULD be treated
45+
-- as an opaque and temporary value by the relying party
46+
| Transient
47+
-- | persistent opaque identifier for a principal that is specific to
48+
-- an identity provider and a service provider or affiliation of service providers
49+
| Persistent
50+
deriving (Eq, Ord, Show, Generic)
51+
52+
-- | Parse a 'NameIDFormat' (prefixed by @urn:oasis:names:tc:SAML:*:nameid-format@).
53+
parseNameIDFormat :: MonadFail m => Text -> m NameIDFormat
54+
parseNameIDFormat = \case
55+
"urn:oasis:names:tc:SAML:1.1:nameid-format:Kerberos" -> pure KerberosPrincipalName
56+
"urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName" -> pure WindowsDomainQualifiedName
57+
"urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName" -> pure X509SubjectName
58+
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" -> pure EmailAddress
59+
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" -> pure Unspecified
60+
"urn:oasis:names:tc:SAML:2.0:nameid-format:entity" -> pure Entity
61+
"urn:oasis:names:tc:SAML:2.0:nameid-format:federated" -> pure Federated
62+
"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" -> pure Persistent
63+
"urn:oasis:names:tc:SAML:2.0:nameid-format:provider" -> pure Provider
64+
"urn:oasis:names:tc:SAML:2.0:nameid-format:transient" -> pure Transient
65+
unknown -> fail $ "parseNameIDFormat: unknown format " <> unpack unknown

tests/data/google.xml.expected

+1-2
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ Response
4747
{ nameIdQualifier = Nothing
4848
, nameIdSPNameQualifier = Nothing
4949
, nameIdSPProvidedID = Nothing
50-
, nameIdFormat =
51-
Just "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
50+
, nameIdFormat = Just EmailAddress
5251
, nameIdValue = "sdlc-standard@herp.chat"
5352
}
5453
}

wai-saml2.cabal

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ library
3939
Network.Wai.SAML2.Config
4040
Network.Wai.SAML2.Error
4141
Network.Wai.SAML2.KeyInfo
42+
Network.Wai.SAML2.NameIDFormat
4243
Network.Wai.SAML2.Request
4344
Network.Wai.SAML2.Response
4445
Network.Wai.SAML2.Signature

0 commit comments

Comments
 (0)