    {-# LANGUAGE CPP #-}
    {-# LANGUAGE FlexibleContexts      #-}
    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE RecordWildCards       #-}
    module Aws.Iam.Core
        ( iamSignQuery
        , iamResponseConsumer
        , IamMetadata(..)
        , IamConfiguration(..)
        , IamError(..)

        , parseDateTime

        , AccessKeyStatus(..)
        , User(..)
        , parseUser
        , Group(..)
        , parseGroup
        , MfaDevice(..)
        , parseMfaDevice
        ) where

    import           Aws.Core
    import qualified Blaze.ByteString.Builder       as Blaze
    import qualified Blaze.ByteString.Builder.Char8 as Blaze8
    import           Control.Exception              (Exception)
    import           Control.Monad
    import           Control.Monad.Trans.Resource   (MonadThrow, throwM)
    import           Data.ByteString                (ByteString)
    import           Data.IORef
    import           Data.List                      (intersperse, sort)
    import           Data.Maybe
    import           Data.Monoid                    ()
    import qualified Data.Semigroup                 as Sem
    import           Data.Text                      (Text)
    import qualified Data.Text                      as Text
    import           Data.Time
    import           Data.Typeable
    import qualified Network.HTTP.Conduit           as HTTP
    import qualified Network.HTTP.Types             as HTTP
    #if !MIN_VERSION_time(1,5,0)
    import           System.Locale
    #endif
    import           Text.XML.Cursor                (($//))
    import qualified Text.XML.Cursor                as Cu

    data IamError
        = IamError {
            IamError -> Status
    iamStatusCode   :: HTTP.Status
          , IamError -> Text
    iamErrorCode    :: Text
          , IamError -> Text
    iamErrorMessage :: Text
          }
        deriving (Int -> IamError -> ShowS
    [IamError] -> ShowS
    IamError -> String
    (Int -> IamError -> ShowS)
    -> (IamError -> String) -> ([IamError] -> ShowS) -> Show IamError
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> IamError -> ShowS
    showsPrec :: Int -> IamError -> ShowS
    $cshow :: IamError -> String
    show :: IamError -> String
    $cshowList :: [IamError] -> ShowS
    showList :: [IamError] -> ShowS
    Show, Typeable)

    instance Exception IamError

    data IamMetadata
        = IamMetadata {
            IamMetadata -> Maybe Text
    requestId :: Maybe Text
          }
        deriving (Int -> IamMetadata -> ShowS
    [IamMetadata] -> ShowS
    IamMetadata -> String
    (Int -> IamMetadata -> ShowS)
    -> (IamMetadata -> String)
    -> ([IamMetadata] -> ShowS)
    -> Show IamMetadata
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> IamMetadata -> ShowS
    showsPrec :: Int -> IamMetadata -> ShowS
    $cshow :: IamMetadata -> String
    show :: IamMetadata -> String
    $cshowList :: [IamMetadata] -> ShowS
    showList :: [IamMetadata] -> ShowS
    Show, Typeable)

    instance Loggable IamMetadata where
        toLogText :: IamMetadata -> Text
    toLogText (IamMetadata Maybe Text
    r) = Text
    "IAM: request ID=" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    Sem.<> Text -> Maybe Text -> Text
    forall a. a -> Maybe a -> a
    fromMaybe Text
    "<none>" Maybe Text
    r

    instance Sem.Semigroup IamMetadata where
        IamMetadata Maybe Text
    r1 <> :: IamMetadata -> IamMetadata -> IamMetadata
    <> IamMetadata Maybe Text
    r2 = Maybe Text -> IamMetadata
    IamMetadata (Maybe Text
    r1 Maybe Text -> Maybe Text -> Maybe Text
    forall a. Maybe a -> Maybe a -> Maybe a
    forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
    `mplus` Maybe Text
    r2)

    instance Monoid IamMetadata where
        mempty :: IamMetadata
    mempty = Maybe Text -> IamMetadata
    IamMetadata Maybe Text
    forall a. Maybe a
    Nothing
        mappend :: IamMetadata -> IamMetadata -> IamMetadata
    mappend = IamMetadata -> IamMetadata -> IamMetadata
    forall a. Semigroup a => a -> a -> a
    (Sem.<>)

    data IamConfiguration qt
        = IamConfiguration {
            forall qt. IamConfiguration qt -> ByteString
    iamEndpoint   :: ByteString
          , forall qt. IamConfiguration qt -> Int
    iamPort       :: Int
          , forall qt. IamConfiguration qt -> Protocol
    iamProtocol   :: Protocol
          , forall qt. IamConfiguration qt -> Method
    iamHttpMethod :: Method
          }
        deriving (Int -> IamConfiguration qt -> ShowS
    [IamConfiguration qt] -> ShowS
    IamConfiguration qt -> String
    (Int -> IamConfiguration qt -> ShowS)
    -> (IamConfiguration qt -> String)
    -> ([IamConfiguration qt] -> ShowS)
    -> Show (IamConfiguration qt)
    forall qt. Int -> IamConfiguration qt -> ShowS
    forall qt. [IamConfiguration qt] -> ShowS
    forall qt. IamConfiguration qt -> String
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: forall qt. Int -> IamConfiguration qt -> ShowS
    showsPrec :: Int -> IamConfiguration qt -> ShowS
    $cshow :: forall qt. IamConfiguration qt -> String
    show :: IamConfiguration qt -> String
    $cshowList :: forall qt. [IamConfiguration qt] -> ShowS
    showList :: [IamConfiguration qt] -> ShowS
    Show)

    instance DefaultServiceConfiguration (IamConfiguration NormalQuery) where
        defServiceConfig :: IamConfiguration NormalQuery
    defServiceConfig   = Method -> Protocol -> ByteString -> IamConfiguration NormalQuery
    forall qt. Method -> Protocol -> ByteString -> IamConfiguration qt
    iam Method
    PostQuery Protocol
    HTTPS ByteString
    iamEndpointDefault
        debugServiceConfig :: IamConfiguration NormalQuery
    debugServiceConfig = Method -> Protocol -> ByteString -> IamConfiguration NormalQuery
    forall qt. Method -> Protocol -> ByteString -> IamConfiguration qt
    iam Method
    PostQuery Protocol
    HTTP  ByteString
    iamEndpointDefault

    instance DefaultServiceConfiguration (IamConfiguration UriOnlyQuery) where
        defServiceConfig :: IamConfiguration UriOnlyQuery
    defServiceConfig   = Method -> Protocol -> ByteString -> IamConfiguration UriOnlyQuery
    forall qt. Method -> Protocol -> ByteString -> IamConfiguration qt
    iam Method
    Get Protocol
    HTTPS ByteString
    iamEndpointDefault
        debugServiceConfig :: IamConfiguration UriOnlyQuery
    debugServiceConfig = Method -> Protocol -> ByteString -> IamConfiguration UriOnlyQuery
    forall qt. Method -> Protocol -> ByteString -> IamConfiguration qt
    iam Method
    Get Protocol
    HTTP  ByteString
    iamEndpointDefault

    -- | The default IAM endpoint.
    iamEndpointDefault :: ByteString
    iamEndpointDefault :: ByteString
    iamEndpointDefault = ByteString
    "iam.amazonaws.com"

    -- | Constructs an IamConfiguration with the specified parameters.
    iam :: Method -> Protocol -> ByteString -> IamConfiguration qt
    iam :: forall qt. Method -> Protocol -> ByteString -> IamConfiguration qt
    iam Method
    method Protocol
    protocol ByteString
    endpoint
        = IamConfiguration {
            iamEndpoint :: ByteString
    iamEndpoint   = ByteString
    endpoint
          , iamProtocol :: Protocol
    iamProtocol   = Protocol
    protocol
          , iamPort :: Int
    iamPort       = Protocol -> Int
    defaultPort Protocol
    protocol
          , iamHttpMethod :: Method
    iamHttpMethod = Method
    method
          }

    -- | Constructs a 'SignedQuery' with the specified request parameters.
    iamSignQuery
        :: [(ByteString, ByteString)]
        -- ^ Pairs of parameter names and values that will be passed as part of
        -- the request data.
        -> IamConfiguration qt
        -> SignatureData
        -> SignedQuery
    iamSignQuery :: forall qt.
    [(ByteString, ByteString)]
    -> IamConfiguration qt -> SignatureData -> SignedQuery
    iamSignQuery [(ByteString, ByteString)]
    q IamConfiguration{Int
    ByteString
    Method
    Protocol
    iamEndpoint :: forall qt. IamConfiguration qt -> ByteString
    iamPort :: forall qt. IamConfiguration qt -> Int
    iamProtocol :: forall qt. IamConfiguration qt -> Protocol
    iamHttpMethod :: forall qt. IamConfiguration qt -> Method
    iamEndpoint :: ByteString
    iamPort :: Int
    iamProtocol :: Protocol
    iamHttpMethod :: Method
    ..} SignatureData{UTCTime
    AbsoluteTimeInfo
    Credentials
    signatureTimeInfo :: AbsoluteTimeInfo
    signatureTime :: UTCTime
    signatureCredentials :: Credentials
    signatureCredentials :: SignatureData -> Credentials
    signatureTime :: SignatureData -> UTCTime
    signatureTimeInfo :: SignatureData -> AbsoluteTimeInfo
    ..}
        = SignedQuery {
            sqMethod :: Method
    sqMethod        = Method
    iamHttpMethod
          , sqProtocol :: Protocol
    sqProtocol      = Protocol
    iamProtocol
          , sqHost :: ByteString
    sqHost          = ByteString
    iamEndpoint
          , sqPort :: Int
    sqPort          = Int
    iamPort
          , sqPath :: ByteString
    sqPath          = ByteString
    "/"
          , sqQuery :: [(ByteString, Maybe ByteString)]
    sqQuery         = [(ByteString, Maybe ByteString)]
    signedQuery
          , sqDate :: Maybe UTCTime
    sqDate          = UTCTime -> Maybe UTCTime
    forall a. a -> Maybe a
    Just UTCTime
    signatureTime
          , sqAuthorization :: Maybe (IO ByteString)
    sqAuthorization = Maybe (IO ByteString)
    forall a. Maybe a
    Nothing
          , sqContentType :: Maybe ByteString
    sqContentType   = Maybe ByteString
    forall a. Maybe a
    Nothing
          , sqContentMd5 :: Maybe (Digest MD5)
    sqContentMd5    = Maybe (Digest MD5)
    forall a. Maybe a
    Nothing
          , sqAmzHeaders :: RequestHeaders
    sqAmzHeaders    = []
          , sqOtherHeaders :: RequestHeaders
    sqOtherHeaders  = []
          , sqBody :: Maybe RequestBody
    sqBody          = Maybe RequestBody
    forall a. Maybe a
    Nothing
          , sqStringToSign :: ByteString
    sqStringToSign  = ByteString
    stringToSign
          }
        where
          sig :: ByteString
    sig             = Credentials -> AuthorizationHash -> ByteString -> ByteString
    signature Credentials
    signatureCredentials AuthorizationHash
    HmacSHA256 ByteString
    stringToSign
          signedQuery :: [(ByteString, Maybe ByteString)]
    signedQuery     = (ByteString
    "Signature", ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just ByteString
    sig)(ByteString, Maybe ByteString)
    -> [(ByteString, Maybe ByteString)]
    -> [(ByteString, Maybe ByteString)]
    forall a. a -> [a] -> [a]
    :[(ByteString, Maybe ByteString)]
    expandedQuery
          accessKey :: ByteString
    accessKey       = Credentials -> ByteString
    accessKeyID Credentials
    signatureCredentials
          timestampHeader :: (ByteString, Maybe ByteString)
    timestampHeader =
              case AbsoluteTimeInfo
    signatureTimeInfo of
                AbsoluteTimestamp UTCTime
    time -> (ByteString
    "Timestamp", ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just (ByteString -> Maybe ByteString) -> ByteString -> Maybe ByteString
    forall a b. (a -> b) -> a -> b
    $ UTCTime -> ByteString
    fmtAmzTime UTCTime
    time)
                AbsoluteExpires   UTCTime
    time -> (ByteString
    "Expires"  , ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just (ByteString -> Maybe ByteString) -> ByteString -> Maybe ByteString
    forall a b. (a -> b) -> a -> b
    $ UTCTime -> ByteString
    fmtAmzTime UTCTime
    time)
          newline :: Builder
    newline         = Char -> Builder
    Blaze8.fromChar Char
    '\n'
          stringToSign :: ByteString
    stringToSign    = Builder -> ByteString
    Blaze.toByteString (Builder -> ByteString)
    -> ([Builder] -> Builder) -> [Builder] -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Builder] -> Builder
    forall a. Monoid a => [a] -> a
    mconcat ([Builder] -> Builder)
    -> ([Builder] -> [Builder]) -> [Builder] -> Builder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Builder -> [Builder] -> [Builder]
    forall a. a -> [a] -> [a]
    intersperse Builder
    newline ([Builder] -> ByteString) -> [Builder] -> ByteString
    forall a b. (a -> b) -> a -> b
    $
                                (ByteString -> Builder) -> [ByteString] -> [Builder]
    forall a b. (a -> b) -> [a] -> [b]
    map ByteString -> Builder
    Blaze.copyByteString
                                    [Method -> ByteString
    httpMethod Method
    iamHttpMethod, ByteString
    iamEndpoint, ByteString
    "/"]
                                [Builder] -> [Builder] -> [Builder]
    forall a. [a] -> [a] -> [a]
    ++  [Bool -> [(ByteString, Maybe ByteString)] -> Builder
    HTTP.renderQueryBuilder Bool
    False [(ByteString, Maybe ByteString)]
    expandedQuery]
          expandedQuery :: [(ByteString, Maybe ByteString)]
    expandedQuery   = [(ByteString, Maybe ByteString)]
    -> [(ByteString, Maybe ByteString)]
    forall a. QueryLike a => a -> [(ByteString, Maybe ByteString)]
    HTTP.toQuery ([(ByteString, Maybe ByteString)]
     -> [(ByteString, Maybe ByteString)])
    -> ([(ByteString, Maybe ByteString)]
        -> [(ByteString, Maybe ByteString)])
    -> [(ByteString, Maybe ByteString)]
    -> [(ByteString, Maybe ByteString)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [(ByteString, Maybe ByteString)]
    -> [(ByteString, Maybe ByteString)]
    forall a. Ord a => [a] -> [a]
    sort ([(ByteString, Maybe ByteString)]
     -> [(ByteString, Maybe ByteString)])
    -> [(ByteString, Maybe ByteString)]
    -> [(ByteString, Maybe ByteString)]
    forall a b. (a -> b) -> a -> b
    $ (((ByteString, ByteString) -> (ByteString, Maybe ByteString))
    -> [(ByteString, ByteString)] -> [(ByteString, Maybe ByteString)]
    forall a b. (a -> b) -> [a] -> [b]
    map (\(ByteString
    a,ByteString
    b) -> (ByteString
    a, ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just ByteString
    b)) [(ByteString, ByteString)]
    q [(ByteString, Maybe ByteString)]
    -> [(ByteString, Maybe ByteString)]
    -> [(ByteString, Maybe ByteString)]
    forall a. [a] -> [a] -> [a]
    ++) [
                                (ByteString
    "AWSAccessKeyId"  , ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just ByteString
    accessKey)
                              , (ByteString
    "SignatureMethod" , ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just (ByteString -> Maybe ByteString) -> ByteString -> Maybe ByteString
    forall a b. (a -> b) -> a -> b
    $ AuthorizationHash -> ByteString
    amzHash AuthorizationHash
    HmacSHA256)
                              , (ByteString
    "SignatureVersion", ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just ByteString
    "2")
                              , (ByteString
    "Version"         , ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just ByteString
    "2010-05-08")
                              , (ByteString, Maybe ByteString)
    timestampHeader] [(ByteString, Maybe ByteString)]
    -> [(ByteString, Maybe ByteString)]
    -> [(ByteString, Maybe ByteString)]
    forall a. [a] -> [a] -> [a]
    ++
                              [(ByteString, Maybe ByteString)]
    -> (ByteString -> [(ByteString, Maybe ByteString)])
    -> Maybe ByteString
    -> [(ByteString, Maybe ByteString)]
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe [] (\ByteString
    tok -> [ (ByteString
    "SecurityToken", ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just ByteString
    tok)]) (Credentials -> Maybe ByteString
    iamToken Credentials
    signatureCredentials)

    -- | Reads the metadata from an IAM response and delegates parsing the rest of
    -- the data from the response to the given function.
    iamResponseConsumer :: (Cu.Cursor -> Response IamMetadata a)
                        -> IORef IamMetadata
                        -> HTTPResponseConsumer a
    iamResponseConsumer :: forall a.
    (Cursor -> Response IamMetadata a)
    -> IORef IamMetadata -> HTTPResponseConsumer a
    iamResponseConsumer Cursor -> Response IamMetadata a
    inner IORef IamMetadata
    md Response (ConduitM () ByteString (ResourceT IO) ())
    resp = (Cursor -> Response IamMetadata a)
    -> IORef IamMetadata -> HTTPResponseConsumer a
    forall m a.
    Monoid m =>
    (Cursor -> Response m a) -> IORef m -> HTTPResponseConsumer a
    xmlCursorConsumer Cursor -> Response IamMetadata a
    parse IORef IamMetadata
    md Response (ConduitM () ByteString (ResourceT IO) ())
    resp
      where
        parse :: Cursor -> Response IamMetadata a
    parse Cursor
    cursor = do
          let rid :: Maybe Text
    rid = [Text] -> Maybe Text
    forall a. [a] -> Maybe a
    listToMaybe ([Text] -> Maybe Text) -> [Text] -> Maybe Text
    forall a b. (a -> b) -> a -> b
    $ Cursor
    cursor Cursor -> (Cursor -> [Text]) -> [Text]
    forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
    $// Text -> Cursor -> [Text]
    elContent Text
    "RequestID"
          IamMetadata -> Response IamMetadata ()
    forall m. m -> Response m ()
    tellMetadata (IamMetadata -> Response IamMetadata ())
    -> IamMetadata -> Response IamMetadata ()
    forall a b. (a -> b) -> a -> b
    $ Maybe Text -> IamMetadata
    IamMetadata Maybe Text
    rid
          case Cursor
    cursor Cursor -> (Cursor -> [Cursor]) -> [Cursor]
    forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
    $// Text -> Cursor -> [Cursor]
    Cu.laxElement Text
    "Error" of
              []      -> Cursor -> Response IamMetadata a
    inner Cursor
    cursor
              (Cursor
    err:[Cursor]
    _) -> Cursor -> Response IamMetadata a
    fromError Cursor
    err
        fromError :: Cursor -> Response IamMetadata a
    fromError Cursor
    cursor = do
          errCode <- String -> [Text] -> Response IamMetadata Text
    forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
    force String
    "Missing Error Code"    ([Text] -> Response IamMetadata Text)
    -> [Text] -> Response IamMetadata Text
    forall a b. (a -> b) -> a -> b
    $ Cursor
    cursor Cursor -> (Cursor -> [Text]) -> [Text]
    forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
    $// Text -> Cursor -> [Text]
    elContent Text
    "Code"
          errMsg  <- force "Missing Error Message" $ cursor $// elContent "Message"
          throwM $ IamError (HTTP.responseStatus resp) errCode errMsg

    -- | Parses IAM @DateTime@ data type.
    parseDateTime :: MonadThrow m => String -> m UTCTime
    parseDateTime :: forall (m :: * -> *). MonadThrow m => String -> m UTCTime
    parseDateTime String
    x
        = case Bool -> TimeLocale -> String -> String -> Maybe UTCTime
    forall (m :: * -> *) t.
    (MonadFail m, ParseTime t) =>
    Bool -> TimeLocale -> String -> String -> m t
    parseTimeM Bool
    True TimeLocale
    defaultTimeLocale String
    iso8601UtcDate String
    x of
            Maybe UTCTime
    Nothing -> XmlException -> m UTCTime
    forall e a. (HasCallStack, Exception e) => e -> m a
    forall (m :: * -> *) e a.
    (MonadThrow m, HasCallStack, Exception e) =>
    e -> m a
    throwM (XmlException -> m UTCTime) -> XmlException -> m UTCTime
    forall a b. (a -> b) -> a -> b
    $ String -> XmlException
    XmlException (String -> XmlException) -> String -> XmlException
    forall a b. (a -> b) -> a -> b
    $ String
    "Invalid DateTime: " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    x
            Just UTCTime
    dt -> UTCTime -> m UTCTime
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return UTCTime
    dt

    -- | The IAM @User@ data type.
    --
    -- <http://docs.aws.amazon.com/IAM/latest/APIReference/API_User.html>
    data User
        = User {
            User -> Text
    userArn        :: Text
          -- ^ ARN used to refer to this user.
          , User -> UTCTime
    userCreateDate :: UTCTime
          -- ^ Date and time at which the user was created.
          , User -> Text
    userPath       :: Text
          -- ^ Path under which the user was created.
          , User -> Text
    userUserId     :: Text
          -- ^ Unique identifier used to refer to this user.
          , User -> Text
    userUserName   :: Text
          -- ^ Name of the user.
          }
        deriving (User -> User -> Bool
    (User -> User -> Bool) -> (User -> User -> Bool) -> Eq User
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: User -> User -> Bool
    == :: User -> User -> Bool
    $c/= :: User -> User -> Bool
    /= :: User -> User -> Bool
    Eq, Eq User
    Eq User =>
    (User -> User -> Ordering)
    -> (User -> User -> Bool)
    -> (User -> User -> Bool)
    -> (User -> User -> Bool)
    -> (User -> User -> Bool)
    -> (User -> User -> User)
    -> (User -> User -> User)
    -> Ord User
    User -> User -> Bool
    User -> User -> Ordering
    User -> User -> User
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: User -> User -> Ordering
    compare :: User -> User -> Ordering
    $c< :: User -> User -> Bool
    < :: User -> User -> Bool
    $c<= :: User -> User -> Bool
    <= :: User -> User -> Bool
    $c> :: User -> User -> Bool
    > :: User -> User -> Bool
    $c>= :: User -> User -> Bool
    >= :: User -> User -> Bool
    $cmax :: User -> User -> User
    max :: User -> User -> User
    $cmin :: User -> User -> User
    min :: User -> User -> User
    Ord, Int -> User -> ShowS
    [User] -> ShowS
    User -> String
    (Int -> User -> ShowS)
    -> (User -> String) -> ([User] -> ShowS) -> Show User
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> User -> ShowS
    showsPrec :: Int -> User -> ShowS
    $cshow :: User -> String
    show :: User -> String
    $cshowList :: [User] -> ShowS
    showList :: [User] -> ShowS
    Show, Typeable)

    -- | Parses the IAM @User@ data type.
    parseUser :: MonadThrow m => Cu.Cursor -> m User
    parseUser :: forall (m :: * -> *). MonadThrow m => Cursor -> m User
    parseUser Cursor
    cursor = do
        userArn        <- Text -> m Text
    attr Text
    "Arn"
        userCreateDate <- attr "CreateDate" >>= parseDateTime . Text.unpack
        userPath       <- attr "Path"
        userUserId     <- attr "UserId"
        userUserName   <- attr "UserName"
        return User{..}
      where
        attr :: Text -> m Text
    attr Text
    name = String -> [Text] -> m Text
    forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
    force (String
    "Missing " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Text -> String
    Text.unpack Text
    name) ([Text] -> m Text) -> [Text] -> m Text
    forall a b. (a -> b) -> a -> b
    $
                    Cursor
    cursor Cursor -> (Cursor -> [Text]) -> [Text]
    forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
    $// Text -> Cursor -> [Text]
    elContent Text
    name

    -- | The IAM @Group@ data type.
    --
    -- <http://docs.aws.amazon.com/IAM/latest/APIReference/API_Group.html>
    data Group
        = Group {
            Group -> Text
    groupArn        :: Text
          -- ^ ARN used to refer to this group.
          , Group -> UTCTime
    groupCreateDate :: UTCTime
          -- ^ Date and time at which the group was created.
          , Group -> Text
    groupPath       :: Text
          -- ^ Path under which the group was created.
          , Group -> Text
    groupGroupId     :: Text
          -- ^ Unique identifier used to refer to this group.
          , Group -> Text
    groupGroupName   :: Text
          -- ^ Name of the group.
          }
        deriving (Group -> Group -> Bool
    (Group -> Group -> Bool) -> (Group -> Group -> Bool) -> Eq Group
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Group -> Group -> Bool
    == :: Group -> Group -> Bool
    $c/= :: Group -> Group -> Bool
    /= :: Group -> Group -> Bool
    Eq, Eq Group
    Eq Group =>
    (Group -> Group -> Ordering)
    -> (Group -> Group -> Bool)
    -> (Group -> Group -> Bool)
    -> (Group -> Group -> Bool)
    -> (Group -> Group -> Bool)
    -> (Group -> Group -> Group)
    -> (Group -> Group -> Group)
    -> Ord Group
    Group -> Group -> Bool
    Group -> Group -> Ordering
    Group -> Group -> Group
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Group -> Group -> Ordering
    compare :: Group -> Group -> Ordering
    $c< :: Group -> Group -> Bool
    < :: Group -> Group -> Bool
    $c<= :: Group -> Group -> Bool
    <= :: Group -> Group -> Bool
    $c> :: Group -> Group -> Bool
    > :: Group -> Group -> Bool
    $c>= :: Group -> Group -> Bool
    >= :: Group -> Group -> Bool
    $cmax :: Group -> Group -> Group
    max :: Group -> Group -> Group
    $cmin :: Group -> Group -> Group
    min :: Group -> Group -> Group
    Ord, Int -> Group -> ShowS
    [Group] -> ShowS
    Group -> String
    (Int -> Group -> ShowS)
    -> (Group -> String) -> ([Group] -> ShowS) -> Show Group
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Group -> ShowS
    showsPrec :: Int -> Group -> ShowS
    $cshow :: Group -> String
    show :: Group -> String
    $cshowList :: [Group] -> ShowS
    showList :: [Group] -> ShowS
    Show, Typeable)

    -- | Parses the IAM @Group@ data type.
    parseGroup :: MonadThrow m => Cu.Cursor -> m Group
    parseGroup :: forall (m :: * -> *). MonadThrow m => Cursor -> m Group
    parseGroup Cursor
    cursor = do
        groupArn        <- Text -> m Text
    attr Text
    "Arn"
        groupCreateDate <- attr "CreateDate" >>= parseDateTime . Text.unpack
        groupPath       <- attr "Path"
        groupGroupId     <- attr "GroupId"
        groupGroupName   <- attr "GroupName"
        return Group{..}
      where
        attr :: Text -> m Text
    attr Text
    name = String -> [Text] -> m Text
    forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
    force (String
    "Missing " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Text -> String
    Text.unpack Text
    name) ([Text] -> m Text) -> [Text] -> m Text
    forall a b. (a -> b) -> a -> b
    $
                    Cursor
    cursor Cursor -> (Cursor -> [Text]) -> [Text]
    forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
    $// Text -> Cursor -> [Text]
    elContent Text
    name

    data AccessKeyStatus = AccessKeyActive | AccessKeyInactive
        deriving (AccessKeyStatus -> AccessKeyStatus -> Bool
    (AccessKeyStatus -> AccessKeyStatus -> Bool)
    -> (AccessKeyStatus -> AccessKeyStatus -> Bool)
    -> Eq AccessKeyStatus
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: AccessKeyStatus -> AccessKeyStatus -> Bool
    == :: AccessKeyStatus -> AccessKeyStatus -> Bool
    $c/= :: AccessKeyStatus -> AccessKeyStatus -> Bool
    /= :: AccessKeyStatus -> AccessKeyStatus -> Bool
    Eq, Eq AccessKeyStatus
    Eq AccessKeyStatus =>
    (AccessKeyStatus -> AccessKeyStatus -> Ordering)
    -> (AccessKeyStatus -> AccessKeyStatus -> Bool)
    -> (AccessKeyStatus -> AccessKeyStatus -> Bool)
    -> (AccessKeyStatus -> AccessKeyStatus -> Bool)
    -> (AccessKeyStatus -> AccessKeyStatus -> Bool)
    -> (AccessKeyStatus -> AccessKeyStatus -> AccessKeyStatus)
    -> (AccessKeyStatus -> AccessKeyStatus -> AccessKeyStatus)
    -> Ord AccessKeyStatus
    AccessKeyStatus -> AccessKeyStatus -> Bool
    AccessKeyStatus -> AccessKeyStatus -> Ordering
    AccessKeyStatus -> AccessKeyStatus -> AccessKeyStatus
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: AccessKeyStatus -> AccessKeyStatus -> Ordering
    compare :: AccessKeyStatus -> AccessKeyStatus -> Ordering
    $c< :: AccessKeyStatus -> AccessKeyStatus -> Bool
    < :: AccessKeyStatus -> AccessKeyStatus -> Bool
    $c<= :: AccessKeyStatus -> AccessKeyStatus -> Bool
    <= :: AccessKeyStatus -> AccessKeyStatus -> Bool
    $c> :: AccessKeyStatus -> AccessKeyStatus -> Bool
    > :: AccessKeyStatus -> AccessKeyStatus -> Bool
    $c>= :: AccessKeyStatus -> AccessKeyStatus -> Bool
    >= :: AccessKeyStatus -> AccessKeyStatus -> Bool
    $cmax :: AccessKeyStatus -> AccessKeyStatus -> AccessKeyStatus
    max :: AccessKeyStatus -> AccessKeyStatus -> AccessKeyStatus
    $cmin :: AccessKeyStatus -> AccessKeyStatus -> AccessKeyStatus
    min :: AccessKeyStatus -> AccessKeyStatus -> AccessKeyStatus
    Ord, Int -> AccessKeyStatus -> ShowS
    [AccessKeyStatus] -> ShowS
    AccessKeyStatus -> String
    (Int -> AccessKeyStatus -> ShowS)
    -> (AccessKeyStatus -> String)
    -> ([AccessKeyStatus] -> ShowS)
    -> Show AccessKeyStatus
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> AccessKeyStatus -> ShowS
    showsPrec :: Int -> AccessKeyStatus -> ShowS
    $cshow :: AccessKeyStatus -> String
    show :: AccessKeyStatus -> String
    $cshowList :: [AccessKeyStatus] -> ShowS
    showList :: [AccessKeyStatus] -> ShowS
    Show, Typeable)

    -- | The IAM @MFADevice@ data type.
    --
    -- <https://docs.aws.amazon.com/IAM/latest/APIReference/API_MFADevice.html>
    data MfaDevice = MfaDevice
                     { MfaDevice -> UTCTime
    mfaEnableDate   :: UTCTime
                       -- ^ The date when the MFA device was enabled for
                       -- the user.
                     , MfaDevice -> Text
    mfaSerialNumber :: Text
                       -- ^ The serial number that uniquely identifies the
                       -- MFA device. For virtual MFA devices, the serial
                       -- number is the device ARN.
                     , MfaDevice -> Text
    mfaUserName     :: Text
                       -- ^ The user with whom the MFA device is
                       -- associated. Minimum length of 1. Maximum length
                       -- of 64.
                     } deriving (MfaDevice -> MfaDevice -> Bool
    (MfaDevice -> MfaDevice -> Bool)
    -> (MfaDevice -> MfaDevice -> Bool) -> Eq MfaDevice
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: MfaDevice -> MfaDevice -> Bool
    == :: MfaDevice -> MfaDevice -> Bool
    $c/= :: MfaDevice -> MfaDevice -> Bool
    /= :: MfaDevice -> MfaDevice -> Bool
    Eq, Eq MfaDevice
    Eq MfaDevice =>
    (MfaDevice -> MfaDevice -> Ordering)
    -> (MfaDevice -> MfaDevice -> Bool)
    -> (MfaDevice -> MfaDevice -> Bool)
    -> (MfaDevice -> MfaDevice -> Bool)
    -> (MfaDevice -> MfaDevice -> Bool)
    -> (MfaDevice -> MfaDevice -> MfaDevice)
    -> (MfaDevice -> MfaDevice -> MfaDevice)
    -> Ord MfaDevice
    MfaDevice -> MfaDevice -> Bool
    MfaDevice -> MfaDevice -> Ordering
    MfaDevice -> MfaDevice -> MfaDevice
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: MfaDevice -> MfaDevice -> Ordering
    compare :: MfaDevice -> MfaDevice -> Ordering
    $c< :: MfaDevice -> MfaDevice -> Bool
    < :: MfaDevice -> MfaDevice -> Bool
    $c<= :: MfaDevice -> MfaDevice -> Bool
    <= :: MfaDevice -> MfaDevice -> Bool
    $c> :: MfaDevice -> MfaDevice -> Bool
    > :: MfaDevice -> MfaDevice -> Bool
    $c>= :: MfaDevice -> MfaDevice -> Bool
    >= :: MfaDevice -> MfaDevice -> Bool
    $cmax :: MfaDevice -> MfaDevice -> MfaDevice
    max :: MfaDevice -> MfaDevice -> MfaDevice
    $cmin :: MfaDevice -> MfaDevice -> MfaDevice
    min :: MfaDevice -> MfaDevice -> MfaDevice
    Ord, Int -> MfaDevice -> ShowS
    [MfaDevice] -> ShowS
    MfaDevice -> String
    (Int -> MfaDevice -> ShowS)
    -> (MfaDevice -> String)
    -> ([MfaDevice] -> ShowS)
    -> Show MfaDevice
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> MfaDevice -> ShowS
    showsPrec :: Int -> MfaDevice -> ShowS
    $cshow :: MfaDevice -> String
    show :: MfaDevice -> String
    $cshowList :: [MfaDevice] -> ShowS
    showList :: [MfaDevice] -> ShowS
    Show, Typeable)

    -- | Parses the IAM @MFADevice@ data type.
    parseMfaDevice :: MonadThrow m => Cu.Cursor -> m MfaDevice
    parseMfaDevice :: forall (m :: * -> *). MonadThrow m => Cursor -> m MfaDevice
    parseMfaDevice Cursor
    cursor = do
      mfaEnableDate   <- Text -> m Text
    attr Text
    "EnableDate" m Text -> (Text -> m UTCTime) -> m UTCTime
    forall a b. m a -> (a -> m b) -> m b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= String -> m UTCTime
    forall (m :: * -> *). MonadThrow m => String -> m UTCTime
    parseDateTime (String -> m UTCTime) -> (Text -> String) -> Text -> m UTCTime
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    Text.unpack
      mfaSerialNumber <- attr "SerialNumber"
      mfaUserName     <- attr "UserName"
      return MfaDevice{..}
     where attr :: Text -> m Text
    attr Text
    name = String -> [Text] -> m Text
    forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
    force (String
    "Missing " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Text -> String
    Text.unpack Text
    name) ([Text] -> m Text) -> [Text] -> m Text
    forall a b. (a -> b) -> a -> b
    $
                   Cursor
    cursor Cursor -> (Cursor -> [Text]) -> [Text]
    forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
    $// Text -> Cursor -> [Text]
    elContent Text
    name