changeset 233:f872349e7038

Align all microservices for BASIC auth. Reviewed-by: jkang Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-August/024649.html
author Severin Gehwolf <sgehwolf@redhat.com>
date Wed, 23 Aug 2017 13:43:11 +0200
parents 8fe9127fb648
children 0e22b21cfe6c
files common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/basic/BasicRealmAuthorizer.java distribution/src/etc/basic-config.properties server/src/main/java/com/redhat/thermostat/gateway/server/auth/BasicAuthFilter.java server/src/main/java/com/redhat/thermostat/gateway/server/auth/basic/BasicAuthFilter.java server/src/main/java/com/redhat/thermostat/gateway/server/services/WebArchiveCoreService.java server/src/test/java/com/redhat/thermostat/gateway/server/services/WebArchiveCoreServiceTest.java services/commands/etc/commands/basic-users.properties services/commands/etc/commands/service-config.properties services/commands/pom.xml services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/http/handlers/CommandChannelAgentEndpointHandler.java services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/http/handlers/CommandChannelClientEndpointHandler.java services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/http/handlers/RealmAuthorizerConfigurator.java services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/socket/CommandChannelAgentSocket.java services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/socket/CommandChannelClientSocket.java services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/socket/CommandChannelWebSocket.java services/commands/src/main/webapp/WEB-INF/web.xml services/commands/src/test/java/com/redhat/thermostat/gateway/service/commands/http/handlers/AuthBasicCoreServerTest.java services/commands/src/test/java/com/redhat/thermostat/gateway/service/commands/http/handlers/CommandChannelEndpointHandlerTest.java services/jvm-gc/src/main/webapp/WEB-INF/web.xml services/jvm-memory/src/main/webapp/WEB-INF/web.xml services/jvms/src/main/webapp/WEB-INF/web.xml services/system-cpu/src/main/webapp/WEB-INF/web.xml services/system-memory/src/main/webapp/WEB-INF/web.xml services/system-network/src/main/webapp/WEB-INF/web.xml services/systems/src/main/webapp/WEB-INF/web.xml tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/tests/integration/IntegrationTest.java
diffstat 26 files changed, 283 insertions(+), 206 deletions(-) [+]
line wrap: on
line diff
--- a/common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/basic/BasicRealmAuthorizer.java	Wed Aug 23 08:34:51 2017 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/gateway/common/core/auth/basic/BasicRealmAuthorizer.java	Wed Aug 23 13:43:11 2017 +0200
@@ -44,18 +44,21 @@
 import com.redhat.thermostat.gateway.common.core.auth.RealmAuthorizer;
 import com.redhat.thermostat.gateway.common.core.auth.Role;
 import com.redhat.thermostat.gateway.common.core.auth.RoleFactory;
