Draft: OAuth: Debug prints and fixes #214

Open
savau wants to merge 21 commits from oauth-fixes into test
11 changed files with 111 additions and 88 deletions

View File

@ -136,7 +136,7 @@ user-auth:
client-id: "_env:AZURECLIENTID:00000000-0000-0000-0000-000000000000"
client-secret: "_env:AZURECLIENTSECRET:''"
tenant-id: "_env:AZURETENANTID:00000000-0000-0000-0000-000000000000"
scopes: "_env:AZURESCOPES:[ID,Profile]"
scopes: "_env:AZURESCOPES:[email,openid,profile,offline_access]"
# protocol: "ldap"
# config:
# host: "_env:LDAPHOST:"

View File

@ -25,12 +25,12 @@
"rev": "40393c938111ac78232dc2c7eec5edb4a22d03e8",
"revCount": 62,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/HaskellNet-SSL.git"
"url": "https://gitlab.uniworx.de/haskell/HaskellNet-SSL.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/HaskellNet-SSL.git"
"url": "https://gitlab.uniworx.de/haskell/HaskellNet-SSL.git"
}
},
"cabal-32": {
@ -92,12 +92,12 @@
"rev": "f8170266ab25b533576e96715bedffc5aa4f19fa",
"revCount": 153,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/colonnade.git"
"url": "https://gitlab.uniworx.de/haskell/colonnade.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/colonnade.git"
"url": "https://gitlab.uniworx.de/haskell/colonnade.git"
}
},
"conduit-resumablesink": {
@ -109,12 +109,12 @@
"rev": "cbea6159c2975d42f948525e03e12fc390da53c5",
"revCount": 10,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/conduit-resumablesink.git"
"url": "https://gitlab.uniworx.de/haskell/conduit-resumablesink.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/conduit-resumablesink.git"
"url": "https://gitlab.uniworx.de/haskell/conduit-resumablesink.git"
}
},
"cryptoids": {
@ -126,29 +126,29 @@
"rev": "130b0dcbf2b09ccdf387b50262f1efbbbf1819e3",
"revCount": 44,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/cryptoids.git"
"url": "https://gitlab.uniworx.de/haskell/cryptoids.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/cryptoids.git"
"url": "https://gitlab.uniworx.de/haskell/cryptoids.git"
}
},
"cryptonite": {
"flake": false,
"locked": {
"lastModified": 1624444174,
"narHash": "sha256-sDMA4ej1NIModAt7PQvcgIknI3KwfzcAp9YQUSe4CWw=",
"lastModified": 1704764911,
"narHash": "sha256-VuEWT2Bd4aSJyRcXpB+lsGDqxrTHB/uRvILzYWLNfxk=",
"ref": "uni2work",
"rev": "71a630edaf5f22c464e24fac8d9d310f4055ea1f",
"revCount": 1202,
"rev": "f78fca2504bb767d632a3bac8dbbc23367eff0e9",
"revCount": 1220,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/cryptonite.git"
"url": "https://gitlab.uniworx.de/haskell/cryptonite.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/cryptonite.git"
"url": "https://gitlab.uniworx.de/haskell/cryptonite.git"
}
},
"encoding": {
@ -160,12 +160,12 @@
"rev": "22fc3bb14841d8d50997aa47f1be3852e666f787",
"revCount": 162,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/encoding.git"
"url": "https://gitlab.uniworx.de/haskell/encoding.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/encoding.git"
"url": "https://gitlab.uniworx.de/haskell/encoding.git"
}
},
"esqueleto": {
@ -177,12 +177,12 @@
"rev": "e18dd125c5ea26fa4e88bed079b61d8c1365ee37",
"revCount": 708,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/esqueleto.git"
"url": "https://gitlab.uniworx.de/haskell/esqueleto.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/esqueleto.git"
"url": "https://gitlab.uniworx.de/haskell/esqueleto.git"
}
},
"flake-utils": {
@ -310,12 +310,12 @@
"rev": "01afaf599ba6f8a9d804c269e91d3190b249d3f0",
"revCount": 61,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/ldap-client.git"
"url": "https://gitlab.uniworx.de/haskell/ldap-client.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/ldap-client.git"
"url": "https://gitlab.uniworx.de/haskell/ldap-client.git"
}
},
"memcached-binary": {
@ -327,29 +327,29 @@
"rev": "b7071df50bad3a251a544b984e4bf98fa09b8fae",
"revCount": 28,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/memcached-binary.git"
"url": "https://gitlab.uniworx.de/haskell/memcached-binary.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/memcached-binary.git"
"url": "https://gitlab.uniworx.de/haskell/memcached-binary.git"
}
},
"minio-hs": {
"flake": false,
"locked": {
"lastModified": 1597069863,
"narHash": "sha256-JmMajaLT4+zt+w2koDkaloFL8ugmrQBlcYKj+78qn9M=",
"lastModified": 1711841413,
"narHash": "sha256-9IdjU1/Mzi4ZGhX7tFJhqliratSVRvDwe9AesD0lkt8=",
"ref": "uni2work",
"rev": "42103ab247057c04c8ce7a83d9d4c160713a3df1",
"revCount": 197,
"rev": "cb25dd23c4cf62a956caad722d45ad6cf3cc5e3a",
"revCount": 224,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/minio-hs.git"
"url": "https://gitlab.uniworx.de/haskell/minio-hs.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/minio-hs.git"
"url": "https://gitlab.uniworx.de/haskell/minio-hs.git"
}
},
"nix-tools": {
@ -528,12 +528,12 @@
"rev": "b9d76def10da1260c7f6aa82bda32111f37a952b",
"revCount": 174,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/serversession.git"
"url": "https://gitlab.uniworx.de/haskell/serversession.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/serversession.git"
"url": "https://gitlab.uniworx.de/haskell/serversession.git"
}
},
"stackage": {
@ -576,29 +576,31 @@
"rev": "dc928c3a456074b8777603bea20e81937321777f",
"revCount": 114,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/xss-sanitize.git"
"url": "https://gitlab.uniworx.de/haskell/xss-sanitize.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/xss-sanitize.git"
"url": "https://gitlab.uniworx.de/haskell/xss-sanitize.git"
}
},
"yesod": {
"flake": false,
"locked": {
"lastModified": 1625061191,
"narHash": "sha256-K0X2MwUStChml1DlJ7t4yBMDwrMe6j/780nJtSy9Hss=",
"ref": "uni2work",
"rev": "a59f63e0336ee61f7a90b8778e9147305d3127bb",
"revCount": 5053,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/yesod.git"
"host": "gitlab.uniworx.de",
"lastModified": 1681915610,
"narHash": "sha256-HtJhPHDC7FTc7kyI3OtBKjgeUyEslIGpQiZJwO4PUec=",
"owner": "haskell",
"repo": "yesod",
"rev": "aa671eb41fdad360f2f7cb844f8de03479efe3f7",
"type": "gitlab"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/yesod.git"
"host": "gitlab.uniworx.de",
"owner": "haskell",
"repo": "yesod",
"rev": "aa671eb41fdad360f2f7cb844f8de03479efe3f7",
"type": "gitlab"
}
},
"zip-stream": {
@ -610,12 +612,12 @@
"rev": "843683d024f767de236f74d24a3348f69181a720",
"revCount": 39,
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/zip-stream.git"
"url": "https://gitlab.uniworx.de/haskell/zip-stream.git"
},
"original": {
"ref": "uni2work",
"type": "git",
"url": "https://gitlab.ifi.lmu.de/uni2work/haskell/zip-stream.git"
"url": "https://gitlab.uniworx.de/haskell/zip-stream.git"
}
}
},

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022-2023 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor@kleen.consulting>
# SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor@kleen.consulting>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
@ -29,59 +29,64 @@
};
encoding = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/encoding.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/encoding.git?ref=uni2work";
flake = false;
};
memcached-binary = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/memcached-binary.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/memcached-binary.git?ref=uni2work";
flake = false;
};
conduit-resumablesink = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/conduit-resumablesink.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/conduit-resumablesink.git?ref=uni2work";
flake = false;
};
HaskellNet-SSL = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/HaskellNet-SSL.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/HaskellNet-SSL.git?ref=uni2work";
flake = false;
};
ldap-client = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/ldap-client.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/ldap-client.git?ref=uni2work";
flake = false;
};
serversession = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/serversession.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/serversession.git?ref=uni2work";
flake = false;
};
xss-sanitize = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/xss-sanitize.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/xss-sanitize.git?ref=uni2work";
flake = false;
};
colonnade = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/colonnade.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/colonnade.git?ref=uni2work";
flake = false;
};
minio-hs = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/minio-hs.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/minio-hs.git?ref=uni2work";
flake = false;
};
cryptoids = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/cryptoids.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/cryptoids.git?ref=uni2work";
flake = false;
};
zip-stream = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/zip-stream.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/zip-stream.git?ref=uni2work";
flake = false;
};
yesod = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/yesod.git?ref=uni2work";
url = "gitlab:haskell/yesod?host=gitlab.uniworx.de&rev=aa671eb41fdad360f2f7cb844f8de03479efe3f7";
flake = false;
};
# TODO: does not function due to missing dependencies in snapshot
# yesod-auth-oauth2 = {
# url = "git+https://gitlab.uniworx.de/haskell/yesod-auth-oauth2.git?ref=ghc-8.10.4";
# flake = false;
# };
cryptonite = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/cryptonite.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/cryptonite.git?ref=uni2work";
flake = false;
};
esqueleto = {
url = "git+https://gitlab.ifi.lmu.de/uni2work/haskell/esqueleto.git?ref=uni2work";
url = "git+https://gitlab.uniworx.de/haskell/esqueleto.git?ref=uni2work";
flake = false;
};
};

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022-2023 Gregor Kleen <gregor@kleen.consulting>, Steffen Jost <jost@cip.ifi.lmu.de>
# SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor@kleen.consulting>, Steffen Jost <jost@cip.ifi.lmu.de>
#
# SPDX-License-Identifier: AGPL-3.0-or-later

