{-# 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
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [IamError] -> ShowS
$cshowList :: [IamError] -> ShowS
show :: IamError -> String
$cshow :: IamError -> String
showsPrec :: Int -> IamError -> ShowS
$cshowsPrec :: Int -> IamError -> ShowS
Show, Typeable)

instance Exception IamError

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

instance Loggable IamMetadata where
    toLogText :: IamMetadata -> Text
toLogText (IamMetadata Maybe Text
r) = Text
"IAM: request ID=" forall a. Semigroup a => a -> a -> a
Sem.<> 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 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 forall a. Maybe a
Nothing
    mappend :: IamMetadata -> IamMetadata -> IamMetadata
mappend = 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
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
showList :: [IamConfiguration qt] -> ShowS
$cshowList :: forall qt. [IamConfiguration qt] -> ShowS
show :: IamConfiguration qt -> String
$cshow :: forall qt. IamConfiguration qt -> String
showsPrec :: Int -> IamConfiguration qt -> ShowS
$cshowsPrec :: forall qt. Int -> IamConfiguration qt -> ShowS
Show)

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

instance DefaultServiceConfiguration (IamConfiguration UriOnlyQuery) where
    defServiceConfig :: IamConfiguration UriOnlyQuery
defServiceConfig   = forall qt. Method -> Protocol -> ByteString -> IamConfiguration qt
iam Method
Get Protocol
HTTPS ByteString
iamEndpointDefault
    debugServiceConfig :: IamConfiguration UriOnlyQuery
debugServiceConfig = 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
iamHttpMethod :: Method
iamProtocol :: Protocol
iamPort :: Int
iamEndpoint :: ByteString
iamHttpMethod :: forall qt. IamConfiguration qt -> Method
iamProtocol :: forall qt. IamConfiguration qt -> Protocol
iamPort :: forall qt. IamConfiguration qt -> Int
iamEndpoint :: forall qt. IamConfiguration qt -> ByteString
..} SignatureData{UTCTime
AbsoluteTimeInfo
Credentials
signatureCredentials :: SignatureData -> Credentials
signatureTime :: SignatureData -> UTCTime
signatureTimeInfo :: SignatureData -> AbsoluteTimeInfo
signatureCredentials :: Credentials
signatureTime :: UTCTime
signatureTimeInfo :: 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          = forall a. a -> Maybe a
Just UTCTime
signatureTime
      , sqAuthorization :: Maybe (IO ByteString)
sqAuthorization = forall a. Maybe a
Nothing
      , sqContentType :: Maybe ByteString
sqContentType   = forall a. Maybe a
Nothing
      , sqContentMd5 :: Maybe (Digest MD5)
sqContentMd5    = forall a. Maybe a
Nothing
      , sqAmzHeaders :: RequestHeaders
sqAmzHeaders    = []
      , sqOtherHeaders :: RequestHeaders
sqOtherHeaders  = []
      , sqBody :: Maybe RequestBody
sqBody          = 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", forall a. a -> Maybe a
Just ByteString
sig)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", forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ UTCTime -> ByteString
fmtAmzTime UTCTime
time)
            AbsoluteExpires   UTCTime
