diff --git a/assembly-multiuser/dashboard/src/main/patches/src/app/index.module.ts.patch b/assembly-multiuser/dashboard/src/main/patches/src/app/index.module.ts.patch index 54d85ddcff..6fbc4a5bc1 100644 --- a/assembly-multiuser/dashboard/src/main/patches/src/app/index.module.ts.patch +++ b/assembly-multiuser/dashboard/src/main/patches/src/app/index.module.ts.patch @@ -8,9 +8,9 @@ + +function buildKeycloakConfig(keycloakSettings) { + return { -+ url: keycloakSettings['che.keycloak.auth-server-url'], ++ url: keycloakSettings['che.keycloak.auth_server_url'], + realm: keycloakSettings['che.keycloak.realm'], -+ clientId: keycloakSettings['che.keycloak.client-id'] ++ clientId: keycloakSettings['che.keycloak.client_id'] + }; +} + @@ -30,7 +30,7 @@ + new Promise((resolve, reject) => { + const script = document.createElement('script'); + script.async = true; -+ script.src = keycloakSettings['che.keycloak.auth-server-url'] + '/js/keycloak.js'; ++ script.src = keycloakSettings['che.keycloak.auth_server_url'] + '/js/keycloak.js'; + script.addEventListener('load', resolve); + script.addEventListener('error', () => reject('Error loading script.')); + script.addEventListener('abort', () => reject('Script loading aborted.')); diff --git a/dockerfiles/init/manifests/che.env b/dockerfiles/init/manifests/che.env index 6dab4bcb13..8de51b911f 100644 --- a/dockerfiles/init/manifests/che.env +++ b/dockerfiles/init/manifests/che.env @@ -468,11 +468,11 @@ CHE_SINGLE_PORT=false # CHE_KEYCLOAK_OSO_ENDPOINT=NULL -CHE_KEYCLOAK_GITHUB.ENDPOINT=NULL -CHE_KEYCLOAK_AUTH-SERVER-URL=http://172.17.0.1:5050/auth +CHE_KEYCLOAK_GITHUB_ENDPOINT=NULL +CHE_KEYCLOAK_AUTH__SERVER__URL=http://172.17.0.1:5050/auth CHE_KEYCLOAK_REALM=che -CHE_KEYCLOAK_CLIENT-ID=che-public +CHE_KEYCLOAK_CLIENT__ID=che-public CHE_KEYCLOAK_PRIVATE_REALM=che -CHE_KEYCLOAK_PRIVATE_CLIENT-ID=che -CHE_KEYCLOAK_PRIVATE_CLIENT-SECRET=2c1b2621-d251-4701-82c4-a7dd447faa97 +CHE_KEYCLOAK_PRIVATE_CLIENT__ID=che +CHE_KEYCLOAK_PRIVATE_CLIENT__SECRET=2c1b2621-d251-4701-82c4-a7dd447faa97 diff --git a/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/AbstractKeycloakFilter.java b/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/AbstractKeycloakFilter.java new file mode 100644 index 0000000000..2677cf9020 --- /dev/null +++ b/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/AbstractKeycloakFilter.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.keycloak.server; + +import javax.servlet.Filter; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +/** + * Base abstract class for the Keycloak-related servlet filters. + * + *

In particular it defines commnon use-cases when the authentication / multi-user logic should + * be skipped + */ +public abstract class AbstractKeycloakFilter implements Filter { + + protected boolean shouldSkipAuthentication(HttpServletRequest request, String token) { + return request.getScheme().startsWith("ws") || (token != null && token.startsWith("machine")); + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException {} + + @Override + public void destroy() {} +} diff --git a/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/KeycloakAuthenticationFilter.java b/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/KeycloakAuthenticationFilter.java index 21ce5a0ed4..ede6a2466c 100644 --- a/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/KeycloakAuthenticationFilter.java +++ b/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/KeycloakAuthenticationFilter.java @@ -29,9 +29,8 @@ import java.util.Base64; import java.util.Map; import javax.inject.Inject; import javax.inject.Named; -import javax.servlet.Filter; +import javax.inject.Singleton; import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -42,7 +41,8 @@ import org.eclipse.che.keycloak.shared.KeycloakConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class KeycloakAuthenticationFilter implements Filter { +@Singleton +public class KeycloakAuthenticationFilter extends AbstractKeycloakFilter { private static final Logger LOG = LoggerFactory.getLogger(KeycloakAuthenticationFilter.class); @@ -61,54 +61,52 @@ public class KeycloakAuthenticationFilter implements Filter { this.tokenExtractor = tokenExtractor; } - @Override - public void init(FilterConfig filterConfig) throws ServletException {} - @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; + final String token = tokenExtractor.getToken(request); - if (request.getScheme().startsWith("ws") || (token != null && token.startsWith("machine"))) { + if (shouldSkipAuthentication(request, token)) { chain.doFilter(req, res); return; - } else { - final String requestURI = request.getRequestURI(); - if (token == null) { - LOG.debug("No 'Authorization' header for {}", requestURI); - send403(res); - return; - } + } - Jws jwt; + final String requestURI = request.getRequestURI(); + if (token == null) { + LOG.debug("No 'Authorization' header for {}", requestURI); + send403(res); + return; + } + + Jws jwt; + try { + jwt = Jwts.parser().setSigningKey(getJwtPublicKey(false)).parseClaimsJws(token); + LOG.debug("JWT = ", jwt); + //OK, we can trust this JWT + } catch (SignatureException + | NoSuchAlgorithmException + | InvalidKeySpecException + | IllegalArgumentException e) { + //don't trust the JWT! + LOG.error("Failed verifying the JWT token", e); try { - jwt = Jwts.parser().setSigningKey(getJwtPublicKey(false)).parseClaimsJws(token); - LOG.debug("JWT = " + jwt.toString()); + LOG.info("Retrying after updating the public key", e); + jwt = Jwts.parser().setSigningKey(getJwtPublicKey(true)).parseClaimsJws(token); + LOG.debug("JWT = ", jwt); //OK, we can trust this JWT } catch (SignatureException | NoSuchAlgorithmException | InvalidKeySpecException - | IllegalArgumentException e) { + | IllegalArgumentException ee) { //don't trust the JWT! - LOG.error("Failed verifying the JWT token", e); - try { - LOG.info("Retrying after updating the public key", e); - jwt = Jwts.parser().setSigningKey(getJwtPublicKey(true)).parseClaimsJws(token); - LOG.debug("JWT = " + jwt.toString()); - //OK, we can trust this JWT - } catch (SignatureException - | NoSuchAlgorithmException - | InvalidKeySpecException - | IllegalArgumentException ee) { - //don't trust the JWT! - LOG.error("Failed verifying the JWT token after public key update", e); - send403(res); - return; - } + LOG.error("Failed verifying the JWT token after public key update", e); + send403(res); + return; } - request.setAttribute("token", jwt); - chain.doFilter(req, res); } + request.setAttribute("token", jwt); + chain.doFilter(req, res); } private synchronized PublicKey getJwtPublicKey(boolean reset) @@ -146,7 +144,4 @@ public class KeycloakAuthenticationFilter implements Filter { HttpServletResponse response = (HttpServletResponse) res; response.sendError(403); } - - @Override - public void destroy() {} } diff --git a/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/KeycloakEnvironmentInitalizationFilter.java b/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/KeycloakEnvironmentInitalizationFilter.java index 616c7dd2f2..086bccd116 100644 --- a/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/KeycloakEnvironmentInitalizationFilter.java +++ b/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/KeycloakEnvironmentInitalizationFilter.java @@ -18,9 +18,7 @@ import java.io.IOException; import java.security.Principal; import javax.inject.Inject; import javax.inject.Singleton; -import javax.servlet.Filter; import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -47,7 +45,7 @@ import org.eclipse.che.commons.subject.SubjectImpl; * @author Max Shaposhnik (mshaposhnik@redhat.com) */ @Singleton -public class KeycloakEnvironmentInitalizationFilter implements Filter { +public class KeycloakEnvironmentInitalizationFilter extends AbstractKeycloakFilter { private final UserManager userManager; private final AccountManager accountManager; @@ -63,16 +61,13 @@ public class KeycloakEnvironmentInitalizationFilter implements Filter { this.tokenExtractor = tokenExtractor; } - @Override - public void init(FilterConfig filterConfig) throws ServletException {} - @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest httpRequest = (HttpServletRequest) request; final String token = tokenExtractor.getToken(httpRequest); - if (request.getScheme().startsWith("ws") || (token != null && token.startsWith("machine"))) { + if (shouldSkipAuthentication(httpRequest, token)) { filterChain.doFilter(request, response); return; } @@ -153,7 +148,4 @@ public class KeycloakEnvironmentInitalizationFilter implements Filter { } }; } - - @Override - public void destroy() {} } diff --git a/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/deploy/KeycloakServletModule.java b/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/deploy/KeycloakServletModule.java index 2348669aa2..656abf61b2 100644 --- a/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/deploy/KeycloakServletModule.java +++ b/plugins/plugin-keycloak/che-plugin-keycloak-server/src/main/java/org/eclipse/che/keycloak/server/deploy/KeycloakServletModule.java @@ -20,10 +20,12 @@ public class KeycloakServletModule extends ServletModule { protected void configureServlets() { bind(KeycloakAuthenticationFilter.class).in(Singleton.class); - // Not contains '/websocket', /docs/ (for swagger) and not ends with '/ws' or '/eventbus' or '/settings/' - filterRegex("^(?!.*(/websocket/?|/docs/))(?!.*(/ws/?|/eventbus/?|/settings/?)$).*") + // Not contains '/websocket', /docs/ (for swagger) and not ends with '/ws' or '/eventbus' or '/settings/' or '/api/system/state' or '/api/stack/[^/]+/icon/' + filterRegex( + "^(?!.*(/websocket/?|/docs/))(?!.*(/ws/?|/eventbus/?|/settings/?|/api/system/state/?|/api/stack/[^/]+/icon/?)$).*") .through(KeycloakAuthenticationFilter.class); - filterRegex("^(?!.*(/websocket/?|/docs/))(?!.*(/ws/?|/eventbus/?|/settings/?)$).*") + filterRegex( + "^(?!.*(/websocket/?|/docs/))(?!.*(/ws/?|/eventbus/?|/settings/?|/api/system/state/?|/api/stack/[^/]+/icon/?)$).*") .through(KeycloakEnvironmentInitalizationFilter.class); } } diff --git a/plugins/plugin-keycloak/che-plugin-keycloak-shared/src/main/java/org/eclipse/che/keycloak/shared/KeycloakConstants.java b/plugins/plugin-keycloak/che-plugin-keycloak-shared/src/main/java/org/eclipse/che/keycloak/shared/KeycloakConstants.java index 7ccdb79cfa..ef0e82916d 100644 --- a/plugins/plugin-keycloak/che-plugin-keycloak-shared/src/main/java/org/eclipse/che/keycloak/shared/KeycloakConstants.java +++ b/plugins/plugin-keycloak/che-plugin-keycloak-shared/src/main/java/org/eclipse/che/keycloak/shared/KeycloakConstants.java @@ -17,18 +17,18 @@ public class KeycloakConstants { private static final String PRIVATE_PREFIX = "private."; private static final String KEYCLOAK_SETTINGS_ENDPOINT_PATH = "/keycloak/settings"; - public static final String AUTH_SERVER_URL_SETTING = KEYCLOAK_SETTING_PREFIX + "auth-server-url"; + public static final String AUTH_SERVER_URL_SETTING = KEYCLOAK_SETTING_PREFIX + "auth_server_url"; public static final String REALM_SETTING = KEYCLOAK_SETTING_PREFIX + "realm"; - public static final String CLIENT_ID_SETTING = KEYCLOAK_SETTING_PREFIX + "client-id"; + public static final String CLIENT_ID_SETTING = KEYCLOAK_SETTING_PREFIX + "client_id"; public static final String REWRITE_RULE_SETTING = - KEYCLOAK_SETTING_PREFIX + "redirect-rewrite-rules"; + KEYCLOAK_SETTING_PREFIX + "redirect_rewrite_rules"; public static final String PRIVATE_REALM_SETTING = KEYCLOAK_SETTING_PREFIX + PRIVATE_PREFIX + "realm"; public static final String PRIVATE_CLIENT_ID_SETTING = - KEYCLOAK_SETTING_PREFIX + PRIVATE_PREFIX + "client-id"; + KEYCLOAK_SETTING_PREFIX + PRIVATE_PREFIX + "client_id"; public static final String PRIVATE_CLIENT_SECRET_SETTING = - KEYCLOAK_SETTING_PREFIX + PRIVATE_PREFIX + "client-secret"; + KEYCLOAK_SETTING_PREFIX + PRIVATE_PREFIX + "client_secret"; public static final String OSO_ENDPOINT_SETTING = KEYCLOAK_SETTING_PREFIX + "oso.endpoint"; public static final String PROFILE_ENDPOINT_SETTING =