google-oauth2-jwt 0.1.2.0 → 0.1.2.1
raw patch · 2 files changed
+63/−63 lines, 2 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- google-oauth2-jwt.cabal +14/−14
- src/Network/Google/OAuth2/JWT.hs +49/−49
google-oauth2-jwt.cabal view
@@ -1,30 +1,30 @@ name: google-oauth2-jwt-version: 0.1.2.0+version: 0.1.2.1 synopsis: Get a signed JWT for Google Service Accounts description: Please see README.md homepage: https://github.com/MichelBoucey/google-oauth2-jwt license: BSD3 license-file: LICENSE author: Michel Boucey-maintainer: michel.boucey@gmail.com-copyright: Copyright (c) 2016 - Michel Boucey+maintainer: michel.boucey@cybervisible.fr+copyright: (c) 2016 - Michel Boucey category: Google build-type: Simple extra-source-files: README.md cabal-version: >= 1.10 library- hs-source-dirs: src- exposed-modules: Network.Google.OAuth2.JWT- build-depends: base >= 4.7 && < 5- , base64-bytestring >= 1.0.0.1- , bytestring >= 0.10.6.0- , HsOpenSSL >= 0.11.1.1- , RSA >= 2.2.0- , text >= 1.2.2.0- , unix-time >= 0.3.6- default-language: Haskell2010- GHC-options: -Wall+ hs-source-dirs: src+ exposed-modules: Network.Google.OAuth2.JWT+ build-depends: base >= 4.7 && < 5+ , base64-bytestring >= 1.0.0.1+ , bytestring >= 0.10.6.0+ , HsOpenSSL >= 0.11.1.1+ , RSA >= 2.2.0+ , text >= 1.2.2.0+ , unix-time >= 0.3.6+ default-language: Haskell2010+ GHC-options: -Wall source-repository head type: git
src/Network/Google/OAuth2/JWT.hs view
@@ -3,7 +3,7 @@ -- | Create a signed JWT needed to make the access token request -- to gain access to Google APIs for server to server applications. ----- For all details : https://developers.google.com/identity/protocols/OAuth2ServiceAccount+-- For all usage details, see https://developers.google.com/identity/protocols/OAuth2ServiceAccount -- module Network.Google.OAuth2.JWT@@ -49,20 +49,21 @@ -- > fromPEMString :: String -> IO PrivateKey fromPEMString s =- fromJust . toKeyPair <$> readPrivateKey s PwNone- >>= \k -> return PrivateKey- { private_pub =- 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- , private_dP = 0- , private_dQ = 0- , private_qinv = 0- }+ fromJust . toKeyPair <$> readPrivateKey s PwNone >>=+ \k -> return+ PrivateKey+ { private_pub =+ 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+ , private_dP = 0+ , private_dQ = 0+ , private_qinv = 0+ } -- | Create the signed JWT ready for transmission -- in the access token request as assertion value.@@ -70,43 +71,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.+ -- ^ 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 iss msub scopes met privateKey = do- let et = fromIntegral $ fromMaybe 3600 met- if et < 1 || et > 3600- then return $ Left "Bad expiration time"- else do- cs <- jwtClaimsSet- (maybe T.empty (\s -> "\"sub\":\"" <> s <> "\",") msub) et- let i = toJWT "{\"alg\":\"RS256\",\"typ\":\"JWT\"}" <> "." <> cs- return $- case rsassa_pkcs1_v1_5_sign hashSHA256 privateKey (fromStrict i) of- Right s -> Right $ i <> "." <> encode (toStrict s)- Left _ -> Left "RSAError"+ let et = fromIntegral $ fromMaybe 3600 met+ if et >= 1 && et <= 3600+ then do+ cs <-+ jwtClaimsSet+ (maybe T.empty (\s -> "\"sub\":\"" <> s <> "\",") msub) et+ let i = toJWT "{\"alg\":\"RS256\",\"typ\":\"JWT\"}" <> "." <> cs+ return $+ case rsassa_pkcs1_v1_5_sign hashSHA256 privateKey (fromStrict i) of+ Right s -> Right (i <> "." <> encode (toStrict s))+ Left _ -> Left "RSAError"+ else fail "Bad expiration time" where jwtClaimsSet s e = do- (exp',iat') <-- getUnixTime >>= \t ->- return ( toText $ utSeconds t + CTime e- , toText $ utSeconds t- )- return $ toJWT $- "{\"iss\":\"" <> iss <> "\"," <> s <> "\"scope\":\""- <> T.intercalate " " scopes <> "\",\"aud\":\"https://ww\- \w.googleapis.com/oauth2/v4/token\",\"exp\":" <> exp'- <> ",\"iat\":" <> iat' <> "}"+ (exp',iat') <- getUnixTime >>=+ \t -> return (toText (utSeconds t + CTime e),toText (utSeconds t))+ return $+ toJWT $+ "{\"iss\":\"" <> iss <> "\"," <> s <> "\"scope\":\""+ <> T.intercalate " " scopes <> "\",\"aud\":\"https:\+ \//www.googleapis.com/oauth2/v4/token\",\"exp\":" <>+ exp' <> ",\"iat\":" <> iat' <> "}" toText = T.pack . show toJWT = encode . encodeUtf8