time -> (ByteString
"Expires"  , forall a. a -> Maybe a
Just 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Monoid a => [a] -> a
mconcat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> [a] -> [a]
intersperse Builder
newline forall a b. (a -> b) -> a -> b
$
                            forall a b. (a -> b) -> [a] -> [b]
map ByteString -> Builder
Blaze.copyByteString
                                [Method -> ByteString
httpMethod Method
iamHttpMethod, ByteString
iamEndpoint, ByteString
"/"]
                            forall a. [a] -> [a] -> [a]
++  [Bool -> [(ByteString, Maybe ByteString)] -> Builder
HTTP.renderQueryBuilder Bool
False [(ByteString, Maybe ByteString)]
expandedQuery]
      expandedQuery :: [(ByteString, Maybe ByteString)]
expandedQuery   = forall a. QueryLike a => a -> [(ByteString, Maybe ByteString)]
HTTP.toQuery forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Ord a => [a] -> [a]
sort forall a b. (a -> b) -> a -> b
$ (forall a b. (a -> b) -> [a] -> [b]
map (\(ByteString
a,ByteString
b) -> (ByteString
a, forall a. a -> Maybe a
Just ByteString
b)) [(ByteString, ByteString)]
q forall a. [a] -> [a] -> [a]
++) [
                            (ByteString
"AWSAccessKeyId"  , forall a. a -> Maybe a
Just ByteString
accessKey)
                          , (ByteString
"SignatureMethod" , forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ AuthorizationHash -> ByteString
amzHash AuthorizationHash
HmacSHA256)
                          , (ByteString
"SignatureVersion", forall a. a -> Maybe a
Just ByteString
"2")
                          , (ByteString
"Version"         , forall a. a -> Maybe a
Just ByteString
"2010-05-08")
                          , (ByteString, Maybe ByteString)
timestampHeader] forall a. [a] -> [a] -> [a]
++
                          forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] (\ByteString
tok -> [ (ByteString
"SecurityToken", 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 = 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 = forall a. [a] -> Maybe a
listToMaybe forall a b. (a -> b) -> a -> b
$ Cursor
cursor forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$// Text -> Cursor -> [Text]
elContent Text
"RequestID"
      forall m. m -> Response m ()
tellMetadata forall a b. (a -> b) -> a -> b
$ Maybe Text -> IamMetadata
IamMetadata Maybe Text
rid
      case Cursor
cursor forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$// Text -> Axis
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
      Text
errCode <- forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
force String
"Missing Error Code"    forall a b. (a -> b) -> a -> b
$ Cursor
cursor forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$// Text -> Cursor -> [Text]
elContent Text
"Code"
      Text
errMsg  <- forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
force String
"Missing Error Message" forall a b. (a -> b) -> a -> b
$ Cursor
cursor forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$// Text -> Cursor -> [Text]
elContent Text
"Message"
      forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM forall a b. (a -> b) -> a -> b
$ Status -> Text -> Text -> IamError
IamError (forall body. Response body -> Status
HTTP.responseStatus Response (ConduitM () ByteString (ResourceT IO) ())
resp) Text
errCode Text
errMsg

-- | Parses IAM @DateTime@ data type.
parseDateTime :: MonadThrow m => String -> m UTCTime
parseDateTime :: forall (m :: * -> *). MonadThrow m => String -> m UTCTime
parseDateTime String
x
    = case 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 -> forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM forall a b. (a -> b) -> a -> b
$ String -> XmlException
XmlException forall a b. (a -> b) -> a -> b
$ String
"Invalid DateTime: " forall a. [a] -> [a] -> [a]
++ String
x
        Just UTCTime
dt -> 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
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: User -> User -> Bool
$c/= :: User -> User -> Bool
== :: User -> User -> Bool
$c== :: User -> User -> Bool
Eq, Eq 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
min :: User -> User -> User
$cmin :: User -> User -> User
max :: User -> User -> User
$cmax :: User -> User -> User
>= :: User -> User -> Bool
$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
compare :: User -> User -> Ordering
$ccompare :: User -> User -> Ordering
Ord, Int -> User -> ShowS
[User] -> ShowS
User -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [User] -> ShowS
$cshowList :: [User] -> ShowS
show :: User -> String
$cshow :: User -> String
showsPrec :: Int -> User -> ShowS
$cshowsPrec :: Int -> 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
    Text
userArn        <- Text -> m Text
attr Text
"Arn"
    UTCTime
userCreateDate <- Text -> m Text
attr Text
"CreateDate" forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *). MonadThrow m => String -> m UTCTime
parseDateTime forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
Text.unpack
    Text
userPath       <- Text -> m Text
attr Text
"Path"
    Text
userUserId     <- Text -> m Text
attr Text
"UserId"
    Text
userUserName   <- Text -> m Text
attr Text
"UserName"
    forall (m :: * -> *) a. Monad m => a -> m a
return User{UTCTime
Text
userUserName :: Text
userUserId :: Text
userPath :: Text
userCreateDate :: UTCTime
userArn :: Text
userUserName :: Text
userUserId :: Text
userPath :: Text
userCreateDate :: UTCTime
userArn :: Text
..}
  where
    attr :: Text -> m Text
attr Text
name = forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
force (String
"Missing " forall a. [a] -> [a] -> [a]
++ Text -> String
Text.unpack Text
name) forall a b. (a -> b) -> a -> b
$
                Cursor
cursor 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
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Group -> Group -> Bool
$c/= :: Group -> Group -> Bool
== :: Group -> Group -> Bool
$c== :: Group -> Group -> Bool
Eq, Eq 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
min :: Group -> Group -> Group
$cmin :: Group -> Group -> Group
max :: Group -> Group -> Group
$cmax :: Group -> Group -> Group
>= :: Group -> Group -> Bool
$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
compare :: Group -> Group -> Ordering
$ccompare :: Group -> Group -> Ordering
Ord, Int -> Group -> ShowS
[Group] -> ShowS
Group -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Group] -> ShowS
$cshowList :: [Group] -> ShowS
show :: Group -> String
$cshow :: Group -> String
showsPrec :: Int -> Group -> ShowS
$cshowsPrec :: Int -> 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
    Text
groupArn        <- Text -> m Text
attr Text
"Arn"
    UTCTime
groupCreateDate <- Text -> m Text
attr Text
"CreateDate" forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *). MonadThrow m => String -> m UTCTime
parseDateTime forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
Text.unpack
    Text
