yesod-auth-oauth2 0.6.1.7 → 0.6.2.0
raw patch · 5 files changed
+187/−114 lines, 5 filesdep ~aesondep ~aeson-prettydep ~bytestringPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: aeson, aeson-pretty, bytestring, containers, cryptonite, errors, hspec, http-conduit, load-env, memory, microlens, safe-exceptions, text, uri-bytestring, warp, yesod, yesod-auth
API changes (from Hackage documentation)
+ Yesod.Auth.OAuth2.ClassLink: instance Data.Aeson.Types.FromJSON.FromJSON Yesod.Auth.OAuth2.ClassLink.User
+ Yesod.Auth.OAuth2.ClassLink: oauth2ClassLink :: YesodAuth m => Text -> Text -> AuthPlugin m
+ Yesod.Auth.OAuth2.ClassLink: oauth2ClassLinkScoped :: YesodAuth m => [Text] -> Text -> Text -> AuthPlugin m
Files
- CHANGELOG.md +12/−1
- example/Main.hs +7/−6
- src/Yesod/Auth/OAuth2/ClassLink.hs +51/−0
- src/Yesod/Auth/OAuth2/Dispatch.hs +21/−4
- yesod-auth-oauth2.cabal +96/−103
CHANGELOG.md view
@@ -1,6 +1,17 @@-## [*Unreleased*](https://github.com/thoughtbot/yesod-auth-oauth2/compare/v0.6.1.7...master)+## [*Unreleased*](https://github.com/thoughtbot/yesod-auth-oauth2/compare/v0.6.2.0...master) None++## [v0.6.2.0](https://github.com/thoughtbot/yesod-auth-oauth2/compare/v0.6.1.7...v0.6.2.0)++- Filter `+` from `state` tokens++ This decreases entropy in the token slightly, but ensures that providers+ performing unexpected +/space/%20 encoding (e.g. ClassLink) still function.++ See [#140](https://github.com/thoughtbot/yesod-auth-oauth2/pull/140).++- Add ClassLink provider ## [v0.6.1.7](https://github.com/thoughtbot/yesod-auth-oauth2/compare/v0.6.1.6...v0.6.1.7)
example/Main.hs view
@@ -38,6 +38,7 @@ import Yesod.Auth.OAuth2.AzureAD import Yesod.Auth.OAuth2.BattleNet import Yesod.Auth.OAuth2.Bitbucket+import Yesod.Auth.OAuth2.ClassLink import Yesod.Auth.OAuth2.EveOnline import Yesod.Auth.OAuth2.GitHub import Yesod.Auth.OAuth2.GitLab@@ -46,8 +47,8 @@ import Yesod.Auth.OAuth2.Salesforce import Yesod.Auth.OAuth2.Slack import Yesod.Auth.OAuth2.Spotify-import Yesod.Auth.OAuth2.WordPressDotCom import Yesod.Auth.OAuth2.Upcase+import Yesod.Auth.OAuth2.WordPressDotCom data App = App { appHttpManager :: Manager@@ -73,10 +74,9 @@ -- Copy the Creds response into the session for viewing after authenticate c = do- mapM_ (uncurry setSession) $- [ ("credsIdent", credsIdent c)- , ("credsPlugin", credsPlugin c)- ] ++ credsExtra c+ mapM_ (uncurry setSession)+ $ [("credsIdent", credsIdent c), ("credsPlugin", credsPlugin c)]+ ++ credsExtra c return $ Authenticated "1" @@ -138,6 +138,7 @@ [ loadPlugin oauth2AzureAD "AZURE_AD" , loadPlugin (oauth2BattleNet [whamlet|TODO|] "en") "BATTLE_NET" , loadPlugin oauth2Bitbucket "BITBUCKET"+ , loadPlugin oauth2ClassLink "CLASSLINK" , loadPlugin (oauth2Eve Plain) "EVE_ONLINE" , loadPlugin oauth2GitHub "GITHUB" , loadPlugin oauth2GitLab "GITLAB"@@ -150,7 +151,7 @@ , loadPlugin oauth2Upcase "UPCASE" ] - return App {..}+ return App { .. } where loadPlugin f prefix = do clientId <- getEnv $ prefix <> "_CLIENT_ID"
+ src/Yesod/Auth/OAuth2/ClassLink.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE OverloadedStrings #-}++module Yesod.Auth.OAuth2.ClassLink+ ( oauth2ClassLink+ , oauth2ClassLinkScoped+ )+where++import Yesod.Auth.OAuth2.Prelude++import qualified Data.Text as T++newtype User = User Int++instance FromJSON User where+ parseJSON = withObject "User" $ \o -> User <$> o .: "UserId"++pluginName :: Text+pluginName = "classlink"++defaultScopes :: [Text]+defaultScopes = ["profile", "oneroster"]++oauth2ClassLink :: YesodAuth m => Text -> Text -> AuthPlugin m+oauth2ClassLink = oauth2ClassLinkScoped defaultScopes++oauth2ClassLinkScoped :: YesodAuth m => [Text] -> Text -> Text -> AuthPlugin m+oauth2ClassLinkScoped scopes clientId clientSecret =+ authOAuth2 pluginName oauth2 $ \manager token -> do+ (User userId, userResponse) <- authGetProfile+ pluginName+ manager+ token+ "https://nodeapi.classlink.com/v2/my/info"++ pure Creds+ { credsPlugin = pluginName+ , credsIdent = T.pack $ show userId+ , credsExtra = setExtra token userResponse+ }+ where+ oauth2 = OAuth2+ { oauthClientId = clientId+ , oauthClientSecret = Just clientSecret+ , oauthOAuthorizeEndpoint =+ "https://launchpad.classlink.com/oauth2/v2/auth"+ `withQuery` [scopeParam "," scopes]+ , oauthAccessTokenEndpoint =+ "https://launchpad.classlink.com/oauth2/v2/token"+ , oauthCallback = Nothing+ }
src/Yesod/Auth/OAuth2/Dispatch.hs view
@@ -156,14 +156,25 @@ getParentUrlRender :: MonadHandler m => m (Route (SubHandlerSite m) -> Text) getParentUrlRender = (.) <$> getUrlRender <*> getRouteToParent --- | Set a random, 30-character value in the session+-- | Set a random, ~30-character value in the session+--+-- Some (but not all) providers decode a @+@ in the state token as a space when+-- sending it back to us. We don't expect this and fail. And if we did code for+-- it, we'd then fail on the providers that /don't/ do that.+--+-- Therefore, we just exclude @+@ in our tokens, which means this function may+-- return slightly less than 30 characters.+-- setSessionCSRF :: MonadHandler m => Text -> m Text setSessionCSRF sessionKey = do csrfToken <- liftIO randomToken csrfToken <$ setSession sessionKey csrfToken where randomToken =- decodeUtf8 . convertToBase @ByteString Base64 <$> getRandomBytes 64+ T.filter (/= '+')+ . decodeUtf8+ . convertToBase @ByteString Base64+ <$> getRandomBytes 64 -- | Verify the callback provided the same CSRF token as in our session verifySessionCSRF :: MonadHandler m => Text -> m Text@@ -172,8 +183,14 @@ sessionToken <- lookupSession sessionKey deleteSession sessionKey - unless (sessionToken == Just token)- $ permissionDenied "Invalid OAuth2 state token"+ unless (sessionToken == Just token) $ do+ $(logError)+ $ "state token does not match. "+ <> "Param: "+ <> tshow token+ <> "State: "+ <> tshow sessionToken+ permissionDenied "Invalid OAuth2 state token" return token
yesod-auth-oauth2.cabal view
@@ -1,117 +1,110 @@-cabal-version: 1.12---- This file has been generated from package.yaml by hpack version 0.33.0.------ see: https://github.com/sol/hpack------ hash: 426ae261ba0f32722928565c45da419547ef444e7635ac5e9da56872729a0df9+cabal-version: 1.12+name: yesod-auth-oauth2+version: 0.6.2.0+license: MIT+license-file: LICENSE+maintainer: Pat Brisbin <pbrisbin@gmail.com>+author: Tom Streller+homepage: http://github.com/thoughtbot/yesod-auth-oauth2+bug-reports: https://github.com/thoughtbot/yesod-auth-oauth2/issues+synopsis: OAuth 2.0 authentication plugins+description:+ Library to authenticate with OAuth 2.0 for Yesod web applications. -name: yesod-auth-oauth2-version: 0.6.1.7-synopsis: OAuth 2.0 authentication plugins-description: Library to authenticate with OAuth 2.0 for Yesod web applications.-category: Web-homepage: http://github.com/thoughtbot/yesod-auth-oauth2-bug-reports: https://github.com/thoughtbot/yesod-auth-oauth2/issues-author: Tom Streller-maintainer: Pat Brisbin <pbrisbin@gmail.com>-license: MIT-license-file: LICENSE-build-type: Simple+category: Web+build-type: Simple extra-source-files: README.md CHANGELOG.md source-repository head- type: git- location: https://github.com/thoughtbot/yesod-auth-oauth2+ type: git+ location: https://github.com/thoughtbot/yesod-auth-oauth2 flag example- description: Build the example application- manual: False- default: False+ description: Build the example application+ default: False library- exposed-modules:- URI.ByteString.Extension- Yesod.Auth.OAuth2- Yesod.Auth.OAuth2.AzureAD- Yesod.Auth.OAuth2.BattleNet- Yesod.Auth.OAuth2.Bitbucket- Yesod.Auth.OAuth2.Dispatch- Yesod.Auth.OAuth2.ErrorResponse- Yesod.Auth.OAuth2.EveOnline- Yesod.Auth.OAuth2.Exception- Yesod.Auth.OAuth2.GitHub- Yesod.Auth.OAuth2.GitLab- Yesod.Auth.OAuth2.Google- Yesod.Auth.OAuth2.Nylas- Yesod.Auth.OAuth2.Prelude- Yesod.Auth.OAuth2.Salesforce- Yesod.Auth.OAuth2.Slack- Yesod.Auth.OAuth2.Spotify- Yesod.Auth.OAuth2.Upcase- Yesod.Auth.OAuth2.WordPressDotCom- other-modules:- Paths_yesod_auth_oauth2- hs-source-dirs:- src- ghc-options: -Wall- build-depends:- aeson >=0.6 && <1.6- , base >=4.9.0.0 && <5- , bytestring >=0.9.1.4- , cryptonite- , errors- , hoauth2 >=1.11.0 && <1.17- , http-client >=0.4.0 && <0.8- , http-conduit >=2.0 && <3.0- , http-types >=0.8 && <0.13- , memory- , microlens- , safe-exceptions- , text >=0.7 && <2.0- , uri-bytestring- , yesod-auth >=1.6.0 && <1.7- , yesod-core >=1.6.0 && <1.7- default-language: Haskell2010+ exposed-modules:+ URI.ByteString.Extension+ Yesod.Auth.OAuth2+ Yesod.Auth.OAuth2.AzureAD+ Yesod.Auth.OAuth2.BattleNet+ Yesod.Auth.OAuth2.Bitbucket+ Yesod.Auth.OAuth2.ClassLink+ Yesod.Auth.OAuth2.Dispatch+ Yesod.Auth.OAuth2.ErrorResponse+ Yesod.Auth.OAuth2.EveOnline+ Yesod.Auth.OAuth2.Exception+ Yesod.Auth.OAuth2.GitHub+ Yesod.Auth.OAuth2.GitLab+ Yesod.Auth.OAuth2.Google+ Yesod.Auth.OAuth2.Nylas+ Yesod.Auth.OAuth2.Prelude+ Yesod.Auth.OAuth2.Salesforce+ Yesod.Auth.OAuth2.Slack+ Yesod.Auth.OAuth2.Spotify+ Yesod.Auth.OAuth2.Upcase+ Yesod.Auth.OAuth2.WordPressDotCom + hs-source-dirs: src+ other-modules: Paths_yesod_auth_oauth2+ default-language: Haskell2010+ ghc-options: -Wall+ build-depends:+ aeson >=0.6 && <1.6,+ base >=4.9.0.0 && <5,+ bytestring >=0.9.1.4 && <0.11,+ cryptonite >=0.26 && <0.28,+ errors >=2.3.0 && <2.4,+ hoauth2 >=1.11.0 && <1.17,+ http-client >=0.4.0 && <0.8,+ http-conduit >=2.0 && <3.0,+ http-types >=0.8 && <0.13,+ memory >=0.15.0 && <0.16,+ microlens >=0.4.11.2 && <0.5,+ safe-exceptions >=0.1.7.1 && <0.2,+ text >=0.7 && <2.0,+ uri-bytestring >=0.3.3.0 && <0.4,+ yesod-auth >=1.6.0 && <1.7,+ yesod-core >=1.6.0 && <1.7+ executable yesod-auth-oauth2-example- main-is: Main.hs- other-modules:- Paths_yesod_auth_oauth2- hs-source-dirs:- example- ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N- build-depends:- aeson- , aeson-pretty- , base >=4.9.0.0 && <5- , bytestring- , containers- , http-conduit- , load-env- , text- , warp- , yesod- , yesod-auth- , yesod-auth-oauth2- if !(flag(example))- buildable: False- default-language: Haskell2010+ main-is: Main.hs+ hs-source-dirs: example+ other-modules: Paths_yesod_auth_oauth2+ default-language: Haskell2010+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ aeson >=1.4.7.1 && <1.5,+ aeson-pretty >=0.8.8 && <0.9,+ base >=4.9.0.0 && <5,+ bytestring >=0.10.10.1 && <0.11,+ containers >=0.6.2.1 && <0.7,+ http-conduit >=2.3.7.4 && <2.4,+ load-env >=0.2.1.0 && <0.3,+ text >=1.2.4.0 && <1.3,+ warp >=3.3.13 && <3.4,+ yesod >=1.6.1.0 && <1.7,+ yesod-auth >=1.6.10.1 && <1.7,+ yesod-auth-oauth2 -any + if !flag(example)+ buildable: False+ test-suite test- type: exitcode-stdio-1.0- main-is: Spec.hs- other-modules:- URI.ByteString.ExtensionSpec- Paths_yesod_auth_oauth2- hs-source-dirs:- test- ghc-options: -Wall- build-depends:- base >=4.9.0.0 && <5- , hspec- , uri-bytestring- , yesod-auth-oauth2- default-language: Haskell2010+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ hs-source-dirs: test+ other-modules:+ URI.ByteString.ExtensionSpec+ Paths_yesod_auth_oauth2++ default-language: Haskell2010+ ghc-options: -Wall+ build-depends:+ base >=4.9.0.0 && <5,+ hspec >=2.7.4 && <2.8,+ uri-bytestring >=0.3.3.0 && <0.4,+ yesod-auth-oauth2 -any