packages feed

google-oauth2-jwt 0.1.3 → 0.2.0

raw patch · 3 files changed

+60/−52 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Network.Google.OAuth2.JWT: instance GHC.Classes.Eq Network.Google.OAuth2.JWT.SignedJWT
+ Network.Google.OAuth2.JWT: instance GHC.Show.Show Network.Google.OAuth2.JWT.SignedJWT
- Network.Google.OAuth2.JWT: getSignedJWT :: Email -> Maybe Email -> [Scope] -> Maybe Int -> PrivateKey -> IO (Either String ByteString)
+ Network.Google.OAuth2.JWT: getSignedJWT :: Email -> Maybe Email -> [Scope] -> Maybe Int -> PrivateKey -> IO (Either String SignedJWT)

Files

LICENSE view
@@ -1,4 +1,4 @@-google-oauth2-jwt - Copyright Michel Boucey (c) 2016+google-oauth2-jwt - Copyright Michel Boucey (c) 2016-2017  All rights reserved. 
google-oauth2-jwt.cabal view
@@ -1,13 +1,14 @@ name:                google-oauth2-jwt-version:             0.1.3+version:             0.2.0 synopsis:            Get a signed JWT for Google Service Accounts-description:         Please see README.md+description:         This library implements the creation of the+                     signed JWT for Google Service Accounts. homepage:            https://github.com/MichelBoucey/google-oauth2-jwt license:             BSD3 license-file:        LICENSE author:              Michel Boucey maintainer:          michel.boucey@cybervisible.fr-copyright:           (c) 2016 - Michel Boucey+copyright:           (c) 2016-2017 - Michel Boucey category:            Google build-type:          Simple extra-source-files:  README.md@@ -16,13 +17,13 @@ library   hs-source-dirs:   src   exposed-modules:  Network.Google.OAuth2.JWT-  build-depends:    base >= 4.7 && < 5-                  , base64-bytestring   >= 1.0.0 && < 1.1-                  , bytestring          >= 0.10.6 && < 0.11+  build-depends:    base                >= 4.7      && < 5+                  , base64-bytestring   >= 1.0.0    && < 1.1+                  , bytestring          >= 0.10.6   && < 0.11                   , HsOpenSSL           >= 0.11.1.1 && < 0.12-                  , RSA                 >= 2.1.0.3 && < 2.3-                  , text                >= 1.2.2 && < 1.3-                  , unix-time           >= 0.3.6 && < 0.4+                  , RSA                 >= 2.1.0.3  && < 2.3+                  , text                >= 1.2.2    && < 1.3+                  , unix-time           >= 0.3.6    && < 0.4    default-language: Haskell2010   GHC-options:      -Wall
src/Network/Google/OAuth2/JWT.hs view
@@ -19,13 +19,14 @@     ) where  import           Codec.Crypto.RSA.Pure+import           Control.Monad              (unless) import qualified Data.ByteString            as B import           Data.ByteString.Base64.URL (encode) import           Data.ByteString.Lazy       (fromStrict, toStrict) import           Data.Maybe                 (fromMaybe, fromJust) import           Data.Monoid                ((<>)) import qualified Data.Text                  as T-import           Data.Text.Encoding+import           Data.Text.Encoding         (encodeUtf8) import           Data.UnixTime              (getUnixTime, utSeconds) import           Foreign.C.Types import           OpenSSL.EVP.PKey           (toKeyPair)@@ -33,19 +34,23 @@                                              readPrivateKey) import           OpenSSL.RSA -type Scope = T.Text+data SignedJWT =+  SignedJWT !B.ByteString+  deriving (Eq, Show)  type Email = T.Text +type Scope = T.Text+ -- | Get the private key obtained from the--- the Google API Console from a PEM file.+-- Google API Console from a PEM file. fromPEMFile :: FilePath -> IO PrivateKey fromPEMFile f = readFile f >>= fromPEMString  -- | Get the private key obtained from the -- Google API Console from a PEM 'String'. ----- >fromPEMString "-----BEGIN PRIVATE KEY-----\nB9e ... bMdF\n-----END PRIVATE KEY-----\n"+-- >fromPEMString "-----BEGIN PRIVATE KEY-----\nB9e [...] bMdF\n-----END PRIVATE KEY-----\n" -- > fromPEMString :: String -> IO PrivateKey fromPEMString s =@@ -53,10 +58,11 @@     \k -> return       PrivateKey         { private_pub =-            PublicKey { public_size = rsaSize k-                      , public_n    = rsaN k-                      , public_e    = rsaE k-                      }+            PublicKey+              { public_size = rsaSize k+              , public_n    = rsaN k+              , public_e    = rsaE k+              }         , private_d    = rsaD k         , private_p    = rsaP k         , private_q    = rsaQ k@@ -70,41 +76,42 @@ -- -- >grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion= ---getSignedJWT :: Email-             -- ^ The email address of the service account.-             -> Maybe Email-             -- ^ The email address of the user for which the-             -- application is requesting delegated access.-             -> [Scope]-             -- ^ The list of the permissions that the application requests.-             -> Maybe Int-             -- ^ Expiration time (maximun and default value is an hour, 3600).-             -> PrivateKey-             -- ^ The private key gotten from the PEM string obtained from the-             -- Google API Console.-             -> IO (Either String B.ByteString)-             -- ^ Either an error message or a signed JWT.+getSignedJWT+  :: Email+  -- ^ The email address of the service account.+  -> Maybe Email+  -- ^ The email address of the user for which the+  -- application is requesting delegated access.+  -> [Scope]+  -- ^ The list of the permissions that the application requests.+  -> Maybe Int+  -- ^ Expiration time (maximun and default value is an hour, 3600).+  -> PrivateKey+  -- ^ The private key gotten from the PEM string obtained from the+  -- Google API Console.+  -> IO (Either String SignedJWT)+  -- ^ Either an error message or a signed JWT. getSignedJWT iss msub scs mxt pk = do   let xt = fromIntegral (fromMaybe 3600 mxt)-  if xt >= 1 && xt <= 3600-    then do-      cs <- do-        let s = maybe T.empty (\e -> "\"sub\":\"" <> e <> "\",") msub-        (t',xt') <- getUnixTime >>=-          \t -> return (toText (utSeconds t),toText (utSeconds t + CTime xt))-        return $-          toJWT $-            "{\"iss\":\"" <> iss <> "\"," <> s <> "\"scope\":\"" <>-            T.intercalate " " scs <> "\",\"aud\":\"https://www.goo\-            \gleapis.com/oauth2/v4/token\",\"exp\":" <> xt' <> ",\"\-            \iat\":" <> t' <> "}"-      let i = toJWT "{\"alg\":\"RS256\",\"typ\":\"JWT\"}" <> "." <> cs-      return $-        case rsassa_pkcs1_v1_5_sign hashSHA256 pk (fromStrict i) of-          Right s -> Right (i <> "." <> encode (toStrict s))-          Left _  -> Left "RSAError"-    else fail "Bad expiration time"+  unless (xt >= 1 && xt <= 3600) (fail "Bad expiration time")+  t <- getUnixTime+  let i = header <> "." <> toB64 ("{\"iss\":\"" <> iss <> "\","+          <> maybe T.empty (\e -> "\"sub\":\"" <> e <> "\",") msub+          <> "\"scope\":\"" <> T.intercalate " " scs <> "\",\"aud\+          \\":\"https://www.googleapis.com/oauth2/v4/token\",\"ex\+          \p\":" <> toT (utSeconds t + CTime xt) <> ",\"iat\":"+          <> toT (utSeconds t) <> "}")+  return $+    either+      (fail "RSAError")+      (\s -> return $ SignedJWT $ i <> "." <> encode (toStrict s))+      (rsassa_pkcs1_v1_5_sign hashSHA256 pk $ fromStrict i)   where-    toText = T.pack . show-    toJWT = encode . encodeUtf8+    toT = T.pack . show++header :: B.ByteString+header = toB64 "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"++toB64 :: T.Text -> B.ByteString+toB64 = encode . encodeUtf8