View File

@ -6,7 +6,7 @@ dependencies:
- yesod-core
- yesod-persistent
- yesod-auth
- yesod-auth-oauth2
- yesod-auth-oauth2 >=0.7.3.0
- yesod-static
- yesod-form
- yesod-persistent

View File

@ -331,7 +331,7 @@ makeFoundation appSettings''@AppSettings{..} = do
, return $ oauth2AzureADScoped ["openid", "profile", "offline_access"] "42" "shhh"
]
#else
let -- Auth Plugins
-- let -- Auth Plugins
-- loadPlugin p prefix = do -- Loads given YesodAuthPlugin
-- mID <- fmap Text.pack <$> appUserAuthConf ^? _UserAuthConfSingleSource . _AuthSourceConfAzureAdV2 . _azureConfClientId
-- mSecret <- fmap Text.pack <$> appUserAuthConf ^? _UserAuthConfSingleSource . _AuthSourceConfAzureAdV2 . _azureConfClientSecret
@ -343,11 +343,17 @@ makeFoundation appSettings''@AppSettings{..} = do
-- -> tshow azureConfTenantId
-- _other
-- -> error "Tenant ID missing!"
oauth2Plugins
| UserAuthConfSingleSource (AuthSourceConfAzureAdV2 AzureConf{..}) <- appUserAuthConf
= singleton $ oauth2AzureADScoped (Set.toList azureConfScopes) (tshow azureConfClientId) azureConfClientSecret
| otherwise
= mempty
oauth2Plugins <- if
| UserAuthConfSingleSource (AuthSourceConfAzureAdV2 AzureConf{..}) <- appUserAuthConf -> do
$logInfoS "OAuth2" "Successfully parsed OAuth2 config from AppSettings"
return . singleton $ oauth2AzureADScoped (Set.toList azureConfScopes) (tshow azureConfClientId) azureConfClientSecret
| otherwise -> do
when appSingleSignOn $ do
$logErrorS "OAuth2" "SingleSignOn via AzureADv2 is enabled, but user-auth config could not be parsed!"
when appAutoSignOn $
$logErrorS "OAuth2" "SingleSignOn via AzureADv2 and AutoSignOn are enabled, but user-auth config could not be parsed! This will likely prevent the app from being accessible!"
$logInfoS "UserAuthConf" $ tshow appUserAuthConf
return mempty
#endif
let appAuthPlugins = oauth2Plugins

