diff --git a/console2/src/components/pages/UnauthorizedPage/index.tsx b/console2/src/components/pages/UnauthorizedPage/index.tsx index 6914918742..62f737b88b 100644 --- a/console2/src/components/pages/UnauthorizedPage/index.tsx +++ b/console2/src/components/pages/UnauthorizedPage/index.tsx @@ -23,17 +23,11 @@ import * as React from 'react'; import { RedirectButton } from '../../organisms'; import './styles.css'; -import { Card, CardContent, CardHeader, Divider, Image } from 'semantic-ui-react'; -import { useContext, useEffect } from 'react'; -import { UserSessionContext } from '../../../session'; - -export default () => { - const session = useContext(UserSessionContext); - - useEffect(() => { - session.setUserInfo(undefined); - }, [session]); +import {Card, CardContent, CardDescription, CardHeader, Divider, Image} from 'semantic-ui-react'; +import {withRouter} from "react-router"; +export default withRouter((props) => { + const error = new URLSearchParams(props.location.search).get('error'); return (
@@ -42,6 +36,8 @@ export default () => { You are not authorized. + {error && Error: {error}} + @@ -51,4 +47,4 @@ export default () => {
); -}; +}); diff --git a/server/dist/src/main/resources/concord-server.conf b/server/dist/src/main/resources/concord-server.conf index 673920fac7..1473632e8f 100644 --- a/server/dist/src/main/resources/concord-server.conf +++ b/server/dist/src/main/resources/concord-server.conf @@ -589,6 +589,7 @@ concord-server { urlBase = "http://concord.example.com" afterLoginUrl = "http://concord.example.com" afterLogoutUrl = "http://concord.example.com/#/logout/done" + onErrorUrl = "http://concord.example.com/#/unauthorized" scopes = [ "openid", "profile", "email", "groups"] diff --git a/server/plugins/oidc/README.md b/server/plugins/oidc/README.md index 8480bd5954..fb027f3b4c 100644 --- a/server/plugins/oidc/README.md +++ b/server/plugins/oidc/README.md @@ -23,6 +23,23 @@ concord-server { } ``` +For running in development mode (i.e. on `localhost`), callback URLs must be +in the form of + +``` +http://localhost:8001/api/service/oidc/callback?client_name=oidc +``` + +Note the `client_name=oidc` query parameter, it is required by the plugin and +must be present in the provider's configuration. + +The plugin uses the following scopes: `openid`, `profile`, `email`, `groups`. +Which may or may not be enabled by default in the provider's configuration. + +Okta, for example, does not provide the `groups` scope by default. You can +add it in the "Security" -> "API" -> "Authorization Servers" -> your_server -> +"Scope" section. + ### Interactive Login Configure the Concord Console to use custom logout/login URLs: diff --git a/server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/OidcAuthFilter.java b/server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/OidcAuthFilter.java index fcdff9df34..fe84070e8b 100644 --- a/server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/OidcAuthFilter.java +++ b/server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/OidcAuthFilter.java @@ -37,30 +37,42 @@ public class OidcAuthFilter implements Filter { public static final String URL = "/api/service/oidc/auth"; - private final Config config; + private final PluginConfiguration pluginConfig; + private final Config oidcConfig; private final OidcClient client; @Inject - public OidcAuthFilter(@Named("oidc") Config config, OidcClient client) { - this.config = config; + public OidcAuthFilter(PluginConfiguration pluginConfig, @Named("oidc") Config oidcConfig, OidcClient client) { + this.pluginConfig = pluginConfig; + this.oidcConfig = oidcConfig; this.client = client; + + if (pluginConfig.isEnabled() && !client.isInitialized()) { + client.init(); + } } @Override @SuppressWarnings("unchecked") - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; + if (!pluginConfig.isEnabled()) { + resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "OIDC disabled"); + return; + } + JEEContext context = new JEEContext(req, resp); String redirectUrl = req.getParameter("from"); context.getSessionStore().set(context, Pac4jConstants.REQUESTED_URL, redirectUrl); - RedirectionAction action = client.getRedirectionAction(context) + RedirectionAction action = client.getRedirectionActionBuilder() + .getRedirectionAction(context) .orElseThrow(() -> new IllegalStateException("Can't get a redirection action for the request")); - config.getHttpActionAdapter().adapt(action, context); + oidcConfig.getHttpActionAdapter().adapt(action, context); } @Override diff --git a/server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/OidcCallbackFilter.java b/server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/OidcCallbackFilter.java index 9313d6da46..b72f273ff3 100644 --- a/server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/OidcCallbackFilter.java +++ b/server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/OidcCallbackFilter.java @@ -72,6 +72,16 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha postLoginUrl = cfg.getAfterLoginUrl(); } + String error = req.getParameter("error"); + if (error != null) { + String derivedError = "unknown"; + if ("access_denied".equals(error)) { + derivedError = "oidc_access_denied"; + } + resp.sendRedirect(resp.encodeRedirectURL(cfg.getOnErrorUrl() + "?from=" + postLoginUrl + "&error=" + derivedError)); + return; + } + try { CallbackLogic callback = pac4jConfig.getCallbackLogic(); callback.perform(context, pac4jConfig, pac4jConfig.getHttpActionAdapter(), postLoginUrl, true, false, true, OidcPluginModule.CLIENT_NAME); diff --git a/server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/PluginConfiguration.java b/server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/PluginConfiguration.java index 811e09d7d4..46ff96b772 100644 --- a/server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/PluginConfiguration.java +++ b/server/plugins/oidc/src/main/java/com/walmartlabs/concord/server/plugins/oidc/PluginConfiguration.java @@ -58,6 +58,10 @@ public class PluginConfiguration { @Config("oidc.afterLogoutUrl") private String afterLogoutUrl; + @Inject + @Config("oidc.onErrorUrl") + private String onErrorUrl; + @Inject @Nullable @Config("oidc.scopes") @@ -102,6 +106,10 @@ public String getAfterLogoutUrl() { return afterLogoutUrl; } + public String getOnErrorUrl() { + return onErrorUrl; + } + public List getScopes() { return scopes; }