# HG changeset patch # User Severin Gehwolf # Date 1504632800 -7200 # Node ID 236e08b6fb0de658ff209a842e5c1f474b2f9911 # Parent 7499f1b499c15f68197348fe96ab64c51856b08f Make KeycloakRealmAuthorizer servlet request independent. Reviewed-by: jkang Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/024837.html diff -r 7499f1b499c1 -r 236e08b6fb0d common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/RealmAuthorizer.java --- a/common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/RealmAuthorizer.java Tue Sep 05 13:30:08 2017 -0400 +++ b/common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/RealmAuthorizer.java Tue Sep 05 19:33:20 2017 +0200 @@ -44,7 +44,16 @@ public abstract class RealmAuthorizer { - protected Set clientRoles = Collections.emptySet(); + /** + * A RealmAuthorizer that will deny any request. + */ + public static final RealmAuthorizer DENY_ALL_AUTHORIZER = new RealmAuthorizer(Collections.emptySet()) {}; + + protected final Set clientRoles; + + protected RealmAuthorizer(Set clientRoles) { + this.clientRoles = clientRoles; + } public boolean readable() { return checkActionExists(Action.READ); diff -r 7499f1b499c1 -r 236e08b6fb0d common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/basic/BasicRealmAuthorizer.java --- a/common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/basic/BasicRealmAuthorizer.java Tue Sep 05 13:30:08 2017 -0400 +++ b/common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/basic/BasicRealmAuthorizer.java Tue Sep 05 19:33:20 2017 +0200 @@ -49,6 +49,17 @@ public static final String DEFAULT_REALM = "thermostat"; public BasicRealmAuthorizer(BasicWebUser user) { + super(buildRoles(user)); + } + + /** + * Package private for testing + */ + Set getAllRoles() { + return clientRoles; + } + + private static Set buildRoles(BasicWebUser user) { RoleFactory roleFactory = new RoleFactory(); Set roles = new HashSet<>(); @@ -61,13 +72,6 @@ } } - clientRoles = Collections.unmodifiableSet(roles); - } - - /** - * Package private for testing - */ - Set getAllRoles() { - return clientRoles; + return Collections.unmodifiableSet(roles); } } diff -r 7499f1b499c1 -r 236e08b6fb0d common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizer.java --- a/common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizer.java Tue Sep 05 13:30:08 2017 -0400 +++ b/common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizer.java Tue Sep 05 19:33:20 2017 +0200 @@ -37,13 +37,9 @@ package com.redhat.thermostat.gateway.common.core.auth.keycloak; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.Set; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; - import org.keycloak.KeycloakSecurityContext; import com.redhat.thermostat.gateway.common.core.auth.InvalidRoleException; @@ -53,13 +49,14 @@ public class KeycloakRealmAuthorizer extends RealmAuthorizer { - public static final String REALMS_HEADER = "X-Thermostat-Realms"; - private static final String REALMS_HEADER_DELIMITER_REGEX = "\\s+"; + private static final String REALMS_LIMITS_DELIMITER_REGEX = "\\s+"; - private final RoleFactory roleFactory = new RoleFactory(); + public KeycloakRealmAuthorizer(KeycloakSecurityContext keycloakSecurityContext, String roleLimits) throws CannotReduceRealmsException { + super(buildClientRoles(keycloakSecurityContext, roleLimits)); + } - public KeycloakRealmAuthorizer(HttpServletRequest httpServletRequest) throws ServletException { - this.clientRoles = buildClientRoles(httpServletRequest); + public KeycloakRealmAuthorizer(KeycloakSecurityContext keycloakSecurityContext) throws CannotReduceRealmsException { + this(keycloakSecurityContext, null); } /** @@ -69,26 +66,12 @@ return clientRoles; } - private Set buildClientRoles(HttpServletRequest httpServletRequest) throws ServletException { - Set keycloakRoles = buildKeycloakRoles(httpServletRequest); - - String realmsHeader = httpServletRequest.getHeader(REALMS_HEADER); - if (realmsHeader != null) { - return buildClientPreferredRoles(keycloakRoles, realmsHeader); - } - - return Collections.unmodifiableSet(keycloakRoles); - } - /** * @return the set of roles from the Keycloak security token */ - private Set buildKeycloakRoles(HttpServletRequest httpServletRequest) { + private static Set buildClientRoles(KeycloakSecurityContext keycloakSecurityContext, String roleLimits) throws CannotReduceRealmsException { + final RoleFactory roleFactory = new RoleFactory(); Set keycloakRoles = new HashSet<>(); - - KeycloakSecurityContext keycloakSecurityContext = (KeycloakSecurityContext) httpServletRequest - .getAttribute(KeycloakSecurityContext.class.getName()); - for (String role : keycloakSecurityContext.getToken().getRealmAccess().getRoles()) { try { keycloakRoles.add(roleFactory.buildRole(role)); @@ -96,20 +79,23 @@ //Do nothing } } - - return keycloakRoles; + if (roleLimits != null) { + return buildClientPreferredRoles(keycloakRoles, roleLimits); + } else { + return keycloakRoles; + } } /** * Builds a set of roles based on a clients preferred set, provided in a comma separated realms header string * @param trustedRoles : The trusted set of roles that the client has - * @param realmsHeader : The REALMS_HEADER value as a string + * @param realmsLimits : The string of space separated realms to reduce the roles to. * @return The set of roles that the client has selected - * @throws ServletException If realms header contains realms the client does not have or no valid realms + * @throws CannotReduceRealmsException If realm limit contains realms the client does not have or no valid realms */ - private Set buildClientPreferredRoles(Set trustedRoles, String realmsHeader) throws ServletException { - realmsHeader = realmsHeader.trim(); - Set preferredRealms = new HashSet<>(Arrays.asList(realmsHeader.split(REALMS_HEADER_DELIMITER_REGEX))); + private static Set buildClientPreferredRoles(Set trustedRoles, String realmsLimits) throws CannotReduceRealmsException { + realmsLimits = realmsLimits.trim(); + Set preferredRealms = new HashSet<>(Arrays.asList(realmsLimits.split(REALMS_LIMITS_DELIMITER_REGEX))); Set selectedRoles = new HashSet<>(); for (String preferredRealm : preferredRealms) { @@ -121,16 +107,22 @@ } } if (!found) { - throw new ServletException("Not authorized to access preferred realms."); + throw new CannotReduceRealmsException("Not authorized to access preferred realms."); } } if (selectedRoles.size() > 0) { return selectedRoles; } else { - throw new ServletException("No realms selected"); + throw new CannotReduceRealmsException("No realms selected"); } } + @SuppressWarnings("serial") + public static class CannotReduceRealmsException extends Exception { + public CannotReduceRealmsException(String msg) { + super(msg); + } + } } diff -r 7499f1b499c1 -r 236e08b6fb0d common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizerServletAdapter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizerServletAdapter.java Tue Sep 05 19:33:20 2017 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.gateway.common.core.auth.keycloak; + +import javax.servlet.http.HttpServletRequest; + +import org.keycloak.KeycloakSecurityContext; + +import com.redhat.thermostat.gateway.common.core.auth.keycloak.KeycloakRealmAuthorizer.CannotReduceRealmsException; + +public class KeycloakRealmAuthorizerServletAdapter { + + public static final String REALMS_HEADER = "X-Thermostat-Realms"; + + public KeycloakRealmAuthorizer createAuthorizer(HttpServletRequest httpServletRequest) throws CannotReduceRealmsException { + String realmsLimits = getRealmsLimits(httpServletRequest); + KeycloakSecurityContext securityContext = getSecurityContext(httpServletRequest); + return new KeycloakRealmAuthorizer(securityContext, realmsLimits); + } + + private KeycloakSecurityContext getSecurityContext(HttpServletRequest httpServletRequest) { + return (KeycloakSecurityContext)httpServletRequest.getAttribute(KeycloakSecurityContext.class.getName()); + } + + private String getRealmsLimits(HttpServletRequest httpServletRequest) { + return httpServletRequest.getHeader(REALMS_HEADER); + } +} diff -r 7499f1b499c1 -r 236e08b6fb0d common/core/src/test/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizerServletAdapterTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/core/src/test/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizerServletAdapterTest.java Tue Sep 05 19:33:20 2017 +0200 @@ -0,0 +1,115 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.gateway.common.core.auth.keycloak; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.HashSet; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Before; +import org.junit.Test; +import org.keycloak.KeycloakSecurityContext; +import org.keycloak.representations.AccessToken; +import org.keycloak.representations.AccessToken.Access; + +import com.redhat.thermostat.gateway.common.core.auth.keycloak.KeycloakRealmAuthorizer.CannotReduceRealmsException; + +public class KeycloakRealmAuthorizerServletAdapterTest { + + private KeycloakRealmAuthorizerServletAdapter adapter = new KeycloakRealmAuthorizerServletAdapter(); + private HttpServletRequest request; + private Access access; + + @Before + public void setup() { + request = mock(HttpServletRequest.class); + KeycloakSecurityContext keycloakSecurityContext = mock(KeycloakSecurityContext.class); + when(request.getAttribute(eq(KeycloakSecurityContext.class.getName()))).thenReturn(keycloakSecurityContext); + + AccessToken accessToken = mock(AccessToken.class); + when(keycloakSecurityContext.getToken()).thenReturn(accessToken); + + access = mock(AccessToken.Access.class); + when(accessToken.getRealmAccess()).thenReturn(access); + } + + @Test + public void testRealmsHeaderSubset() throws CannotReduceRealmsException { + String[] roles = new String[]{"w-write", "r-read", "u-update"}; + when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); + + when(request.getHeader(eq("X-Thermostat-Realms"))).thenReturn("read update"); + + KeycloakRealmAuthorizer realmAuthorizer = adapter.createAuthorizer(request); + assertEquals(1, realmAuthorizer.getReadableRealms().size()); + assertEquals(1, realmAuthorizer.getUpdatableRealms().size()); + + assertEquals(0, realmAuthorizer.getWritableRealms().size()); + assertEquals(0, realmAuthorizer.getDeletableRealms().size()); + } + + @Test(expected = CannotReduceRealmsException.class) + public void testRealmsHeaderSuperset() throws CannotReduceRealmsException { + String[] roles = new String[]{"r-read,","u-update"}; + when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); + + when(request.getHeader(eq("X-Thermostat-Realms"))).thenReturn("read update other"); + + adapter.createAuthorizer(request); + } + + @Test + public void testRealmsHeaderWhitespace() throws CannotReduceRealmsException { + String[] roles = new String[]{"w-write", "r-read", "u-update"}; + when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); + + when(request.getHeader(eq("X-Thermostat-Realms"))).thenReturn(" read update\twrite "); + + KeycloakRealmAuthorizer realmAuthorizer = adapter.createAuthorizer(request); + assertEquals(1, realmAuthorizer.getReadableRealms().size()); + assertEquals(1, realmAuthorizer.getUpdatableRealms().size()); + assertEquals(1, realmAuthorizer.getWritableRealms().size()); + + assertEquals(0, realmAuthorizer.getDeletableRealms().size()); + } +} diff -r 7499f1b499c1 -r 236e08b6fb0d common/core/src/test/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizerTest.java --- a/common/core/src/test/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizerTest.java Tue Sep 05 13:30:08 2017 -0400 +++ b/common/core/src/test/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizerTest.java Tue Sep 05 19:33:20 2017 +0200 @@ -39,7 +39,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -47,26 +46,22 @@ import java.util.HashSet; import java.util.Set; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; - import org.junit.Before; import org.junit.Test; import org.keycloak.KeycloakSecurityContext; import org.keycloak.representations.AccessToken; import com.redhat.thermostat.gateway.common.core.auth.Role; +import com.redhat.thermostat.gateway.common.core.auth.keycloak.KeycloakRealmAuthorizer.CannotReduceRealmsException; public class KeycloakRealmAuthorizerTest { - HttpServletRequest request; - AccessToken.Access access; + private AccessToken.Access access; + private KeycloakSecurityContext keycloakSecurityContext; @Before public void setup() { - request = mock(HttpServletRequest.class); - KeycloakSecurityContext keycloakSecurityContext = mock(KeycloakSecurityContext.class); - when(request.getAttribute(eq(KeycloakSecurityContext.class.getName()))).thenReturn(keycloakSecurityContext); + keycloakSecurityContext = mock(KeycloakSecurityContext.class); AccessToken accessToken = mock(AccessToken.class); when(keycloakSecurityContext.getToken()).thenReturn(accessToken); @@ -76,22 +71,22 @@ } @Test - public void testBuildSingleRealm() throws ServletException { + public void testBuildSingleRealm() throws CannotReduceRealmsException { String[] roles = new String[]{"a-realm"}; when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); Set realms = realmAuthorizer.getRealmsWithAction("a"); assertTrue(realms.contains("realm")); } @Test - public void testBuildMultipleRealms() throws ServletException { + public void testBuildMultipleRealms() throws CannotReduceRealmsException { String[] roles = new String[]{"a-realm", "b-another"}; when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); Set realms = realmAuthorizer.getRealmsWithAction("a"); assertTrue(realms.contains("realm")); @@ -103,11 +98,11 @@ } @Test - public void testBuildMultipleRealmsSameAction() throws ServletException { + public void testBuildMultipleRealmsSameAction() throws CannotReduceRealmsException { String[] roles = new String[]{"r-realm", "w-realm"}; when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); Set realms = realmAuthorizer.getRealmsWithAction("r"); @@ -118,21 +113,21 @@ } @Test - public void testBuildRoleWithoutRealm() throws ServletException { + public void testBuildRoleWithoutRealm() throws CannotReduceRealmsException { String[] roles = new String[]{"a-"}; when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); Set realms = realmAuthorizer.getAllRoles(); assertTrue(realms.isEmpty()); } @Test - public void testBuildInvalidRoleWithoutAction() throws ServletException { + public void testBuildInvalidRoleWithoutAction() throws CannotReduceRealmsException { String[] roles = new String[]{"-realm"}; when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); Set realms = realmAuthorizer.getAllRoles(); assertTrue(realms.isEmpty()); } @@ -144,10 +139,10 @@ } @Test - public void testReadable() throws ServletException { + public void testReadable() throws CannotReduceRealmsException { setupRealms(); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); assertTrue(realmAuthorizer.readable()); Set realms = realmAuthorizer.getReadableRealms(); @@ -156,10 +151,10 @@ } @Test - public void testWritable() throws ServletException { + public void testWritable() throws CannotReduceRealmsException { setupRealms(); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); assertTrue(realmAuthorizer.writable()); Set realms = realmAuthorizer.getWritableRealms(); @@ -168,10 +163,10 @@ } @Test - public void testUpdatable() throws ServletException { + public void testUpdatable() throws CannotReduceRealmsException { setupRealms(); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); assertTrue(realmAuthorizer.updatable()); Set realms = realmAuthorizer.getUpdatableRealms(); @@ -180,10 +175,10 @@ } @Test - public void testDeletable() throws ServletException { + public void testDeletable() throws CannotReduceRealmsException { setupRealms(); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); assertTrue(realmAuthorizer.deletable()); Set realms = realmAuthorizer.getDeletableRealms(); @@ -192,11 +187,11 @@ } @Test - public void testNotReadable() throws ServletException { + public void testNotReadable() throws CannotReduceRealmsException { String[] roles = new String[]{"w-write", "d-delete", "u-update"}; when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); assertFalse(realmAuthorizer.readable()); Set realms = realmAuthorizer.getReadableRealms(); @@ -204,11 +199,11 @@ } @Test - public void testNotWritable() throws ServletException { + public void testNotWritable() throws CannotReduceRealmsException { String[] roles = new String[]{"r-read", "d-delete", "u-update"}; when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); assertFalse(realmAuthorizer.writable()); Set realms = realmAuthorizer.getWritableRealms(); @@ -216,11 +211,11 @@ } @Test - public void testNotUpdatable() throws ServletException { + public void testNotUpdatable() throws CannotReduceRealmsException { String[] roles = new String[]{"w-write", "d-delete", "r-read"}; when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); assertFalse(realmAuthorizer.updatable()); Set realms = realmAuthorizer.getUpdatableRealms(); @@ -228,55 +223,15 @@ } @Test - public void testNotDeletable() throws ServletException { + public void testNotDeletable() throws CannotReduceRealmsException { String[] roles = new String[]{"w-write", "r-read", "u-update"}; when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); + KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(keycloakSecurityContext); assertFalse(realmAuthorizer.deletable()); Set realms = realmAuthorizer.getDeletableRealms(); assertEquals(0, realms.size()); } - @Test - public void testRealmsHeaderSubset() throws ServletException { - String[] roles = new String[]{"w-write", "r-read", "u-update"}; - when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - - when(request.getHeader(eq("X-Thermostat-Realms"))).thenReturn("read update"); - - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); - assertEquals(1, realmAuthorizer.getReadableRealms().size()); - assertEquals(1, realmAuthorizer.getUpdatableRealms().size()); - - assertEquals(0, realmAuthorizer.getWritableRealms().size()); - assertEquals(0, realmAuthorizer.getDeletableRealms().size()); - } - - @Test (expected = ServletException.class) - public void testRealmsHeaderSuperset() throws ServletException { - String[] roles = new String[]{"r-read,","u-update"}; - when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - - when(request.getHeader(eq("X-Thermostat-Realms"))).thenReturn("read update other"); - - new KeycloakRealmAuthorizer(request); - } - - @Test - public void testRealmsHeaderWhitespace() throws ServletException { - String[] roles = new String[]{"w-write", "r-read", "u-update"}; - when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - - when(request.getHeader(eq("X-Thermostat-Realms"))).thenReturn(" read update\twrite "); - - KeycloakRealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(request); - assertEquals(1, realmAuthorizer.getReadableRealms().size()); - assertEquals(1, realmAuthorizer.getUpdatableRealms().size()); - assertEquals(1, realmAuthorizer.getWritableRealms().size()); - - assertEquals(0, realmAuthorizer.getDeletableRealms().size()); - } - } diff -r 7499f1b499c1 -r 236e08b6fb0d server/src/main/java/com/redhat/thermostat/gateway/server/auth/basic/BasicAuthFilter.java --- a/server/src/main/java/com/redhat/thermostat/gateway/server/auth/basic/BasicAuthFilter.java Tue Sep 05 13:30:08 2017 -0400 +++ b/server/src/main/java/com/redhat/thermostat/gateway/server/auth/basic/BasicAuthFilter.java Tue Sep 05 19:33:20 2017 +0200 @@ -64,7 +64,7 @@ BasicWebUser user = (BasicWebUser)httpServletRequest.getUserPrincipal(); RealmAuthorizer realmAuthorizer; if (user == null) { - realmAuthorizer = new RealmAuthorizer() {}; // Deny-all realm authorizer + realmAuthorizer = RealmAuthorizer.DENY_ALL_AUTHORIZER; } else { realmAuthorizer = new BasicRealmAuthorizer(user); } diff -r 7499f1b499c1 -r 236e08b6fb0d server/src/main/java/com/redhat/thermostat/gateway/server/auth/keycloak/KeycloakRequestFilter.java --- a/server/src/main/java/com/redhat/thermostat/gateway/server/auth/keycloak/KeycloakRequestFilter.java Tue Sep 05 13:30:08 2017 -0400 +++ b/server/src/main/java/com/redhat/thermostat/gateway/server/auth/keycloak/KeycloakRequestFilter.java Tue Sep 05 19:33:20 2017 +0200 @@ -48,7 +48,8 @@ import javax.servlet.http.HttpServletResponse; import com.redhat.thermostat.gateway.common.core.auth.RealmAuthorizer; -import com.redhat.thermostat.gateway.common.core.auth.keycloak.KeycloakRealmAuthorizer; +import com.redhat.thermostat.gateway.common.core.auth.keycloak.KeycloakRealmAuthorizer.CannotReduceRealmsException; +import com.redhat.thermostat.gateway.common.core.auth.keycloak.KeycloakRealmAuthorizerServletAdapter; public class KeycloakRequestFilter implements Filter { @Override @@ -60,12 +61,13 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { HttpServletRequest httpServletRequest = (HttpServletRequest) request; - RealmAuthorizer realmAuthorizer = new KeycloakRealmAuthorizer(httpServletRequest); + KeycloakRealmAuthorizerServletAdapter adapter = new KeycloakRealmAuthorizerServletAdapter(); + RealmAuthorizer realmAuthorizer = adapter.createAuthorizer(httpServletRequest); httpServletRequest.setAttribute(RealmAuthorizer.class.getName(), realmAuthorizer); chain.doFilter(request, response); - } catch (ServletException e) { + } catch (CannotReduceRealmsException e) { HttpServletResponse httpServletResponse = (HttpServletResponse) response; httpServletResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid realms header"); } diff -r 7499f1b499c1 -r 236e08b6fb0d server/src/test/java/com/redhat/thermostat/gateway/server/auth/keycloak/KeycloakRequestFilterTest.java --- a/server/src/test/java/com/redhat/thermostat/gateway/server/auth/keycloak/KeycloakRequestFilterTest.java Tue Sep 05 13:30:08 2017 -0400 +++ b/server/src/test/java/com/redhat/thermostat/gateway/server/auth/keycloak/KeycloakRequestFilterTest.java Tue Sep 05 19:33:20 2017 +0200 @@ -59,6 +59,7 @@ import com.redhat.thermostat.gateway.common.core.auth.RealmAuthorizer; import com.redhat.thermostat.gateway.common.core.auth.keycloak.KeycloakRealmAuthorizer; +import com.redhat.thermostat.gateway.common.core.auth.keycloak.KeycloakRealmAuthorizerServletAdapter; public class KeycloakRequestFilterTest { @@ -101,7 +102,7 @@ String[] roles = new String[]{"a-realm"}; when(access.getRoles()).thenReturn(new HashSet<>(Arrays.asList(roles))); - when(request.getHeader(eq(KeycloakRealmAuthorizer.REALMS_HEADER))).thenReturn("blob"); + when(request.getHeader(eq(KeycloakRealmAuthorizerServletAdapter.REALMS_HEADER))).thenReturn("blob"); KeycloakRequestFilter keycloakRequestFilter = new KeycloakRequestFilter(); diff -r 7499f1b499c1 -r 236e08b6fb0d services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/channel/endpoints/RealmAuthorizerConfigurator.java --- a/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/channel/endpoints/RealmAuthorizerConfigurator.java Tue Sep 05 13:30:08 2017 -0400 +++ b/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/channel/endpoints/RealmAuthorizerConfigurator.java Tue Sep 05 19:33:20 2017 +0200 @@ -52,8 +52,6 @@ public class RealmAuthorizerConfigurator extends Configurator { - private static final RealmAuthorizer DENY_ALL_AUTHORIZER = new RealmAuthorizer() {}; - @Override public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) { Configuration serviceConfig = (Configuration)config.getUserProperties().get(GlobalConstants.SERVICE_CONFIG_KEY); @@ -62,12 +60,12 @@ if (isBasicAuthEnabled(serviceConfig)) { BasicWebUser user = (BasicWebUser)request.getUserPrincipal(); if (user == null) { - realmAuthorizer = DENY_ALL_AUTHORIZER; + realmAuthorizer = RealmAuthorizer.DENY_ALL_AUTHORIZER; } else { realmAuthorizer = new BasicRealmAuthorizer(user); } } else { - realmAuthorizer = DENY_ALL_AUTHORIZER; + realmAuthorizer = RealmAuthorizer.DENY_ALL_AUTHORIZER; } config.getUserProperties().put(RealmAuthorizer.class.getName(), realmAuthorizer); }