Merge branch '139-single-sign-on-sso-routing-anpassen' into 'oauth2'
Resolve "Single sign-on (SSO): Routing anpassen" See merge request fradrive/fradrive!28
This commit is contained in:
commit
608bea5199
@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>
|
||||
# SPDX-FileCopyrightText: 2022-2024 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>,David Mosbach <david.mosbach@uniworx.de>
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -131,6 +131,8 @@ database:
|
||||
|
||||
auto-db-migrate: '_env:AUTO_DB_MIGRATE:true'
|
||||
|
||||
single-sign-on: "_env:OIDC_SSO:true"
|
||||
|
||||
ldap:
|
||||
- host: "_env:LDAPHOST:"
|
||||
tls: "_env:LDAPTLS:"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Winnie Ros <winnie.ros@campus.lmu.de>
|
||||
# SPDX-FileCopyrightText: 2022-2024 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Winnie Ros <winnie.ros@campus.lmu.de>,David Mosbach <david.mosbach@uniworx.de>
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -139,3 +139,6 @@ FormHoneypotNamePlaceholder: Name
|
||||
FormHoneypotComment: Kommentar
|
||||
FormHoneypotCommentPlaceholder: Kommentar
|
||||
FormHoneypotFilled: Bitte füllen Sie keines der verstecken Felder aus
|
||||
|
||||
Logout: Abmeldung
|
||||
SingleSignOut: Abmeldung bei Azure
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Winnie Ros <winnie.ros@campus.lmu.de>
|
||||
# SPDX-FileCopyrightText: 2022-2024 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Winnie Ros <winnie.ros@campus.lmu.de>,David Mosbach <david.mosbach@uniworx.de>
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -140,3 +140,6 @@ FormHoneypotNamePlaceholder !ident-ok: Name
|
||||
FormHoneypotComment: Comment
|
||||
FormHoneypotCommentPlaceholder: Comment
|
||||
FormHoneypotFilled: Please do not fill in any of the hidden fields
|
||||
|
||||
Logout: Logout
|
||||
SingleSignOut: Azure logout
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@cip.ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Winnie Ros <winnie.ros@campus.lmu.de>
|
||||
# SPDX-FileCopyrightText: 2022-2024 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@cip.ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Winnie Ros <winnie.ros@campus.lmu.de>,David Mosbach <david.mosbach@uniworx.de>
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -24,6 +24,7 @@ MenuPayments: Zahlungsbedingungen
|
||||
MenuInstance: Instanz-Identifikation
|
||||
MenuHealth: Instanz-Zustand
|
||||
MenuHelp: Hilfe
|
||||
MenuAccount: Konto
|
||||
MenuProfile: Anpassen
|
||||
MenuLogin !ident-ok: Login
|
||||
MenuLogout !ident-ok: Logout
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Winnie Ros <winnie.ros@campus.lmu.de>
|
||||
# SPDX-FileCopyrightText: 2022-2024 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Winnie Ros <winnie.ros@campus.lmu.de>,David Mosbach <david.mosbach@uniworx.de>
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -24,6 +24,7 @@ MenuPayments: Payment Terms
|
||||
MenuInstance: Instance identification
|
||||
MenuHealth: Instance health
|
||||
MenuHelp: Support
|
||||
MenuAccount: Account
|
||||
MenuProfile: Settings
|
||||
MenuLogin: Login
|
||||
MenuLogout: Logout
|
||||
|
||||
5
routes
5
routes
@ -1,4 +1,4 @@
|
||||
-- SPDX-FileCopyrightText: 2022-2023 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.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>,Steffen Jost <jost@tcs.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>,David Mosbach <david.mosbach@uniworx.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -46,6 +46,9 @@
|
||||
/static StaticR EmbeddedStatic appStatic !free
|
||||
/auth AuthR Auth getAuth !free
|
||||
|
||||
/logout SOutR GET !free
|
||||
/logout/ssout SSOutR GET !free -- single sign-out (OIDC)
|
||||
|
||||
/metrics MetricsR GET !free -- verify if this can be free
|
||||
|
||||
/err ErrorR GET !free
|
||||
|
||||
@ -9,7 +9,8 @@ let
|
||||
|
||||
haskellPackages = pkgs.haskellPackages;
|
||||
|
||||
oauth2Flake = (builtins.getFlake "git+https://gitlab.uniworx.de/mosbach/oauth2-mock-server/?rev=d47908b4f7883b4b485abf1ee06645495ccdc7b3&ref=user-queries").packages.x86_64-linux;
|
||||
oauth2Flake = (builtins.getFlake "git+https://gitlab.uniworx.de/mosbach/oauth2-mock-server/?rev=7b995e6cffa963a24eb5d0373b2d29089533284f&ref=main").packages.x86_64-linux;
|
||||
|
||||
|
||||
oauth2MockServer = oauth2Flake.default;
|
||||
mkOauth2DB = oauth2Flake.mkOauth2DB;
|
||||
|
||||
@ -164,6 +164,7 @@ import Handler.PrintCenter
|
||||
import Handler.ApiDocs
|
||||
import Handler.Swagger
|
||||
import Handler.Firm
|
||||
import Handler.SingleSignOut
|
||||
|
||||
import ServantApi () -- YesodSubDispatch instances
|
||||
import Servant.API
|
||||
|
||||
@ -8,15 +8,16 @@ module Auth.OAuth2
|
||||
( AzureUserException(..)
|
||||
, azurePluginName
|
||||
, oauth2MockServer
|
||||
, mockPluginName
|
||||
, mockPluginName
|
||||
, queryOAuth2User
|
||||
, UserDataException
|
||||
, singleSignOut
|
||||
) where
|
||||
|
||||
import Data.Maybe (fromJust)
|
||||
import Data.Text
|
||||
|
||||
import Import.NoFoundation hiding (unpack)
|
||||
import Import.NoFoundation hiding (pack, unpack)
|
||||
|
||||
import Network.HTTP.Simple (httpJSONEither, getResponseBody, JSONException)
|
||||
|
||||
@ -36,9 +37,9 @@ instance Exception AzureUserException
|
||||
azurePluginName :: Text
|
||||
azurePluginName = "azureadv2"
|
||||
|
||||
----------------------------------------
|
||||
---- OAuth2 development auth plugin ----
|
||||
----------------------------------------
|
||||
-----------------------------------------------
|
||||
---- OAuth2 + OIDC development auth plugin ----
|
||||
-----------------------------------------------
|
||||
|
||||
mockPluginName :: Text
|
||||
mockPluginName = "dev-oauth2-mock"
|
||||
@ -53,7 +54,11 @@ oauth2MockServer port =
|
||||
let oa = OAuth2
|
||||
{ oauth2ClientId = "42"
|
||||
, oauth2ClientSecret = Just "shhh"
|
||||
, oauth2AuthorizeEndpoint = (fromString $ mockServerURL <> "/auth") `withQuery` [scopeParam " " ["ID", "Profile"]]
|
||||
, oauth2AuthorizeEndpoint = (fromString $ mockServerURL <> "/auth")
|
||||
`withQuery` [ scopeParam " " ["openid", "profile", "email", "offline_access"] -- TODO read scopes from config
|
||||
, ("response_type", "code id_token")
|
||||
, ("nonce", "Foo") -- TODO generate meaningful value
|
||||
]
|
||||
, oauth2TokenEndpoint = fromString $ mockServerURL <> "/token"
|
||||
, oauth2RedirectUri = Nothing
|
||||
}
|
||||
@ -94,7 +99,8 @@ queryOAuth2User userID = runExceptT $ do
|
||||
setSessionJson SessionOAuth2Token (Just $ accessToken newTokens, refreshToken newTokens)
|
||||
eResult <- lift $ getResponseBody <$> httpJSONEither @m @j (req
|
||||
{ secure = secure
|
||||
, requestHeaders = [("Authorization", encodeUtf8 . ("Bearer " <>) . atoken $ accessToken newTokens)] })
|
||||
, requestHeaders = [("Authorization", encodeUtf8 . ("Bearer " <>) . atoken $ accessToken newTokens)]
|
||||
})
|
||||
case eResult of
|
||||
Left x -> throwE $ UserDataJSONException x
|
||||
Right x -> return x
|
||||
@ -130,8 +136,8 @@ refreshOAuth2Token (_, rToken) url secure
|
||||
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), ("scope", "openid profile")]
|
||||
else return $ ("scope", "ID Profile") : body
|
||||
return $ body ++ [("client_id", fromString clientID), ("client_secret", fromString clientSecret), ("scope", "openid profile offline_access")] -- TODO read from config
|
||||
else return $ ("scope", "openid profile offline_access") : body -- TODO read from config
|
||||
$logErrorS "\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
|
||||
@ -142,3 +148,25 @@ refreshOAuth2Token (_, rToken) url secure
|
||||
instance Show RequestBody where
|
||||
show (RequestBodyLBS x) = show x
|
||||
show _ = error ":("
|
||||
|
||||
|
||||
-----------------------
|
||||
---- Single Sign-Out ----
|
||||
-----------------------
|
||||
|
||||
singleSignOut :: forall a m. (MonadHandler m)
|
||||
=> Maybe Text -- ^ redirect uri
|
||||
-> m a
|
||||
singleSignOut mRedirect = do
|
||||
# ifdef DEVELOPMENT
|
||||
port <- liftIO $ fromJust <$> lookupEnv "OAUTH2_SERVER_PORT"
|
||||
let base = "http://localhost:" <> pack port <> "/logout"
|
||||
# else
|
||||
let base = "" -- TODO find out fraport oidc end_session_endpoint
|
||||
# endif
|
||||
endpoint = case mRedirect of
|
||||
Just r -> base <> "?post_logout_redirect_uri=" <> r
|
||||
Nothing -> base
|
||||
$logErrorS "\n\27[31mSSO\27[0m" endpoint
|
||||
redirect endpoint
|
||||
|
||||
|
||||
@ -11,11 +11,14 @@ module Foundation.Instances
|
||||
, unsafeHandler
|
||||
) where
|
||||
|
||||
import qualified Prelude as P
|
||||
|
||||
import Import.NoFoundation
|
||||
|
||||
import qualified Data.Text as Text
|
||||
import Data.List (inits)
|
||||
|
||||
import Yesod.Auth.OAuth2
|
||||
import qualified Yesod.Core.Unsafe as Unsafe
|
||||
import qualified Yesod.Auth.Message as Auth
|
||||
|
||||
@ -23,6 +26,7 @@ import Utils.Form
|
||||
import Auth.LDAP
|
||||
import Auth.PWHash
|
||||
import Auth.Dummy
|
||||
import Auth.OAuth2
|
||||
|
||||
import qualified Foundation.Yesod.Session as UniWorX
|
||||
import qualified Foundation.Yesod.Middleware as UniWorX
|
||||
@ -42,6 +46,8 @@ import Foundation.DB
|
||||
|
||||
import Network.Wai.Parse (lbsBackEnd)
|
||||
|
||||
import System.Environment (lookupEnv)
|
||||
|
||||
import UnliftIO.Pool (withResource)
|
||||
|
||||
import qualified Control.Monad.State.Class as State
|
||||
@ -128,14 +134,23 @@ instance YesodAuth UniWorX where
|
||||
-- Where to send a user after logout
|
||||
logoutDest _ = NewsR
|
||||
-- Override the above two destinations when a Referer: header is present
|
||||
redirectToReferer _ = True
|
||||
redirectToReferer _ = False
|
||||
|
||||
loginHandler = do
|
||||
plugins <- getsYesod authPlugins
|
||||
AppSettings{..} <- getsYesod appSettings'
|
||||
|
||||
when appSingleSignOn $ do
|
||||
let plugin = P.head $ P.filter ((`elem` [mockPluginName, azurePluginName]) . apName) plugins
|
||||
pieces = case oauth2Url (apName plugin) of
|
||||
PluginR _ p -> p
|
||||
_ -> error "Unexpected OAuth2 AuthRoute"
|
||||
void $ apDispatch plugin "GET" pieces
|
||||
|
||||
toParent <- getRouteToParent
|
||||
liftHandler . defaultLayout $ do
|
||||
plugins <- getsYesod authPlugins
|
||||
$logDebugS "Auth" $ "Enabled plugins: " <> Text.intercalate ", " (map apName plugins)
|
||||
|
||||
mPort <- liftIO $ lookupEnv "OAUTH2_SERVER_PORT"
|
||||
setTitleI MsgLoginTitle
|
||||
$(widgetFile "login")
|
||||
|
||||
@ -159,6 +174,11 @@ instance YesodAuth UniWorX where
|
||||
|
||||
addMessage Success . toHtml $ mr Auth.NowLoggedIn
|
||||
|
||||
-- onLogout = do
|
||||
-- AppSettings{..} <- getsYesod appSettings'
|
||||
-- when appSingleSignOn $ singleSignOut @UniWorX Nothing
|
||||
|
||||
|
||||
onErrorHtml dest msg = do
|
||||
addMessage Error $ toHtml msg
|
||||
redirect dest
|
||||
|
||||
@ -73,6 +73,8 @@ breadcrumb :: ( BearerAuthSite UniWorX
|
||||
=> Route UniWorX
|
||||
-> m Breadcrumb
|
||||
breadcrumb (AuthR _) = i18nCrumb MsgMenuLogin $ Just NewsR
|
||||
breadcrumb SOutR = i18nCrumb MsgLogout Nothing
|
||||
breadcrumb SSOutR = i18nCrumb MsgSingleSignOut Nothing
|
||||
breadcrumb (StaticR _) = i18nCrumb MsgBreadcrumbStatic Nothing
|
||||
breadcrumb (WellKnownR _) = i18nCrumb MsgBreadcrumbWellKnown Nothing
|
||||
breadcrumb MetricsR = i18nCrumb MsgBreadcrumbMetrics Nothing
|
||||
@ -541,42 +543,37 @@ defaultLinks :: ( MonadHandler m
|
||||
, BearerAuthSite UniWorX
|
||||
) => m [Nav]
|
||||
defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the header.
|
||||
[ return NavHeader
|
||||
[ return NavHeaderContainer
|
||||
{ navHeaderRole = NavHeaderSecondary
|
||||
, navIcon = IconMenuLogout
|
||||
, navLink = NavLink
|
||||
{ navLabel = MsgMenuLogout
|
||||
, navRoute = AuthR LogoutR
|
||||
, navAccess' = NavAccessHandler $ is _Just <$> maybeAuthId
|
||||
, navType = NavTypeLink { navModal = False }
|
||||
, navQuick' = mempty
|
||||
, navForceActive = False
|
||||
}
|
||||
}
|
||||
, return NavHeader
|
||||
{ navHeaderRole = NavHeaderSecondary
|
||||
, navIcon = IconMenuLogin
|
||||
, navLink = NavLink
|
||||
{ navLabel = MsgMenuLogin
|
||||
, navRoute = AuthR LoginR
|
||||
, navAccess' = NavAccessHandler $ is _Nothing <$> maybeAuthId
|
||||
, navType = NavTypeLink { navModal = True }
|
||||
, navQuick' = mempty
|
||||
, navForceActive = False
|
||||
}
|
||||
}
|
||||
, return NavHeader
|
||||
{ navHeaderRole = NavHeaderSecondary
|
||||
, navIcon = IconMenuProfile
|
||||
, navLink = NavLink
|
||||
{ navLabel = MsgMenuProfile
|
||||
, navRoute = ProfileR
|
||||
, navAccess' = NavAccessHandler $ is _Just <$> maybeAuthId
|
||||
, navType = NavTypeLink { navModal = False }
|
||||
, navQuick' = mempty
|
||||
, navForceActive = False
|
||||
}
|
||||
}
|
||||
, navLabel = SomeMessage MsgMenuAccount
|
||||
, navIcon = IconMenuAccount
|
||||
, navChildren =
|
||||
[ NavLink
|
||||
{ navLabel = MsgMenuLogout
|
||||
, navRoute = SSOutR -- AuthR LogoutR
|
||||
, navAccess' = NavAccessHandler $ is _Just <$> maybeAuthId
|
||||
, navType = NavTypeLink { navModal = False }
|
||||
, navQuick' = mempty
|
||||
, navForceActive = False
|
||||
}
|
||||
, NavLink
|
||||
{ navLabel = MsgMenuLogin
|
||||
, navRoute = AuthR LoginR
|
||||
, navAccess' = NavAccessHandler $ is _Nothing <$> maybeAuthId
|
||||
, navType = NavTypeLink { navModal = False }
|
||||
, navQuick' = mempty
|
||||
, navForceActive = False
|
||||
}
|
||||
, NavLink
|
||||
{ navLabel = MsgMenuProfile
|
||||
, navRoute = ProfileR
|
||||
, navAccess' = NavAccessHandler $ is _Just <$> maybeAuthId
|
||||
, navType = NavTypeLink { navModal = False }
|
||||
, navQuick' = mempty
|
||||
, navForceActive = False
|
||||
}
|
||||
]
|
||||
}
|
||||
, do
|
||||
mCurrentRoute <- getCurrentRoute
|
||||
|
||||
|
||||
31
src/Handler/SingleSignOut.hs
Normal file
31
src/Handler/SingleSignOut.hs
Normal file
@ -0,0 +1,31 @@
|
||||
-- SPDX-FileCopyrightText: 2024 David Mosbach <david.mosbach@uniworx.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
module Handler.SingleSignOut
|
||||
( getSOutR
|
||||
, getSSOutR
|
||||
) where
|
||||
|
||||
import Import
|
||||
import Auth.OAuth2 (singleSignOut)
|
||||
import qualified Network.Wai as W
|
||||
|
||||
|
||||
getSOutR :: Handler Html
|
||||
getSOutR = do
|
||||
$logErrorS "\27[31mSOut\27[0m" "Redirect to LogoutR"
|
||||
redirect $ AuthR LogoutR
|
||||
|
||||
getSSOutR :: Handler Html
|
||||
getSSOutR = do
|
||||
app <- getYesod
|
||||
let redir = intercalate "/" . fst . renderRoute $ SOutR
|
||||
root = case approot of
|
||||
ApprootRequest f -> f app W.defaultRequest
|
||||
_ -> error "approt implementation changed"
|
||||
url = decodeUtf8 . urlEncode True . encodeUtf8 $ root <> "/" <> redir
|
||||
AppSettings{..} <- getsYesod appSettings'
|
||||
$logErrorS "\27[31mSSOut\27[0m" "Redirect to auth server"
|
||||
if appSingleSignOn then singleSignOut (Just url) else redirect (AuthR LogoutR)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
-- SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>
|
||||
-- SPDX-FileCopyrightText: 2022-2024 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,David Mosbach <david.mosbach@uniworx.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -96,6 +96,8 @@ data AppSettings = AppSettings
|
||||
, appDatabaseConf :: PostgresConf
|
||||
-- ^ Configuration settings for accessing the database.
|
||||
, appAutoDbMigrate :: Bool
|
||||
, appSingleSignOn :: Bool
|
||||
-- ^ Enable OIDC single sign-on
|
||||
, appLdapConf :: Maybe (PointedList LdapConf)
|
||||
-- ^ Configuration settings for CSV export/import to LMS (= Learn Management System)
|
||||
, appLmsConf :: LmsConf
|
||||
@ -627,6 +629,7 @@ instance FromJSON AppSettings where
|
||||
appWebpackEntrypoints <- o .: "webpack-manifest"
|
||||
appDatabaseConf <- o .: "database"
|
||||
appAutoDbMigrate <- o .: "auto-db-migrate"
|
||||
appSingleSignOn <- o .: "single-sign-on"
|
||||
let nonEmptyHost LdapConf{..} = case ldapHost of
|
||||
Ldap.Tls host _ -> not $ null host
|
||||
Ldap.Plain host -> not $ null host
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
-- SPDX-FileCopyrightText: 2022-23 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Sarah Vaupel <vaupel.sarah@campus.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>,Steffen Jost <s.jost@fraport.de>
|
||||
-- SPDX-FileCopyrightText: 2022-24 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Sarah Vaupel <vaupel.sarah@campus.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>,Steffen Jost <s.jost@fraport.de>,David Mosbach <david.mosbach@uniworx.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -81,6 +81,7 @@ data Icon
|
||||
| IconNavContainerClose | IconPageActionChildrenClose
|
||||
| IconMenuNews
|
||||
| IconMenuHelp
|
||||
| IconMenuAccount
|
||||
| IconMenuProfile
|
||||
| IconMenuLogin | IconMenuLogout
|
||||
| IconBreadcrumbsHome
|
||||
@ -173,6 +174,7 @@ iconText = \case
|
||||
IconPageActionChildrenClose -> "chevron-up"
|
||||
IconMenuNews -> "megaphone"
|
||||
IconMenuHelp -> "question"
|
||||
IconMenuAccount -> "user"
|
||||
IconMenuProfile -> "cogs"
|
||||
IconMenuLogin -> "sign-in-alt"
|
||||
IconMenuLogout -> "sign-out-alt"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
$newline never
|
||||
|
||||
$# SPDX-FileCopyrightText: 2022-2024 Gregor Kleen <gregor.kleen@ifi.lmu.de>,David Mosbach <david.mosbach@uniworx.de>
|
||||
$# SPDX-FileCopyrightText: 2022-2024 Gregor Kleen <gregor.kleen@ifi.lmu.de>, David Mosbach <david.mosbach@uniworx.de>
|
||||
$#
|
||||
$# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -26,3 +26,8 @@ $forall AuthPlugin{apName, apLogin} <- plugins
|
||||
<section>
|
||||
<h2>_{MsgDummyLoginTitle}
|
||||
^{apLogin toParent}
|
||||
$maybe port <- mPort
|
||||
<section>
|
||||
<h2>SSO Dev Test
|
||||
<a href=http://localhost:#{port}/test-sso>Test login via single sign-on
|
||||
|
||||
|
||||
Reference in New Issue
Block a user