View File

@ -19,13 +19,16 @@ module Auth.OAuth2
-- import qualified Data.CaseInsensitive as CI
import Data.Maybe (fromJust)
import qualified Data.Set as Set
import Data.Text
import Import.NoFoundation hiding (pack, unpack)
import Network.HTTP.Simple (httpJSONEither, getResponseBody, JSONException)
# ifdef DEVELOPMENT
import System.Environment (lookupEnv)
# endif
import Yesod.Auth.OAuth2
import Yesod.Auth.OAuth2.Prelude hiding (encodeUtf8)
@ -127,7 +130,7 @@ azureMockServer port =
, ("nonce", "Foo") -- TODO generate meaningful value
]
, oauthAccessTokenEndpoint = fromString $ mockServerURL <> "/token"
, oauthCallback = Nothing
, oauthCallback = Nothing -- TODO use approot as redirect uri?
}
mockServerURL = "http://localhost:" <> fromString port
profileSrc = fromString $ mockServerURL <> "/users/me"
@ -195,31 +198,31 @@ mkBaseUrls = do
refreshOAuth2Token :: forall m.
( MonadHandler m
, HasAppSettings (HandlerSite m)
, MonadThrow m
)
=> (Maybe AccessToken, Maybe RefreshToken)
-> String
-> Bool
-> ExceptT UserDataException m OAuth2Token
refreshOAuth2Token (_, rToken) url secure
| isJust rToken = do
refreshOAuth2Token (_, Nothing) _ _ = throwE $ UserDataInternalException "Could not refresh access token. Refresh token is missing."
refreshOAuth2Token (_, Just rToken) url secure = getsYesod (view $ _appUserAuthConf . _userAuthConfSingleSource) >>= \case
AuthSourceConfAzureAdV2 AzureConf{..} -> do
req <- parseRequest $ "POST " ++ url
let
body =
[ ("grant_type", "refresh_token")
, ("refresh_token", encodeUtf8 . rtoken $ fromJust rToken)
, ("refresh_token", encodeUtf8 $ rtoken rToken)
]
body' <- if secure then do
clientID <- liftIO $ fromJust <$> lookupEnv "CLIENT_ID"
clientSecret <- liftIO $ fromJust <$> lookupEnv "CLIENT_SECRET"
return $ body ++ [("client_id", fromString clientID), ("client_secret", fromString clientSecret), scopeParam " " ["openid","profile"," offline_access"]] -- TODO read from config
else return $ scopeParam " " ["openid","profile","offline_access"] : body -- TODO read from config
$logDebugS "\27[31mAdmin Handler\27[0m" $ tshow (requestBody $ urlEncodedBody body' req{ secure = secure })
body'
| secure = body ++ [("client_id", fromString $ show azureConfClientId), ("client_secret", fromString $ unpack azureConfClientSecret), scopeParam " " $ Set.toList azureConfScopes]
| otherwise = scopeParam " " (Set.toList azureConfScopes) : body
$logInfoS "\27[31mAdmin Handler\27[0m" $ tshow (requestBody $ urlEncodedBody body' req{ secure = secure })
eResult <- lift $ getResponseBody <$> httpJSONEither @m @OAuth2Token (urlEncodedBody body' req{ secure = secure })
case eResult of
Left x -> throwE $ UserDataJSONException x
Right x -> return x
| otherwise = throwE $ UserDataInternalException "Could not refresh access token. Refresh token is missing."
_other -> throwE $ UserDataInternalException "Could not refresh access token. Invalid/Conflicting auth source configuration."
instance Show RequestBody where
show (RequestBodyLBS x) = show x

View File

@ -140,12 +140,17 @@ instance YesodAuth UniWorX where
plugins <- getsYesod authPlugins
AppSettings{..} <- getsYesod appSettings'
when appSingleSignOn $ do
let plugin = P.head $ P.filter ((`elem` [apAzureMock, apAzure]) . apName) plugins
pieces = case oauth2Url (apName plugin) of
PluginR _ p -> p
_ -> error "Unexpected OAuth2 AuthRoute"
void $ apDispatch plugin "GET" pieces
when appSingleSignOn $
let azurePlugins = P.filter ((`elem` [apAzureMock, apAzure]) . apName) plugins
in if
| (plugin:_) <- azurePlugins
, PluginR _ pieces <- oauth2Url (apName plugin) -> do
$logInfoS "SSO" "Azure plugin with plugin url as expected. Calling apDispatch..."
void $ apDispatch plugin "GET" pieces
| not (null azurePlugins) -> do
$logErrorS "SSO" "Azure plugin initialized, but unexpected oauth2Url. Cannot apDispatch."
| otherwise -> do
$logErrorS "SSO" "No Azure plugin initialized despite SSO being enabled!"
toParent <- getRouteToParent
liftHandler . defaultLayout $ do

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>
# SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
@ -55,6 +55,8 @@ extra-deps:
subdirs:
- gearhash
- fastcdc
- git: https://github.com/freckle/yesod-auth-oauth2.git
commit: 342dac80e40b10f07694a7e9aa8bab6d03ed6d66
- classy-prelude-yesod-1.5.0@sha256:8f7e183bdfd6d2ea9674284c4f285294ab086aff60d9be4e5d7d2f3c1a2b05b7,1330
- acid-state-0.16.0.1@sha256:d43f6ee0b23338758156c500290c4405d769abefeb98e9bc112780dae09ece6f,6207

View File

@ -18,7 +18,7 @@ nix:
packages: []
pure: false
shell-file: ./stack.nix
add-gc-roots: true
add-gc-roots: false
extra-package-dbs: []

View File

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
{ nixpkgs ? import ./nixpkgs.nix
, snapshot ? "lts-13.21"
, snapshot ? "lts-18.0"
}:
let