-import com.redhat.thermostat.gateway.common.core.auth.basic.BasicWebUser;
 
 public class BasicRealmAuthorizer extends RealmAuthorizer {
     public static final String DEFAULT_REALM = "thermostat";
 
-    public BasicRealmAuthorizer(BasicWebUser user) throws InvalidRoleException {
+    public BasicRealmAuthorizer(BasicWebUser user) {
         RoleFactory roleFactory = new RoleFactory();
 
         Set<Role> roles = new HashSet<>();
         for (String role : user.getRoles()) {
-            Role r = roleFactory.buildRole(role);
-            roles.add(r);
+            try {
+                Role r = roleFactory.buildRole(role);
+                roles.add(r);
+            } catch (InvalidRoleException e) {
+                // ignore role
+            }
         }
 
         clientRoles = Collections.unmodifiableSet(roles);
--- a/distribution/src/etc/basic-config.properties	Wed Aug 23 08:34:51 2017 -0400
+++ b/distribution/src/etc/basic-config.properties	Wed Aug 23 13:43:11 2017 +0200
@@ -1,2 +1,2 @@
-agent=agent-pwd,r-thermostat,w-thermostat,u-thermostat,d-thermostat
-client=client-pwd,r-thermostat
\ No newline at end of file
+agent=agent-pwd,r-thermostat,w-thermostat,u-thermostat,d-thermostat,receiver_provider-commands,thermostat
+client=client-pwd,r-thermostat,kill_vm-commands,ping-commands,thermostat
\ No newline at end of file
--- a/server/src/main/java/com/redhat/thermostat/gateway/server/auth/BasicAuthFilter.java	Wed Aug 23 08:34:51 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,129 +0,0 @@
-/*
- * 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.server.auth;
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.NotAuthorizedException;
-import javax.ws.rs.core.HttpHeaders;
-import javax.xml.bind.DatatypeConverter;
-
-import com.redhat.thermostat.gateway.common.core.auth.basic.BasicRealmAuthorizer;
-import com.redhat.thermostat.gateway.common.core.auth.InvalidRoleException;
-import com.redhat.thermostat.gateway.common.core.auth.RealmAuthorizer;
-import com.redhat.thermostat.gateway.server.auth.basic.BasicUserStore;
-import com.redhat.thermostat.gateway.common.core.auth.basic.BasicWebUser;
-
-public class BasicAuthFilter implements Filter {
-    private BasicUserStore userStore;
-
-    public BasicAuthFilter(BasicUserStore userStore) {
-        this.userStore = userStore;
-    }
-
-    @Override
-    public void init(FilterConfig filterConfig) throws ServletException {
-        // Do nothing
-    }
-
-    @Override
-    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
-        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
-
-        String authentication = httpServletRequest.getHeader(HttpHeaders.AUTHORIZATION);
-        if (authentication == null) {
-            sendHttpUnauth(response);
-            return;
-        }
-
-        if (!authentication.startsWith("Basic ")) {
-            sendHttpUnauth(response);
-            return;
-        }
-
-        authentication = authentication.substring("Basic ".length());
-        String[] values = new String(DatatypeConverter.parseBase64Binary(authentication),
-                Charset.forName("ASCII")).split(":");
-        if (values.length < 2) {
-            sendHttpUnauth(response);
-            return;
-        }
-
-        String username = values[0];
-        String password = values[1];
-
-        BasicWebUser user = userStore.getUser(username);
-        if (user == null) {
-            sendHttpUnauth(response);
-            return;
-        }
-
-        if (!user.getPassword().equals(password)) {
-            sendHttpUnauth(response);
-            return;
-        }
-
-        try {
-            RealmAuthorizer realmAuthorizer = new BasicRealmAuthorizer(user);
-            httpServletRequest.setAttribute(RealmAuthorizer.class.getName(), realmAuthorizer);
-
-            chain.doFilter(request, response);
-        } catch (InvalidRoleException e) {
-            throw new IllegalStateException("Unable to create DefaultRealmAuthorizer", e);
-        }
-    }
-
-    private void sendHttpUnauth(ServletResponse response) throws IOException {
-        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
-        httpServletResponse.setHeader("WWW-Authenticate", "Basic realm=\"thermostat\"");
-        httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
-    }
-
-    @Override
-    public void destroy() {
-        // Do nothing
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/main/java/com/redhat/thermostat/gateway/server/auth/basic/BasicAuthFilter.java	Wed Aug 23 13:43:11 2017 +0200
@@ -0,0 +1,81 @@
+/*
+ * 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.server.auth.basic;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import com.redhat.thermostat.gateway.common.core.auth.RealmAuthorizer;
+import com.redhat.thermostat.gateway.common.core.auth.basic.BasicRealmAuthorizer;
+import com.redhat.thermostat.gateway.common.core.auth.basic.BasicWebUser;
+
+public class BasicAuthFilter implements Filter {
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        // Do nothing
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+
+        BasicWebUser user = (BasicWebUser)httpServletRequest.getUserPrincipal();
+        RealmAuthorizer realmAuthorizer;
+        if (user == null) {
+            realmAuthorizer = new RealmAuthorizer() {}; // Deny-all realm authorizer
+        } else {
+            realmAuthorizer = new BasicRealmAuthorizer(user);
+        }
+
+        httpServletRequest.setAttribute(RealmAuthorizer.class.getName(), realmAuthorizer);
+
+        chain.doFilter(request, response);
+    }
+
+    @Override
+    public void destroy() {
+        // Do nothing
+    }
+}
--- a/server/src/main/java/com/redhat/thermostat/gateway/server/services/WebArchiveCoreService.java	Wed Aug 23 08:34:51 2017 -0400
+++ b/server/src/main/java/com/redhat/thermostat/gateway/server/services/WebArchiveCoreService.java	Wed Aug 23 13:43:11 2017 +0200
@@ -47,8 +47,7 @@
 
 import org.eclipse.jetty.security.ConstraintMapping;
 import org.eclipse.jetty.security.ConstraintSecurityHandler;
-import org.eclipse.jetty.security.LoginService;
-import org.eclipse.jetty.security.SecurityHandler;
+import org.eclipse.jetty.security.authentication.BasicAuthenticator;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.servlet.FilterHolder;
 import org.eclipse.jetty.servlet.ServletContextHandler;
@@ -61,7 +60,7 @@
 import com.redhat.thermostat.gateway.common.core.config.IllegalConfigurationException;
 import com.redhat.thermostat.gateway.common.core.config.ServiceConfiguration;
 import com.redhat.thermostat.gateway.common.core.servlet.GlobalConstants;
-import com.redhat.thermostat.gateway.server.auth.BasicAuthFilter;
+import com.redhat.thermostat.gateway.server.auth.basic.BasicAuthFilter;
 import com.redhat.thermostat.gateway.server.auth.basic.BasicLoginService;
 import com.redhat.thermostat.gateway.server.auth.basic.BasicUserStore;
 import com.redhat.thermostat.gateway.server.auth.keycloak.KeycloakConfiguration;
@@ -70,6 +69,9 @@
 
 class WebArchiveCoreService implements CoreService {
 
+    // Users need to be in at least this role for authentication to succeed.
+    // This applies for keycloak and basic.
+    private static final String AUTH_ACCESS_ROLE = "thermostat";
     private final String contextPath;
     private final String warPath;
     private final Configuration serviceConfig;
@@ -113,15 +115,25 @@
 
     private void setupBasicAuthForContext(WebAppContext webAppContext) {
         Map<String, String> userConfig = getBasicAuthUserConfig();
-        BasicUserStore userStore = new BasicUserStore(userConfig);
-        BasicAuthFilter basicAuthFilter = new BasicAuthFilter(userStore);
-        FilterHolder filterHolder = new FilterHolder(basicAuthFilter);
+        ConstraintSecurityHandler security = new ConstraintSecurityHandler();
+        String realmName = "Thermostat Realm"; // must match name of login service
+        Constraint cons = new Constraint();
+        cons.setName(realmName);
+        cons.setRoles(new String[] { AUTH_ACCESS_ROLE });
+        cons.setAuthenticate(true);
+        cons.setDataConstraint(Constraint.DC_CONFIDENTIAL);
+        ConstraintMapping mapping = new ConstraintMapping();
+        mapping.setConstraint(cons);
+        mapping.setMethodOmissions(new String[] {});
+        mapping.setPathSpec("/*");
+        security.setConstraintMappings(Collections.singletonList(mapping));
+        security.setAuthenticator(new BasicAuthenticator());
+        security.setLoginService(new BasicLoginService(new BasicUserStore(userConfig), realmName));
+        webAppContext.setSecurityHandler(security);
 
+        // Add the realm authorizer
+        FilterHolder filterHolder = new FilterHolder(new BasicAuthFilter());
         webAppContext.addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
-
-        SecurityHandler security = webAppContext.getSecurityHandler();
-        LoginService loginService = new BasicLoginService(userStore, security.getRealmName());
-        security.setLoginService(loginService);
     }
 
     private void setupKeycloakAuthForContext(WebAppContext webAppContext) {
@@ -137,7 +149,7 @@
 
         Constraint constraint = new Constraint();
         constraint.setName(Constraint.__BASIC_AUTH);
-        constraint.setRoles(new String[]{"thermostat"});
+        constraint.setRoles(new String[]{ AUTH_ACCESS_ROLE });
         constraint.setAuthenticate(true);
 
         ConstraintMapping constraintMapping = new ConstraintMapping();
--- a/server/src/test/java/com/redhat/thermostat/gateway/server/services/WebArchiveCoreServiceTest.java	Wed Aug 23 08:34:51 2017 -0400
+++ b/server/src/test/java/com/redhat/thermostat/gateway/server/services/WebArchiveCoreServiceTest.java	Wed Aug 23 13:43:11 2017 +0200
@@ -58,7 +58,6 @@
 import org.keycloak.adapters.jetty.KeycloakJettyAuthenticator;
 
 import com.redhat.thermostat.gateway.common.core.config.Configuration;
-import com.redhat.thermostat.gateway.common.core.config.GlobalConfiguration;
 import com.redhat.thermostat.gateway.common.core.config.IllegalConfigurationException;
 import com.redhat.thermostat.gateway.common.core.config.ServiceConfiguration;
 import com.redhat.thermostat.gateway.common.core.servlet.GlobalConstants;
--- a/services/commands/etc/commands/basic-users.properties	Wed Aug 23 08:34:51 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-# Agent user(s)
-foo-agent-user=agent-pwd,thermostat-commands-realm,thermostat-commands-receiver-provider
-agent-user=agent-pwd,thermostat-commands-realm,thermostat-commands-receiver-provider
-# Client user
-bar-client-user=client-pwd,thermostat-commands-realm,thermostat-commands-grant-kill_vm,thermostat-commands-grant-ping
--- a/services/commands/etc/commands/service-config.properties	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/commands/etc/commands/service-config.properties	Wed Aug 23 13:43:11 2017 +0200
@@ -1,3 +1,1 @@
-SECURITY_BASIC=true
-properties|SECURITY_BASIC_USERS=basic-users.properties
 WEBSOCKETS=true
\ No newline at end of file
--- a/services/commands/pom.xml	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/commands/pom.xml	Wed Aug 23 13:43:11 2017 +0200
@@ -51,12 +51,25 @@
   <name>Thermostat Web Gateway Command Channel Service</name>
 
   <properties>
+    <com.redhat.thermostat.gateway.SERVICE_NAME>commands</com.redhat.thermostat.gateway.SERVICE_NAME>
+    <!-- Needed for the plugin config assembly -->
     <thermostat.microservice.name>commands</thermostat.microservice.name>
   </properties>
 
   <build>
     <plugins>
       <plugin>
+        <artifactId>maven-war-plugin</artifactId>
+          <configuration>
+          <webResources>
+            <resource>
+              <directory>src/main/webapp</directory>
+              <filtering>true</filtering>
+            </resource>
+          </webResources>
+        </configuration>
+      </plugin>
+      <plugin>
         <artifactId>maven-assembly-plugin</artifactId>
         <version>3.0.0</version>
         <dependencies>
--- a/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/http/handlers/CommandChannelAgentEndpointHandler.java	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/http/handlers/CommandChannelAgentEndpointHandler.java	Wed Aug 23 13:43:11 2017 +0200
@@ -58,7 +58,8 @@
 @ServerEndpoint(
         value = "/v1/systems/{systemId}/agents/{agentId}",
         encoders = { AgentRequestEncoder.class, WebSocketResponseEncoder.class },
-        decoders = { MessageDecoder.class }
+        decoders = { MessageDecoder.class },
+        configurator = RealmAuthorizerConfigurator.class
 )
 public class CommandChannelAgentEndpointHandler extends CommandChannelEndpointHandler {
 
--- a/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/http/handlers/CommandChannelClientEndpointHandler.java	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/http/handlers/CommandChannelClientEndpointHandler.java	Wed Aug 23 13:43:11 2017 +0200
@@ -61,7 +61,8 @@
 @ServerEndpoint(
         value = "/v1/actions/{action}/systems/{systemId}/agents/{agentId}/jvms/{jvmId}/sequence/{seqId}",
         encoders = { AgentRequestEncoder.class, WebSocketResponseEncoder.class },
-        decoders = { MessageDecoder.class }
+        decoders = { MessageDecoder.class },
+        configurator = RealmAuthorizerConfigurator.class
 )
 public class CommandChannelClientEndpointHandler extends CommandChannelEndpointHandler {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/http/handlers/RealmAuthorizerConfigurator.java	Wed Aug 23 13:43:11 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.service.commands.http.handlers;
+
+import javax.websocket.HandshakeResponse;
+import javax.websocket.server.HandshakeRequest;
+import javax.websocket.server.ServerEndpointConfig;
+import javax.websocket.server.ServerEndpointConfig.Configurator;
+
+import com.redhat.thermostat.gateway.common.core.auth.RealmAuthorizer;
+import com.redhat.thermostat.gateway.common.core.auth.basic.BasicRealmAuthorizer;
+import com.redhat.thermostat.gateway.common.core.auth.basic.BasicWebUser;
+
+public class RealmAuthorizerConfigurator extends Configurator {
+
+    @Override
+    public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
+        // FIXME: Set up proper realm authorizer based on config
+        BasicWebUser user = (BasicWebUser)request.getUserPrincipal();
+        RealmAuthorizer realmAuthorizer;
+        if (user == null) {
+            realmAuthorizer = new RealmAuthorizer() {}; // deny-all authorizer
+        } else {
+            realmAuthorizer = new BasicRealmAuthorizer(user);
+        }
+        config.getUserProperties().put(RealmAuthorizer.class.getName(), realmAuthorizer);
+    }
+}
--- a/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/socket/CommandChannelAgentSocket.java	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/socket/CommandChannelAgentSocket.java	Wed Aug 23 13:43:11 2017 +0200
@@ -39,6 +39,7 @@
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -46,7 +47,7 @@
 import javax.websocket.PongMessage;
 import javax.websocket.Session;
 
-import com.redhat.thermostat.gateway.common.core.auth.basic.RoleAwareUser;
+import com.redhat.thermostat.gateway.common.core.auth.RealmAuthorizer;
 import com.redhat.thermostat.gateway.common.util.LoggingUtil;
 import com.redhat.thermostat.gateway.service.commands.channel.ClientAgentCommunication;
 import com.redhat.thermostat.gateway.service.commands.channel.CommunicationsRegistry;
@@ -58,7 +59,7 @@
     private static final Logger logger = LoggingUtil.getLogger(CommandChannelAgentSocket.class);
     private static final long SOCKET_SESSION_IDLE_TIMEOUT = TimeUnit.MINUTES.toMillis(10);
     private static final String UNKNOWN_PAYLOAD = "UNKNOWN";
-    private static final String RECEIVER_PROVIDER_ROLE = "thermostat-commands-receiver-provider";
+    private static final String RECEIVER_PROVIDER_ACTION = "receiver_provider";
 
     CommandChannelAgentSocket(String id, Session session) {
         super(id, session);
@@ -136,9 +137,9 @@
 
     @Override
     protected boolean checkRoles() {
-        // FIXME: relies on RoleAwareUser - i.e. specific auth scheme.
-        RoleAwareUser user = (RoleAwareUser) session.getUserPrincipal();
-        if (!user.isUserInRole(RECEIVER_PROVIDER_ROLE)) {
+        RealmAuthorizer realmAuthorizer = (RealmAuthorizer)session.getUserProperties().get(RealmAuthorizer.class.getName());
+        Set<String> receiverProviderActions = realmAuthorizer.getRealmsWithAction(RECEIVER_PROVIDER_ACTION);
+        if (!receiverProviderActions.contains(COMMANDS_REALM)) {
             return false;
         }
         return true;
--- a/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/socket/CommandChannelClientSocket.java	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/socket/CommandChannelClientSocket.java	Wed Aug 23 13:43:11 2017 +0200
@@ -37,12 +37,13 @@
 package com.redhat.thermostat.gateway.service.commands.socket;
 
 import java.io.IOException;
+import java.util.Set;
 
 import javax.websocket.EncodeException;
 import javax.websocket.RemoteEndpoint.Basic;
 import javax.websocket.Session;
 
-import com.redhat.thermostat.gateway.common.core.auth.basic.RoleAwareUser;
+import com.redhat.thermostat.gateway.common.core.auth.RealmAuthorizer;
 import com.redhat.thermostat.gateway.service.commands.channel.ClientAgentCommunication;
 import com.redhat.thermostat.gateway.service.commands.channel.CommunicationsRegistry;
 import com.redhat.thermostat.gateway.service.commands.channel.WebSocketCommunicationBuilder;
@@ -53,7 +54,6 @@
 
 class CommandChannelClientSocket extends CommandChannelSocket {
 
-    private static final String CLIENT_GRANT_ACTION_PREFIX = "thermostat-commands-grant-";
     private static final String PATH_PARAM_ACTION = "action";
     private static final String PATH_PARAM_SYSTEM_ID = "systemId";
     private static final String PATH_PARAM_JVM_ID = "jvmId";
@@ -112,11 +112,10 @@
 
     @Override
     protected boolean checkRoles() {
-        // FIXME: relies on RoleAwareUser - i.e. specific auth scheme.
-        RoleAwareUser user = (RoleAwareUser) session.getUserPrincipal();
+        RealmAuthorizer realmAuthorizer = (RealmAuthorizer)session.getUserProperties().get(RealmAuthorizer.class.getName());
         String action = session.getPathParameters().get(PATH_PARAM_ACTION);
-        String actionAllowedRole = CLIENT_GRANT_ACTION_PREFIX + action;
-        if (!user.isUserInRole(actionAllowedRole)) {
+        Set<String> actionRealms = realmAuthorizer.getRealmsWithAction(action);
+        if (!actionRealms.contains(COMMANDS_REALM)) {
             return false;
         }
         // TODO: Add roles checks for systemId/jvmId, both part of the
--- a/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/socket/CommandChannelWebSocket.java	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/commands/src/main/java/com/redhat/thermostat/gateway/service/commands/socket/CommandChannelWebSocket.java	Wed Aug 23 13:43:11 2017 +0200
@@ -44,6 +44,8 @@
 
 public interface CommandChannelWebSocket {
 
+    String COMMANDS_REALM = "commands";
+
     void onClose(int code, String message);
 
     void onConnect() throws IOException;
--- a/services/commands/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/commands/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 13:43:11 2017 +0200
@@ -60,30 +60,12 @@
     <listener>
       <listener-class>com.redhat.thermostat.gateway.service.commands.servlet.SocketRegistrationListener</listener-class>
     </listener>
-    <security-constraint>
-      <web-resource-collection>
-        <web-resource-name>All of commands API</web-resource-name>
-        <url-pattern>/*</url-pattern>
-      </web-resource-collection>
-      <auth-constraint>
-        <role-name>thermostat-commands-realm</role-name>
-      </auth-constraint>
-    </security-constraint>
-    <!-- Allow viewing of API json spec without authentication -->
+    <!-- Allow viewing of API spec without authentication -->
     <security-constraint>
       <web-resource-collection>
         <web-resource-name>Swagger API SPEC YAML File</web-resource-name>
-        <url-pattern>/v1/static/doc/commands-swagger.yaml</url-pattern>
+        <url-pattern>/v1/static/doc/@com.redhat.thermostat.gateway.SERVICE_NAME@-swagger.yaml</url-pattern>
       </web-resource-collection>
       <!-- Explicitly no auth constraint for this file -->
     </security-constraint>
-
-    <login-config>
-      <auth-method>BASIC</auth-method>
-      <realm-name>Commands Realm</realm-name>
-    </login-config>
-
-    <security-role>
-      <role-name>thermostat-commands-realm</role-name>
-    </security-role>
 </web-app>
--- a/services/commands/src/test/java/com/redhat/thermostat/gateway/service/commands/http/handlers/AuthBasicCoreServerTest.java	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/commands/src/test/java/com/redhat/thermostat/gateway/service/commands/http/handlers/AuthBasicCoreServerTest.java	Wed Aug 23 13:43:11 2017 +0200
@@ -146,8 +146,8 @@
 
     protected static Map<String, String> getUserConfig() {
         Map<String, String> userConfig = new HashMap<>();
-        userConfig.put("foo-agent-user", "agent-pwd,thermostat-commands-receiver-provider");
-        userConfig.put("bar-client-user", "client-pwd,thermostat-commands-grant-dump-heap");
+        userConfig.put("foo-agent-user", "agent-pwd,receiver_provider-commands");
+        userConfig.put("bar-client-user", "client-pwd,dump_heap-commands");
         userConfig.put("insufficient-roles-agent", "agent-pwd");
         userConfig.put("insufficient-roles-client", "client-pwd");
         return userConfig;
--- a/services/commands/src/test/java/com/redhat/thermostat/gateway/service/commands/http/handlers/CommandChannelEndpointHandlerTest.java	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/commands/src/test/java/com/redhat/thermostat/gateway/service/commands/http/handlers/CommandChannelEndpointHandlerTest.java	Wed Aug 23 13:43:11 2017 +0200
@@ -46,13 +46,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import com.redhat.thermostat.gateway.service.commands.channel.coders.typeadapters.MessageTypeAdapterFactory;
-import com.redhat.thermostat.gateway.service.commands.channel.model.AgentRequest;
-import com.redhat.thermostat.gateway.service.commands.channel.model.ClientRequest;
-import com.redhat.thermostat.gateway.service.commands.channel.model.Message;
-import com.redhat.thermostat.gateway.service.commands.channel.model.Message.MessageType;
-import com.redhat.thermostat.gateway.service.commands.channel.model.WebSocketResponse;
-import com.redhat.thermostat.gateway.service.commands.channel.model.WebSocketResponse.ResponseType;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
@@ -61,6 +54,13 @@
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
+import com.redhat.thermostat.gateway.service.commands.channel.coders.typeadapters.MessageTypeAdapterFactory;
+import com.redhat.thermostat.gateway.service.commands.channel.model.AgentRequest;
+import com.redhat.thermostat.gateway.service.commands.channel.model.ClientRequest;
+import com.redhat.thermostat.gateway.service.commands.channel.model.Message;
+import com.redhat.thermostat.gateway.service.commands.channel.model.Message.MessageType;
+import com.redhat.thermostat.gateway.service.commands.channel.model.WebSocketResponse;
+import com.redhat.thermostat.gateway.service.commands.channel.model.WebSocketResponse.ResponseType;
 
 public class CommandChannelEndpointHandlerTest extends AuthBasicCoreServerTest {
 
@@ -84,7 +84,7 @@
         clientRequest.setSequenceId(clientSequence);
         String agentId = "testAgent";
         URI clientUri = new URI(
-                baseUrl + "actions/dump-heap/systems/foo/agents/" + agentId
+                baseUrl + "actions/dump_heap/systems/foo/agents/" + agentId
                         + "/jvms/abc/sequence/" + clientSequence);
         URI agentUri = new URI(baseUrl + "systems/foo/agents/" + agentId);
         final CountDownLatch clientHasSentMessages = new CountDownLatch(1);
@@ -148,7 +148,7 @@
         String clientUser = "bar-client-user";
         String agentId = "testAgent";
         URI clientUri = new URI(
-                baseUrl + "actions/dump-heap/systems/foo/agents/" + agentId
+                baseUrl + "actions/dump_heap/systems/foo/agents/" + agentId
                         + "/jvms/abc/sequence/" + sequenceId);
         final CountDownLatch clientHasSentMessages = new CountDownLatch(1);
         CmdChannelClientSocket clientSocket = new CmdChannelClientSocket(clientRequest, clientHasSentMessages);
@@ -388,7 +388,7 @@
         ClientRequest noMatter = new ClientRequest(clientSequence);
         String agentId = "testAgent";
         URI clientUri = new URI(
-                baseUrl + "actions/dump-heap/systems/foo/agents/" + agentId
+                baseUrl + "actions/dump_heap/systems/foo/agents/" + agentId
                         + "/jvms/abc/sequence/" + clientSequence);
         CmdChannelClientSocket clientSocket = new CmdChannelClientSocket(
                  noMatter /* doesn't matter */);
--- a/services/jvm-gc/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/jvm-gc/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 13:43:11 2017 +0200
@@ -77,4 +77,12 @@
     <listener>
         <listener-class>com.redhat.thermostat.gateway.common.mongodb.servlet.StorageConnectionSettingListener</listener-class>
     </listener>
-</web-app>
\ No newline at end of file
+    <!-- Allow viewing of API spec without authentication -->
+    <security-constraint>
+      <web-resource-collection>
+        <web-resource-name>Swagger API Spec File</web-resource-name>
+        <url-pattern>/0.0.2/doc/@com.redhat.thermostat.gateway.SERVICE_NAME@-swagger.yaml</url-pattern>
+      </web-resource-collection>
+      <!-- Explicitly no auth constraint for this file -->
+    </security-constraint>
+</web-app>
--- a/services/jvm-memory/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/jvm-memory/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 13:43:11 2017 +0200
@@ -77,4 +77,12 @@
     <listener>
         <listener-class>com.redhat.thermostat.gateway.common.mongodb.servlet.StorageConnectionSettingListener</listener-class>
     </listener>
+    <!-- Allow viewing of API spec without authentication -->
+    <security-constraint>
+      <web-resource-collection>
+        <web-resource-name>Swagger API Spec File</web-resource-name>
+        <url-pattern>/0.0.2/doc/@com.redhat.thermostat.gateway.SERVICE_NAME@-swagger.yaml</url-pattern>
+      </web-resource-collection>
+      <!-- Explicitly no auth constraint for this file -->
+    </security-constraint>
 </web-app>
--- a/services/jvms/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/jvms/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 13:43:11 2017 +0200
@@ -77,4 +77,12 @@
     <listener>
         <listener-class>com.redhat.thermostat.gateway.common.mongodb.servlet.StorageConnectionSettingListener</listener-class>
     </listener>
-</web-app>
\ No newline at end of file
+    <!-- Allow viewing of API spec without authentication -->
+    <security-constraint>
+      <web-resource-collection>
+        <web-resource-name>Swagger API Spec File</web-resource-name>
+        <url-pattern>/0.0.1/doc/@com.redhat.thermostat.gateway.SERVICE_NAME@-swagger.yaml</url-pattern>
+      </web-resource-collection>
+      <!-- Explicitly no auth constraint for this file -->
+    </security-constraint>
+</web-app>
--- a/services/system-cpu/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/system-cpu/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 13:43:11 2017 +0200
@@ -77,4 +77,12 @@
     <listener>
         <listener-class>com.redhat.thermostat.gateway.common.mongodb.servlet.StorageConnectionSettingListener</listener-class>
     </listener>
-</web-app>
\ No newline at end of file
+    <!-- Allow viewing of API spec without authentication -->
+    <security-constraint>
+      <web-resource-collection>
+        <web-resource-name>Swagger API Spec File</web-resource-name>
+        <url-pattern>/0.0.1/doc/@com.redhat.thermostat.gateway.SERVICE_NAME@-swagger.yaml</url-pattern>
+      </web-resource-collection>
+      <!-- Explicitly no auth constraint for this file -->
+    </security-constraint>
+</web-app>
--- a/services/system-memory/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/system-memory/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 13:43:11 2017 +0200
@@ -77,4 +77,12 @@
     <listener>
         <listener-class>com.redhat.thermostat.gateway.common.mongodb.servlet.StorageConnectionSettingListener</listener-class>
     </listener>
-</web-app>
\ No newline at end of file
+    <!-- Allow viewing of API spec without authentication -->
+    <security-constraint>
+      <web-resource-collection>
+        <web-resource-name>Swagger API Spec File</web-resource-name>
+        <url-pattern>/0.0.1/doc/@com.redhat.thermostat.gateway.SERVICE_NAME@-swagger.yaml</url-pattern>
+      </web-resource-collection>
+      <!-- Explicitly no auth constraint for this file -->
+    </security-constraint>
+</web-app>
--- a/services/system-network/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/system-network/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 13:43:11 2017 +0200
@@ -77,4 +77,12 @@
     <listener>
         <listener-class>com.redhat.thermostat.gateway.common.mongodb.servlet.StorageConnectionSettingListener</listener-class>
     </listener>
-</web-app>
\ No newline at end of file
+    <!-- Allow viewing of API spec without authentication -->
+    <security-constraint>
+      <web-resource-collection>
+        <web-resource-name>Swagger API Spec File</web-resource-name>
+        <url-pattern>/0.0.1/doc/@com.redhat.thermostat.gateway.SERVICE_NAME@-swagger.yaml</url-pattern>
+      </web-resource-collection>
+      <!-- Explicitly no auth constraint for this file -->
+    </security-constraint>
+</web-app>
--- a/services/systems/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 08:34:51 2017 -0400
+++ b/services/systems/src/main/webapp/WEB-INF/web.xml	Wed Aug 23 13:43:11 2017 +0200
@@ -77,4 +77,12 @@
     <listener>
         <listener-class>com.redhat.thermostat.gateway.common.mongodb.servlet.StorageConnectionSettingListener</listener-class>
     </listener>
-</web-app>
\ No newline at end of file
+    <!-- Allow viewing of API spec without authentication -->
+    <security-constraint>
+      <web-resource-collection>
+        <web-resource-name>Swagger API Spec File</web-resource-name>
+        <url-pattern>/0.0.1/doc/@com.redhat.thermostat.gateway.SERVICE_NAME@-swagger.yaml</url-pattern>
+      </web-resource-collection>
+      <!-- Explicitly no auth constraint for this file -->
+    </security-constraint>
+</web-app>
--- a/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/tests/integration/IntegrationTest.java	Wed Aug 23 08:34:51 2017 -0400
+++ b/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/tests/integration/IntegrationTest.java	Wed Aug 23 13:43:11 2017 +0200
@@ -105,7 +105,8 @@
         }
         AuthenticationStore authenticationStore = theclient.getAuthenticationStore();
         URI uri = URI.create(baseUrl);
-        authenticationStore.addAuthentication(new BasicAuthentication(uri, "thermostat", "agent", "agent-pwd"));
+        String realmName = "Thermostat Realm"; // must match Basic login service's realm name.
+        authenticationStore.addAuthentication(new BasicAuthentication(uri, realmName, "agent", "agent-pwd"));
         theclient.start();
         return theclient;
     }