groupPath       <- Text -> m Text
attr Text
"Path"
    Text
groupGroupId     <- Text -> m Text
attr Text
"GroupId"
    Text
groupGroupName   <- Text -> m Text
attr Text
"GroupName"
    forall (m :: * -> *) a. Monad m => a -> m a
return Group{UTCTime
Text
groupGroupName :: Text
groupGroupId :: Text
groupPath :: Text
groupCreateDate :: UTCTime
groupArn :: Text
groupGroupName :: Text
groupGroupId :: Text
groupPath :: Text
groupCreateDate :: UTCTime
groupArn :: Text
..}
  where
    attr :: Text -> m Text
attr Text
name = forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
force (String
"Missing " forall a. [a] -> [a] -> [a]
++ Text -> String
Text.unpack Text
name) forall a b. (a -> b) -> a -> b
$
                Cursor
cursor forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$// Text -> Cursor -> [Text]
elContent Text
name


data AccessKeyStatus = AccessKeyActive | AccessKeyInactive
    deriving (AccessKeyStatus -> AccessKeyStatus -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AccessKeyStatus -> AccessKeyStatus -> Bool
$c/= :: AccessKeyStatus -> AccessKeyStatus -> Bool
== :: AccessKeyStatus -> AccessKeyStatus -> Bool
$c== :: AccessKeyStatus -> AccessKeyStatus -> Bool
Eq, Eq 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
min :: AccessKeyStatus -> AccessKeyStatus -> AccessKeyStatus
$cmin :: AccessKeyStatus -> AccessKeyStatus -> AccessKeyStatus
max :: AccessKeyStatus -> AccessKeyStatus -> AccessKeyStatus
$cmax :: AccessKeyStatus -> AccessKeyStatus -> AccessKeyStatus
>= :: AccessKeyStatus -> AccessKeyStatus -> Bool
$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
compare :: AccessKeyStatus -> AccessKeyStatus -> Ordering
$ccompare :: AccessKeyStatus -> AccessKeyStatus -> Ordering
Ord, Int -> AccessKeyStatus -> ShowS
[AccessKeyStatus] -> ShowS
AccessKeyStatus -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AccessKeyStatus] -> ShowS
$cshowList :: [AccessKeyStatus] -> ShowS
show :: AccessKeyStatus -> String
$cshow :: AccessKeyStatus -> String
showsPrec :: Int -> AccessKeyStatus -> ShowS
$cshowsPrec :: Int -> 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
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: MfaDevice -> MfaDevice -> Bool
$c/= :: MfaDevice -> MfaDevice -> Bool
== :: MfaDevice -> MfaDevice -> Bool
$c== :: MfaDevice -> MfaDevice -> Bool
Eq, Eq 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
min :: MfaDevice -> MfaDevice -> MfaDevice
$cmin :: MfaDevice -> MfaDevice -> MfaDevice
max :: MfaDevice -> MfaDevice -> MfaDevice
$cmax :: MfaDevice -> MfaDevice -> MfaDevice
>= :: MfaDevice -> MfaDevice -> Bool
$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
compare :: MfaDevice -> MfaDevice -> Ordering
$ccompare :: MfaDevice -> MfaDevice -> Ordering
Ord, Int -> MfaDevice -> ShowS
[MfaDevice] -> ShowS
MfaDevice -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [MfaDevice] -> ShowS
$cshowList :: [MfaDevice] -> ShowS
show :: MfaDevice -> String
$cshow :: MfaDevice -> String
showsPrec :: Int -> MfaDevice -> ShowS
$cshowsPrec :: Int -> 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
  UTCTime
mfaEnableDate   <- Text -> m Text
attr Text
"EnableDate" forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *). MonadThrow m => String -> m UTCTime
parseDateTime forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
Text.unpack
  Text
mfaSerialNumber <- Text -> m Text
attr Text
"SerialNumber"
  Text
mfaUserName     <- Text -> m Text
attr Text
"UserName"
  forall (m :: * -> *) a. Monad m => a -> m a
return MfaDevice{UTCTime
Text
mfaUserName :: Text
mfaSerialNumber :: Text
mfaEnableDate :: UTCTime
mfaUserName :: Text
mfaSerialNumber :: Text
mfaEnableDate :: UTCTime
..}
 where attr :: Text -> m Text
attr Text
name = forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
force (String
"Missing " forall a. [a] -> [a] -> [a]
++ Text -> String
Text.unpack Text
name) forall a b. (a -> b) -> a -> b
$
               Cursor
cursor forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$// Text -> Cursor -> [Text]
elContent Text
name