packages feed

wai-middleware-hmac-client (empty) → 0.1.0.0

raw patch · 4 files changed

+280/−0 lines, 4 filesdep +basedep +base64-bytestringdep +byteablesetup-changed

Dependencies added: base, base64-bytestring, byteable, bytestring, case-insensitive, cryptohash, http-client, http-types, mtl, old-locale, time, transformers, word8

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2015, Christopher Reichert++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Christopher Reichert nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Network/Wai/Middleware/HmacAuth/Client.hs view
@@ -0,0 +1,200 @@+-------------------------------------------------------------------------+-- |+-- Module      : Network.Wai.Middleware.HmacAuth.Client+-- Description : Wai HMAC Auth Middleware Client+-- Copyright   : (c) 2015 Christopher Reichert+-- License     : BSD3+-- Maintainer  : Christopher Reichert <creichert07@gmail.com>+-- Stability   : experimental+-- Portability : POSIX+--+-- Compatible with HTTP Client+++{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE RankNTypes          #-}+{-# LANGUAGE RecordWildCards     #-}+{-# LANGUAGE ScopedTypeVariables #-}+++module Network.Wai.Middleware.HmacAuth.Client+       (+         -- * Sign a 'Request' with HMAC+         applyHmacAuth++         -- * Settings+         --+         -- These correspond to the 'HmacAuthSettings' found+         -- in 'Network.WAI.Middleware.HmacAuth' with slightly+         -- less options. These should correlate when deploying.+         -- The 'defaultHmacAuthSettings' in both modules should+         -- be ready-to-use together.+       , defaultHmacAuthSettings+       , HmacAuthSettings (..)+       ) where++++import           Control.Monad.IO.Class (MonadIO, liftIO)+import           Crypto.Hash+import           Crypto.Hash.MD5        as MD5+import           Data.Byteable          (toBytes)+import           Data.ByteString        (ByteString)+import qualified Data.ByteString.Base64 as BS64+import qualified Data.ByteString.Char8  as BS+import qualified Data.ByteString.Lazy   as B+import           Data.CaseInsensitive   (CI)+import           Data.Maybe             (fromMaybe)+import           Data.Monoid            ((<>))+import           Data.Time+import           Network.HTTP.Client+import qualified Network.HTTP.Types     as Http+import           System.Locale+++++-- | Various control settings for HMAC authentication+data HmacAuthSettings alg = HmacAuthSettings+    {+      authKeyHeader       :: !(CI ByteString)+    , authTimestampHeader :: !(CI ByteString)++      -- | HMAC signing algorithm+      --+      -- MD5, SHA1, SHA256, and SHA512 supported+    , authAlgorithm       :: alg++      -- | Realm provider.+      --+      -- e.g. Authorization: API key:signature+    , authRealm           :: !ByteString++      -- | Use Header or QueryParam spec.+      --+      -- Currently, only the @Header@ @Strategy@ is supported+    , authSpec            :: !Strategy+    }++++data Strategy = Header+              -- ^ Use HTTP Header to authorize clients+              --- | Query+              --- ^ TODO Use query parameters (not yet supported)++++type Secret = ByteString+type Key    = ByteString++++-- | default HMAC client settings+defaultHmacAuthSettings :: HmacAuthSettings SHA512+defaultHmacAuthSettings = HmacAuthSettings+    { authRealm           = "Hmac"+    , authKeyHeader       = "X-auth-key"+    , authTimestampHeader = "X-auth-timestamp"+    , authSpec            = Header+    , authAlgorithm       = SHA512+    }++++-- | Add an Hmac auth header, signed with the specified secret, to the+-- given Request. Ignore error handling:+--+-- > applyHmacAuth defaultHmacSettings "secret" $ fromJust $ parseUrl url+--+-- Since 0.1.0+applyHmacAuth :: forall m alg .+                 (+                   MonadIO m+                 , HashAlgorithm alg )+                 => HmacAuthSettings alg+                 -> Key+                 -> Secret+                 -> Request+                 -> m Request+applyHmacAuth cfg@HmacAuthSettings{..} key secret req = do++    now <- liftIO getCurrentTime++    let date                = timefmt now+        contentmd5          = MD5.hash $ B.toStrict body+        res                 = canonicalizedResource req+        payload             = buildMessage verb contentmd5 (ctype req) date res+        HMAC hashed         = signPayload secret payload+        digest              = BS64.encode (toBytes hashed)++    return $ req { requestHeaders =+                      [ (authTimestampHeader, date)+                      , (authKeyHeader, key)+                      , authHeader cfg key digest+                      ] <> requestHeaders req+                 }+  where+    signPayload :: Secret -> ByteString -> HMAC alg+    signPayload = hmac+    timefmt     = BS.pack . formatTime defaultTimeLocale "%FT%T"+    verb        = method req+    ctype       = fromMaybe "" . lookup Http.hContentType . requestHeaders+    body        = case requestBody req of+                    RequestBodyLBS lbs -> lbs+                    RequestBodyBS  bs  -> B.fromStrict bs+                    _                  -> error "RequestBody type Not Supported"+++++-----------------------------------------------------------------------------+-----------------------------------------------------------------------------++++-- | Create HTTP Authorization header for the give key and signature.+authHeader :: HmacAuthSettings alg+              -> Key+              -> Secret+              -> (CI ByteString, ByteString)+authHeader HmacAuthSettings{..} key sig =+    let auth = BS.concat [ authRealm, " ", key, ":", sig ]+    in ("Authorization", auth)+++++-- | Prepare a string to be HMAC signed.+--+-- @+-- stringtosign = http-method  + "\n" ++-- 	          content md5  + "\n" ++-- 	          content-type + "\n" ++-- 	          date         + "\n" ++-- 	          canonicalizedUri;+-- @+--+buildMessage+  :: Http.Method    -- ^ HTTP Method+     -> ByteString  -- ^ md5 Checksum of the request body+     -> ByteString  -- ^ Content-Type+     -> ByteString  -- ^ Date header of the HTTP request+     -> ByteString  -- ^ Canonicalized request location+     -> ByteString  -- ^ Return the unencoded string to sign+buildMessage verb contentmd5 ctype date resource =+    BS.concat [ verb, "\n"+              , contentmd5, "\n"+              , ctype, "\n"+              , date, "\n"+              , resource+              ]++++-- | Canonicalization of the request uri+--+-- http-request uri from the protocol name up to the query string.+-- TODO add the query string to the canonicalized resource?+canonicalizedResource :: Request -> ByteString+canonicalizedResource = path
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ wai-middleware-hmac-client.cabal view
@@ -0,0 +1,48 @@++name:                wai-middleware-hmac-client+version:             0.1.0.0+license:             BSD3+license-file:        LICENSE+author:              Christopher Reichert+maintainer:          creichert07@gmail.com+copyright:           (c) 2015, Christopher Reichert+category:            Web+build-type:          Simple+cabal-version:       >=1.10+homepage:            https://github.com/creichert/wai-middleware-hmac+synopsis:            Wai HMAC Authentication Middleware Client+description:+   .+   Ready to use client module for wai-middleware-hmac. This module is+   built on http-client but is in the Wai namespace since the protocol+   is somewhat specific. Although this implementation does follow the+   RFC as closely as possible as well as Amazon AWS's implementation.+   Howeber, since nothing is formally specified these modules are+   specifically built for each other Because of this, we also try to+   maintain a slim dependency profile.  Because of the compatibility+   with http-client you can still build into a streaming module if+   needed+++source-repository head+  type:     git+  location: git://github.com/creichert/wai-middleware-hmac-client+++library+  exposed-modules:     Network.Wai.Middleware.HmacAuth.Client+  default-language:    Haskell2010+  ghc-options:         -Wall -fno-warn-unused-binds+  build-depends:       base == 4.*+                     , bytestring        >= 0.10+                     , http-types        >= 0.8+                     , http-client+                     , base64-bytestring >= 1.0+                     , word8             >= 0.1+                     , case-insensitive+                     , cryptohash+                     , byteable+                     , mtl+                     , time+                     , old-locale+                     , transformers