changeset 247:236e08b6fb0d

Make KeycloakRealmAuthorizer servlet request independent. Reviewed-by: jkang Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/024837.html
author Severin Gehwolf <sgehwolf@redhat.com>
date Tue, 05 Sep 2017 19:33:20 +0200
parents 7499f1b499c1
children b951d7bc0308
files common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/RealmAuthorizer.java common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/basic/BasicRealmAuthorizer.java common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizer.java common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizerServletAdapter.java common/core/src/test/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizerServletAdapterTest.java common/core/src/test/java/com/redhat/thermostat/gateway/common/core/auth/keycloak/KeycloakRealmAuthorizerTest.java server/src/main/java/com/redhat/thermostat/gateway/server/auth/basic/BasicAuthFilter.java server/src/main/java/com/redhat/thermostat/gateway/server/auth/keycloak/KeycloakRequestFilter.java server/src/test/java/com/redhat/thermostat/gateway/server/auth/keycloak/KeycloakRequestFilterTest.java services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/channel/endpoints/RealmAuthorizerConfigurator.java
diffstat 10 files changed, 265 insertions(+), 127 deletions(-) [+]
line wrap: on
line diff
--- 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<Role> clientRoles = Collections.emptySet();
+    /**
+     * A RealmAuthorizer that will deny any request.
+     */
+    public static final RealmAuthorizer DENY_ALL_AUTHORIZER = new RealmAuthorizer(Collections.<Role>emptySet()) {};
+
+    protected final Set<Role> clientRoles;
+
+    protected RealmAuthorizer(Set<Role> clientRoles) {
+        this.clientRoles = clientRoles;
+    }
 
     public boolean readable() {
         return checkActionExists(Action.READ);
--- 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<Role> getAllRoles() {
+        return clientRoles;
+    }
+
+    private static Set<Role> buildRoles(BasicWebUser user) {
         RoleFactory roleFactory = new RoleFactory();
 
         Set<Role> roles = new HashSet<>();
@@ -61,13 +72,6 @@
             }
         }
 
-        clientRoles = Collections.unmodifiableSet(roles);
-    }
-
-    /**
-     * Package private for testing
-     */
-    Set<Role> getAllRoles() {
-        return clientRoles;
+        return Collections.unmodifiableSet(roles);
     }
 }
--- 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<Role> buildClientRoles(HttpServletRequest httpServletRequest) throws ServletException {
-        Set<Role> 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<Role> buildKeycloakRoles(HttpServletRequest httpServletRequest) {
+    private static Set<Role> buildClientRoles(KeycloakSecurityContext keycloakSecurityContext, String roleLimits) throws CannotReduceRealmsException {
+        final RoleFactory roleFactory = new RoleFactory();
         Set<Role> 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<Role> buildClientPreferredRoles(Set<Role> trustedRoles, String realmsHeader) throws ServletException {
-        realmsHeader = realmsHeader.trim();
-        Set<String> preferredRealms = new HashSet<>(Arrays.asList(realmsHeader.split(REALMS_HEADER_DELIMITER_REGEX)));
+    private static Set<Role> buildClientPreferredRoles(Set<Role> trustedRoles, String realmsLimits) throws CannotReduceRealmsException {
+        realmsLimits = realmsLimits.trim();
+        Set<String> preferredRealms = new HashSet<>(Arrays.asList(realmsLimits.split(REALMS_LIMITS_DELIMITER_REGEX)));
         Set<Role> 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);
+        }
+    }
 }
--- /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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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);
+    }
+}
--- /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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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());
+    }
+}
--- 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<String> 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<String> 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<String> 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<Role> 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<Role> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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());
-    }
-
 }
--- 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);
         }
--- 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");
         }
--- 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();
 
--- 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);
     }