This is an automated email from the ASF dual-hosted git repository.

jinmeiliao pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new 2e030f6  GEODE-7156: add token based authentication support in 
management rest… (#4005)
2e030f6 is described below

commit 2e030f61137bab475f89cabdb1c2d0fc9a9c293d
Author: Jinmei Liao <[email protected]>
AuthorDate: Thu Sep 5 17:43:04 2019 -0700

    GEODE-7156: add token based authentication support in management rest… 
(#4005)
    
    * GEODE-7156: add token based authentication support in management rest api
    
    Co-authored-by: Joris Melchior <[email protected]>
    
    * added security-auth-token-enabled-components property
    * pass this property to the management web application context
    * enabled auth token filter when that property is set
    * improve SimpleSecurityManager to authenticate mock token
---
 .../ManagementRestAuthTokenIntegrationTest.java    | 70 ++++++++++++++++++++
 .../integrationTest/resources/assembly_content.txt |  1 +
 .../InternalDistributedSystemJUnitTest.java        | 25 +++++++
 .../geode/distributed/ConfigurationProperties.java | 21 ++++++
 .../internal/AbstractDistributionConfig.java       | 11 +++-
 .../distributed/internal/DistributionConfig.java   | 25 +++++++
 .../internal/DistributionConfigImpl.java           | 27 +++++++-
 .../distributed/internal/InternalLocator.java      |  8 +++
 .../geode/examples/SimpleSecurityManager.java      | 15 ++++-
 .../org/apache/geode/internal/AbstractConfig.java  |  9 ++-
 .../geode/internal/cache/InternalHttpService.java  |  1 +
 .../internal/security/ResourceConstants.java       |  3 +-
 .../geode/security/AuthTokenEnabledComponents.java | 33 +++++-----
 .../org/apache/geode/security/SecurityManager.java | 20 +++++-
 .../sanctioned-geode-core-serializables.txt        |  1 +
 .../internal/DistributionConfigJUnitTest.java      | 22 ++++++-
 .../apache/geode/internal/AbstractConfigTest.java  |  9 ++-
 .../internal/rest/BaseLocatorContextLoader.java    |  2 +
 .../management/internal/rest/GeodeComponent.java   |  4 ++
 .../internal/rest/LocatorWebContext.java           |  9 ---
 .../internal/rest/SecuredLocatorContextLoader.java |  1 -
 ...dLocatorWithAuthTokenEnabledContextLoader.java} |  5 +-
 .../internal/rest/RequestWithAuthTokenTest.java    | 59 +++++++++++++++++
 .../rest/security/GeodeAuthenticationProvider.java | 24 +++++--
 .../rest/security/JwtAuthenticationFilter.java     | 77 ++++++++++++++++++++++
 .../rest/security/RestSecurityConfiguration.java   | 48 ++++++++++----
 .../rest/security/JwtAuthenticationFilterTest.java | 69 +++++++++++++++++++
 .../security/LogNoPasswordDistributedTest.java     |  2 +-
 28 files changed, 538 insertions(+), 63 deletions(-)

diff --git 
a/geode-assembly/src/integrationTest/java/org/apache/geode/rest/internal/web/ManagementRestAuthTokenIntegrationTest.java
 
b/geode-assembly/src/integrationTest/java/org/apache/geode/rest/internal/web/ManagementRestAuthTokenIntegrationTest.java
new file mode 100644
index 0000000..4f134d1
--- /dev/null
+++ 
b/geode-assembly/src/integrationTest/java/org/apache/geode/rest/internal/web/ManagementRestAuthTokenIntegrationTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license
+ * agreements. See the NOTICE file distributed with this work for additional 
information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache 
License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the 
License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.geode.rest.internal.web;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.examples.SimpleSecurityManager;
+import org.apache.geode.test.junit.rules.LocatorStarterRule;
+
+public class ManagementRestAuthTokenIntegrationTest {
+
+  @ClassRule
+  public static LocatorStarterRule locator = new LocatorStarterRule()
+      
.withProperty(ConfigurationProperties.SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS,
+          "all,management")
+      .withSecurityManager(SimpleSecurityManager.class)
+      .withHttpService()
+      .withAutoStart();
+
+  @Test
+  public void name() throws Exception {
+    String response =
+        requestUseBearerToken(
+            "http://localhost:"; + locator.getHttpPort() + 
"/management/experimental/ping", "bar");
+
+    assertThat(response).isEqualTo("pong");
+  }
+
+  private static String requestUseBearerToken(String stringUrl, String 
bearerToken)
+      throws Exception {
+    BufferedReader reader = null;
+    URL url = new URL(stringUrl);
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestProperty("Authorization", "Bearer " + bearerToken);
+    connection.setDoOutput(true);
+    connection.setRequestMethod("GET");
+    reader = new BufferedReader(new 
InputStreamReader(connection.getInputStream()));
+    String line = null;
+    StringWriter out =
+        new StringWriter(connection.getContentLength() > 0 ? 
connection.getContentLength() : 2048);
+    while ((line = reader.readLine()) != null) {
+      out.append(line);
+    }
+    String response = out.toString();
+    return response;
+  }
+}
diff --git a/geode-assembly/src/integrationTest/resources/assembly_content.txt 
b/geode-assembly/src/integrationTest/resources/assembly_content.txt
index 06731a4..1aac949 100644
--- a/geode-assembly/src/integrationTest/resources/assembly_content.txt
+++ b/geode-assembly/src/integrationTest/resources/assembly_content.txt
@@ -899,6 +899,7 @@ javadoc/org/apache/geode/redis/package-summary.html
 javadoc/org/apache/geode/redis/package-tree.html
 javadoc/org/apache/geode/security/AccessControl.html
 javadoc/org/apache/geode/security/AuthInitialize.html
+javadoc/org/apache/geode/security/AuthTokenEnabledComponents.html
 javadoc/org/apache/geode/security/AuthenticationFailedException.html
 javadoc/org/apache/geode/security/AuthenticationRequiredException.html
 javadoc/org/apache/geode/security/Authenticator.html
diff --git 
a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/InternalDistributedSystemJUnitTest.java
 
b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/InternalDistributedSystemJUnitTest.java
index d310a47..99329b0 100644
--- 
a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/InternalDistributedSystemJUnitTest.java
+++ 
b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/InternalDistributedSystemJUnitTest.java
@@ -30,12 +30,14 @@ import static 
org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
 import static 
org.apache.geode.distributed.ConfigurationProperties.MEMBERSHIP_PORT_RANGE;
 import static 
org.apache.geode.distributed.ConfigurationProperties.MEMBER_TIMEOUT;
 import static org.apache.geode.distributed.ConfigurationProperties.NAME;
+import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS;
 import static 
org.apache.geode.distributed.ConfigurationProperties.SERVER_SSL_ENABLED;
 import static 
org.apache.geode.distributed.ConfigurationProperties.SSL_ENABLED_COMPONENTS;
 import static 
org.apache.geode.distributed.ConfigurationProperties.START_LOCATOR;
 import static 
org.apache.geode.distributed.ConfigurationProperties.STATISTIC_ARCHIVE_FILE;
 import static 
org.apache.geode.distributed.ConfigurationProperties.STATISTIC_SAMPLE_RATE;
 import static 
org.apache.geode.distributed.ConfigurationProperties.STATISTIC_SAMPLING_ENABLED;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -678,6 +680,29 @@ public class InternalDistributedSystemJUnitTest {
   }
 
   @Test
+  public void testEmptySecurityAuthTokenProp() throws Exception {
+    Properties props = getCommonProperties();
+    props.setProperty(SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS, "");
+    DistributionConfig config1 = new DistributionConfigImpl(props, false);
+    assertThat(config1.getSecurityAuthTokenEnabledComponents()).hasSize(0);
+    Properties securityProps = config1.getSecurityProps();
+    
assertThat(securityProps.getProperty(SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS)).isEqualTo("");
+    assertThat(config1.getSecurityAuthTokenEnabledComponents()).hasSize(0);
+  }
+
+  @Test
+  public void testSecurityAuthTokenProp() throws Exception {
+    Properties props = getCommonProperties();
+    props.setProperty(SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS, "management");
+    DistributionConfig config1 = new DistributionConfigImpl(props, false);
+    
assertThat(config1.getSecurityAuthTokenEnabledComponents()).containsExactly("MANAGEMENT");
+    Properties securityProps = config1.getSecurityProps();
+    
assertThat(securityProps.getProperty(SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS))
+        .isEqualTo("management");
+    
assertThat(config1.getSecurityAuthTokenEnabledComponents()).containsExactly("MANAGEMENT");
+  }
+
+  @Test
   public void testSSLEnabledComponents() {
     Properties props = getCommonProperties();
     props.setProperty(SSL_ENABLED_COMPONENTS, "cluster,server");
diff --git 
a/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
 
b/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
index e88eb09..dd864e2 100644
--- 
a/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
+++ 
b/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
@@ -2003,6 +2003,27 @@ public interface ConfigurationProperties {
    * {@link org.apache.geode.security.SecurableCommunicationChannels} 
<U>Since</U>: Geode 1.0
    */
   String SSL_ENABLED_COMPONENTS = "ssl-enabled-components";
+
+  /**
+   * The static String definition of the 
<i>"security-auth-token-enabled-components"</i> property <a
+   * name="security-auth-token-enabled-components"/a>
+   * </p>
+   * <U>Description</U>: This setting is a comma delimited list of component 
names which works in
+   * conjunction with
+   * the {@link #SECURITY_MANAGER} properties. if security manager is enabled, 
this property will
+   * determine what rest end point will use token based authentication instead 
of basic
+   * (username/password)
+   * authentication.
+   * </p>
+   * <U>Componant names</U>: "all","management" <U>Since</U>: Geode 1.11
+   * "all": shorthand for all the security components that support token 
authentication.
+   * "management": the {@link #ENABLE_MANAGEMENT_REST_SERVICE Management REST 
Service}
+   *
+   * Note: listing components that are not enabled does nothing.
+   *
+   * Default: empty. All security components use basic (username/password) 
authentication
+   */
+  String SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS = SECURITY_PREFIX + 
"auth-token-enabled-components";
   /**
    * The static String definition of the <i>"ssl-ciphers"</i> property <a 
name="ssl-ciphers"/a>
    * </p>
diff --git 
a/geode-core/src/main/java/org/apache/geode/distributed/internal/AbstractDistributionConfig.java
 
b/geode-core/src/main/java/org/apache/geode/distributed/internal/AbstractDistributionConfig.java
index 71bf398..e7c043c 100644
--- 
a/geode-core/src/main/java/org/apache/geode/distributed/internal/AbstractDistributionConfig.java
+++ 
b/geode-core/src/main/java/org/apache/geode/distributed/internal/AbstractDistributionConfig.java
@@ -118,6 +118,7 @@ import static 
org.apache.geode.distributed.ConfigurationProperties.REDUNDANCY_ZO
 import static 
org.apache.geode.distributed.ConfigurationProperties.REMOTE_LOCATORS;
 import static 
org.apache.geode.distributed.ConfigurationProperties.REMOVE_UNRESPONSIVE_CLIENT;
 import static org.apache.geode.distributed.ConfigurationProperties.ROLES;
+import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS;
 import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_CLIENT_ACCESSOR;
 import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_CLIENT_ACCESSOR_PP;
 import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_CLIENT_AUTHENTICATOR;
@@ -756,7 +757,12 @@ public abstract class AbstractDistributionConfig extends 
AbstractConfig
     }
 
     if (attName.startsWith(SECURITY_PREFIX)) {
-      setSecurity(attName, attValue.toString());
+      // some security properties will be an array, such as 
security-auth-token-enabled-components
+      if (attValue instanceof Object[]) {
+        setSecurity(attName, StringUtils.join((Object[]) attValue, ','));
+      } else {
+        setSecurity(attName, attValue.toString());
+      }
     }
 
     if (attName.startsWith(SSL_SYSTEM_PROPS_NAME) || 
attName.startsWith(SYS_PROP_NAME)) {
@@ -1218,6 +1224,9 @@ public abstract class AbstractDistributionConfig extends 
AbstractConfig
     m.put(SECURITY_PREFIX,
         "Prefix for security related properties which are packed together and 
invoked as authentication parameter. Neither key nor value can be NULL. Legal 
tags can be [security-username, security-digitalid] and Legal values can be any 
string data.");
 
+    m.put(SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS,
+        "list of rest service to authenticate request with a Bearer token 
passed in the 'Authentication' header of the REST request. Otherwise BASIC 
authentication scheme is used. Possible value is a comma separated list of: 
'all', 'management'. This property is ignored if 'security-manager' is not set. 
Default value is empty.");
+
     m.put(USERDEFINED_PREFIX_NAME,
         "Prefix for user defined properties which are used for replacements in 
Cache.xml. Neither key nor value can be NULL. Legal tags can be 
[custom-any-string] and Legal values can be any string data.");
 
diff --git 
a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
 
b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
index e30d138..2d21361 100644
--- 
a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
+++ 
b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
@@ -118,6 +118,7 @@ import static 
org.apache.geode.distributed.ConfigurationProperties.REDUNDANCY_ZO
 import static 
org.apache.geode.distributed.ConfigurationProperties.REMOTE_LOCATORS;
 import static 
org.apache.geode.distributed.ConfigurationProperties.REMOVE_UNRESPONSIVE_CLIENT;
 import static org.apache.geode.distributed.ConfigurationProperties.ROLES;
+import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS;
 import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_CLIENT_ACCESSOR;
 import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_CLIENT_ACCESSOR_PP;
 import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_CLIENT_AUTHENTICATOR;
@@ -2623,6 +2624,27 @@ public interface DistributionConfig extends Config, 
LogConfig, StatisticsConfig
 
   String SECURITY_PREFIX_NAME = SECURITY_PREFIX;
 
+  /**
+   * Sets the value for
+   * {@link ConfigurationProperties#SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS}
+   */
+  @ConfigAttributeSetter(name = SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS)
+  void setSecurityAuthTokenEnabledComponents(String[] newValue);
+
+  /**
+   * Returns the value of
+   * {@link ConfigurationProperties#SSECURITY_AUTH_TOKEN_ENABLED_COMPONENTS} 
property
+   */
+  @ConfigAttributeGetter(name = SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS)
+  String[] getSecurityAuthTokenEnabledComponents();
+
+  /**
+   * the name of the {@link 
ConfigurationProperties#SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS}
+   * property
+   */
+  @ConfigAttribute(type = String[].class)
+  String SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS_NAME =
+      SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS;
 
   /**
    * The static String definition of the cluster ssl prefix 
<i>"cluster-ssl"</i> used in conjunction
@@ -4996,6 +5018,9 @@ public interface DistributionConfig extends Config, 
LogConfig, StatisticsConfig
   SecurableCommunicationChannel[] DEFAULT_SSL_ENABLED_COMPONENTS =
       new SecurableCommunicationChannel[] {};
 
+  @Immutable
+  String[] DEFAULT_SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS = new String[0];
+
   boolean DEFAULT_SSL_USE_DEFAULT_CONTEXT = false;
 
   @ConfigAttribute(type = Boolean.class)
diff --git 
a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
 
b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
index 2c9ac6e..c1a772b 100644
--- 
a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
+++ 
b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
@@ -91,6 +91,7 @@ import org.apache.geode.internal.ConfigSource;
 import org.apache.geode.internal.net.SocketCreator;
 import org.apache.geode.internal.process.ProcessLauncherContext;
 import org.apache.geode.internal.security.SecurableCommunicationChannel;
+import org.apache.geode.security.AuthTokenEnabledComponents;
 
 /**
  * Provides an implementation of <code>DistributionConfig</code> that knows 
how to read the
@@ -605,6 +606,8 @@ public class DistributionConfigImpl extends 
AbstractDistributionConfig implement
 
   private SecurableCommunicationChannel[] securableCommunicationChannels =
       DEFAULT_SSL_ENABLED_COMPONENTS;
+  private String[] securityAuthTokenEnabledComponents =
+      DEFAULT_SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS;
 
   private boolean sslUseDefaultSSLContext = DEFAULT_SSL_USE_DEFAULT_CONTEXT;
   private String sslProtocols = DEFAULT_SSL_PROTOCOLS;
@@ -866,8 +869,8 @@ public class DistributionConfigImpl extends 
AbstractDistributionConfig implement
     validateSerializableObjects = other.getValidateSerializableObjects();
     serializableObjectFilter = other.getSerializableObjectFilter();
 
-    // following added for 9.9
     enableManagementRestService = other.getEnableManagementRestService();
+    securityAuthTokenEnabledComponents = 
other.getSecurityAuthTokenEnabledComponents();
   }
 
   /**
@@ -2541,6 +2544,28 @@ public class DistributionConfigImpl extends 
AbstractDistributionConfig implement
   }
 
   @Override
+  public void setSecurityAuthTokenEnabledComponents(String[] newValue) {
+    // validate the value first
+    for (int i = 0; i < newValue.length; i++) {
+      String value = newValue[i];
+      try {
+        AuthTokenEnabledComponents.valueOf(value.toUpperCase());
+        // normalize the values to all uppercase
+        newValue[i] = value.toUpperCase();
+      } catch (Exception e) {
+        throw new IllegalArgumentException(
+            "Invalid security-auth-token-enabled-components value: " + value);
+      }
+    }
+    securityAuthTokenEnabledComponents = newValue;
+  }
+
+  @Override
+  public String[] getSecurityAuthTokenEnabledComponents() {
+    return securityAuthTokenEnabledComponents;
+  }
+
+  @Override
   public boolean getRemoveUnresponsiveClient() {
     return removeUnresponsiveClient;
   }
diff --git 
a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
 
b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
index 5685c85..ff5884d 100644
--- 
a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
+++ 
b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
@@ -29,6 +29,7 @@ import java.net.URI;
 import java.net.UnknownHostException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -98,6 +99,7 @@ import 
org.apache.geode.management.internal.configuration.handlers.SharedConfigu
 import 
org.apache.geode.management.internal.configuration.messages.ClusterManagementServiceInfoRequest;
 import 
org.apache.geode.management.internal.configuration.messages.SharedConfigurationStatusRequest;
 import 
org.apache.geode.management.internal.configuration.messages.SharedConfigurationStatusResponse;
+import org.apache.geode.security.AuthTokenEnabledComponents;
 
 /**
  * Provides the implementation of a distribution {@code Locator} as well as 
internal-only
@@ -760,6 +762,12 @@ public class InternalLocator extends Locator implements 
ConnectListener, LogConf
     
serviceAttributes.put(InternalHttpService.CLUSTER_MANAGEMENT_SERVICE_CONTEXT_PARAM,
         clusterManagementService);
 
+    String[] authEnabledComponents = 
distributionConfig.getSecurityAuthTokenEnabledComponents();
+
+    boolean managementAuthTokenEnabled = Arrays.stream(authEnabledComponents)
+        .anyMatch(AuthTokenEnabledComponents::hasManagement);
+    serviceAttributes.put(InternalHttpService.AUTH_TOKEN_ENABLED_PARAM, 
managementAuthTokenEnabled);
+
     if (distributionConfig.getEnableManagementRestService()) {
       internalCache.getHttpService().ifPresent(x -> {
         try {
diff --git 
a/geode-core/src/main/java/org/apache/geode/examples/SimpleSecurityManager.java 
b/geode-core/src/main/java/org/apache/geode/examples/SimpleSecurityManager.java
index 7743ddb..d97a2f3 100644
--- 
a/geode-core/src/main/java/org/apache/geode/examples/SimpleSecurityManager.java
+++ 
b/geode-core/src/main/java/org/apache/geode/examples/SimpleSecurityManager.java
@@ -14,6 +14,10 @@
  */
 package org.apache.geode.examples;
 
+import static org.apache.geode.security.SecurityManager.PASSWORD;
+import static org.apache.geode.security.SecurityManager.TOKEN;
+import static org.apache.geode.security.SecurityManager.USER_NAME;
+
 import java.util.Properties;
 
 import org.apache.geode.security.AuthenticationFailedException;
@@ -33,8 +37,12 @@ public class SimpleSecurityManager implements 
SecurityManager {
 
   @Override
   public Object authenticate(final Properties credentials) throws 
AuthenticationFailedException {
-    String username = credentials.getProperty("security-username");
-    String password = credentials.getProperty("security-password");
+    String token = credentials.getProperty(TOKEN);
+    if (token != null) {
+      return "Bearer " + token;
+    }
+    String username = credentials.getProperty(USER_NAME);
+    String password = credentials.getProperty(PASSWORD);
     if (username != null && username.equals(password)) {
       return username;
     }
@@ -43,6 +51,9 @@ public class SimpleSecurityManager implements SecurityManager 
{
 
   @Override
   public boolean authorize(final Object principal, final ResourcePermission 
permission) {
+    if (principal.toString().startsWith("Bearer ")) {
+      return true;
+    }
     String[] principals = principal.toString().toLowerCase().split(",");
     for (String role : principals) {
       String permissionString = permission.toString().replace(":", 
"").toLowerCase();
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/AbstractConfig.java 
b/geode-core/src/main/java/org/apache/geode/internal/AbstractConfig.java
index 8dc718b..75b0b16 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/AbstractConfig.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/AbstractConfig.java
@@ -36,6 +36,8 @@ import java.util.Properties;
 import java.util.StringTokenizer;
 import java.util.TreeSet;
 
+import org.apache.commons.lang3.StringUtils;
+
 import org.apache.geode.InternalGemFireException;
 import org.apache.geode.distributed.internal.FlowControlParams;
 import org.apache.geode.internal.net.SocketCreator;
@@ -222,7 +224,12 @@ public abstract class AbstractConfig implements Config {
       if (valueType.equals(String.class)) {
         attObjectValue = value;
       } else if (valueType.equals(String[].class)) {
-        attObjectValue = value.split(",");
+        // this would avoid converting empty string value to an array of size 
1.
+        if (StringUtils.isBlank(value)) {
+          attObjectValue = new String[0];
+        } else {
+          attObjectValue = value.split(",");
+        }
       } else if (valueType.equals(Integer.class)) {
         attObjectValue = Integer.valueOf(value);
       } else if (valueType.equals(Long.class)) {
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/cache/InternalHttpService.java
 
b/geode-core/src/main/java/org/apache/geode/internal/cache/InternalHttpService.java
index b001569..f381246 100644
--- 
a/geode-core/src/main/java/org/apache/geode/internal/cache/InternalHttpService.java
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/cache/InternalHttpService.java
@@ -43,6 +43,7 @@ import org.apache.geode.management.internal.SSLUtil;
 
 public class InternalHttpService implements HttpService {
 
+  public static final String AUTH_TOKEN_ENABLED_PARAM = 
"org.apache.geode.auth.token.enabled";
   private static final Logger logger = LogService.getLogger();
   private Server httpServer;
   private String bindAddress = "0.0.0.0";
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/security/ResourceConstants.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/security/ResourceConstants.java
index 1bac885..22f962c 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/security/ResourceConstants.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/security/ResourceConstants.java
@@ -118,6 +118,7 @@ public class ResourceConstants {
       "GemFire:service=AccessControl,type=Distributed";
   public static final String USER_NAME = "security-username";
   public static final String PASSWORD = "security-password";
+  public static final String TOKEN = "security-token";
 
   public static final String MBEAN_TYPE_DISTRIBUTED = "Distributed";
   public static final String MBEAN_TYPE_MEMBER = "Member";
@@ -147,6 +148,4 @@ public class ResourceConstants {
   public static final String GETTER_STATUS = "status";
 
   public static final String MANAGEMENT_PACKAGE = 
"org.apache.geode.management";
-
-
 }
diff --git 
a/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/GeodeComponent.java
 
b/geode-core/src/main/java/org/apache/geode/security/AuthTokenEnabledComponents.java
similarity index 61%
copy from 
geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/GeodeComponent.java
copy to 
geode-core/src/main/java/org/apache/geode/security/AuthTokenEnabledComponents.java
index 192dc0b..76fde33 100644
--- 
a/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/GeodeComponent.java
+++ 
b/geode-core/src/main/java/org/apache/geode/security/AuthTokenEnabledComponents.java
@@ -13,20 +13,21 @@
  * the License.
  */
 
-package org.apache.geode.management.internal.rest;
-
-import org.apache.geode.internal.security.SecurityService;
-import org.apache.geode.management.api.ClusterManagementService;
-
-public interface GeodeComponent {
-
-  void start();
-
-  void stop();
-
-  int getPort();
-
-  SecurityService getSecurityService();
-
-  ClusterManagementService getClusterManagementService();
+package org.apache.geode.security;
+
+public enum AuthTokenEnabledComponents {
+  /**
+   * This determines that all rest components will use token based 
authentication. <U>Since</U>:
+   * Geode 1.11
+   */
+  ALL,
+  /**
+   * This determines that management rest service will use token based 
authentication. <U>Since</U>:
+   * Geode 1.11
+   */
+  MANAGEMENT;
+
+  public static boolean hasManagement(String value) {
+    return ALL.name().equalsIgnoreCase(value) || 
MANAGEMENT.name().equalsIgnoreCase(value);
+  }
 }
diff --git 
a/geode-core/src/main/java/org/apache/geode/security/SecurityManager.java 
b/geode-core/src/main/java/org/apache/geode/security/SecurityManager.java
index b1065b3..301b3d5 100644
--- a/geode-core/src/main/java/org/apache/geode/security/SecurityManager.java
+++ b/geode-core/src/main/java/org/apache/geode/security/SecurityManager.java
@@ -25,6 +25,18 @@ import org.apache.geode.distributed.DistributedSystem;
  * @since Geode 1.0
  */
 public interface SecurityManager {
+  /**
+   * property name of the username passed in the Properties in authenticate 
method
+   */
+  String USER_NAME = "security-username";
+  /**
+   * property name of the password passed in the Properties in authenticate 
method
+   */
+  String PASSWORD = "security-password";
+  /**
+   * property name of the token passed in the Properties in authenticate method
+   */
+  String TOKEN = "security-token";
 
   /**
    * Initialize the SecurityManager. This is invoked when a cache is created
@@ -46,8 +58,12 @@ public interface SecurityManager {
    * property, so your securityManager implementation needs to validate these 
kind of properties
    * as well.
    *
-   * @param credentials it contains the security-username and 
security-password as keys of the
-   *        properties, also the properties generated by your AuthInitialize 
interface
+   * if a channel supports token-based-authentication, the token will be 
passed to the
+   * security manager in the property with the key "security-token".
+   *
+   * @param credentials it contains the security-username, security-password 
or security-token,
+   *        as keys of the properties, also the properties generated by your 
AuthInitialize
+   *        interface
    * @return a serializable principal object
    */
   Object authenticate(Properties credentials) throws 
AuthenticationFailedException;
diff --git 
a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
 
b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
index 70d25d1..b3507ca 100644
--- 
a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
+++ 
b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
@@ -585,6 +585,7 @@ 
org/apache/geode/pdx/PdxSerializationException,true,-3843814927034345635
 
org/apache/geode/pdx/internal/EnumInfo$PdxInstanceEnumInfo,true,7907582104525106416,ei:org/apache/geode/pdx/internal/EnumInfo,enumId:int
 org/apache/geode/pdx/internal/PdxInputStream,false
 
org/apache/geode/pdx/internal/PdxReaderImpl,true,-6094553093860427759,blobType:org/apache/geode/pdx/internal/PdxType,dis:org/apache/geode/pdx/internal/PdxInputStream
+org/apache/geode/security/AuthTokenEnabledComponents,false
 
org/apache/geode/security/AuthenticationFailedException,true,-8202866472279088879
 
org/apache/geode/security/AuthenticationRequiredException,true,4675976651103154919
 
org/apache/geode/security/GemFireSecurityException,true,3814254578203076926,cause:java/lang/Throwable
diff --git 
a/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionConfigJUnitTest.java
 
b/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionConfigJUnitTest.java
index a482892..fd53247 100644
--- 
a/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionConfigJUnitTest.java
+++ 
b/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionConfigJUnitTest.java
@@ -27,6 +27,7 @@ import static 
org.apache.geode.distributed.ConfigurationProperties.LOG_FILE_SIZE
 import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
 import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
 import static 
org.apache.geode.distributed.ConfigurationProperties.REDUNDANCY_ZONE;
+import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS;
 import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_LOG_LEVEL;
 import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_MANAGER;
 import static 
org.apache.geode.distributed.ConfigurationProperties.SECURITY_POST_PROCESSOR;
@@ -38,6 +39,7 @@ import static 
org.apache.geode.distributed.ConfigurationProperties.STATISTIC_ARC
 import static 
org.apache.geode.distributed.ConfigurationProperties.STATISTIC_SAMPLE_RATE;
 import static 
org.apache.geode.distributed.ConfigurationProperties.STATISTIC_SAMPLING_ENABLED;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -101,7 +103,7 @@ public class DistributionConfigJUnitTest {
   @Test
   public void testGetAttributeNames() {
     String[] attNames = AbstractDistributionConfig._getAttNames();
-    assertThat(attNames.length).isEqualTo(166);
+    assertThat(attNames.length).isEqualTo(167);
 
     List boolList = new ArrayList();
     List intList = new ArrayList();
@@ -139,7 +141,7 @@ public class DistributionConfigJUnitTest {
     assertEquals(35, intList.size());
     assertEquals(87, stringList.size());
     assertEquals(5, fileList.size());
-    assertEquals(4, otherList.size());
+    assertEquals(5, otherList.size());
   }
 
   @Test
@@ -450,4 +452,20 @@ public class DistributionConfigJUnitTest {
     DistributionConfig config = new DistributionConfigImpl(props);
     assertThat(config.getSSLEndPointIdentificationEnabled()).isEqualTo(true);
   }
+
+  @Test
+  public void invalidAuthToken() throws Exception {
+    Properties props = new Properties();
+    props.put(SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS, "manager");
+    assertThatThrownBy(() -> new DistributionConfigImpl(props))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void authTokenIsCaseInsensitive() throws Exception {
+    Properties props = new Properties();
+    props.put(SECURITY_AUTH_TOKEN_ENABLED_COMPONENTS, "MANAGEment");
+    DistributionConfig config = new DistributionConfigImpl(props);
+    
assertThat(config.getSecurityAuthTokenEnabledComponents()).containsExactly("MANAGEMENT");
+  }
 }
diff --git 
a/geode-core/src/test/java/org/apache/geode/internal/AbstractConfigTest.java 
b/geode-core/src/test/java/org/apache/geode/internal/AbstractConfigTest.java
index aebb928..12abe3e 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/AbstractConfigTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/AbstractConfigTest.java
@@ -15,7 +15,6 @@
 package org.apache.geode.internal;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.catchThrowable;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -52,14 +51,14 @@ public class AbstractConfigTest {
   public void setAttributeForStringArrayTypeWithEmpty() {
     abstractConfig.setAttribute(stringArrayAttributeName, "", source);
 
-    verify(abstractConfig).setAttributeObject(stringArrayAttributeName, new 
String[] {""}, source);
+    verify(abstractConfig).setAttributeObject(stringArrayAttributeName, new 
String[0], source);
   }
 
   @Test
   public void setAttributeForStringArrayTypeWithNull() {
-    Throwable thrown =
-        catchThrowable(() -> 
abstractConfig.setAttribute(stringArrayAttributeName, null, source));
-    assertThat(thrown).isInstanceOf(NullPointerException.class);
+    abstractConfig.setAttribute(stringArrayAttributeName, null, source);
+
+    verify(abstractConfig).setAttributeObject(stringArrayAttributeName, new 
String[0], source);
   }
 
   @Test
diff --git 
a/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/BaseLocatorContextLoader.java
 
b/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/BaseLocatorContextLoader.java
index f0068fa..f5dae84 100644
--- 
a/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/BaseLocatorContextLoader.java
+++ 
b/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/BaseLocatorContextLoader.java
@@ -41,6 +41,8 @@ public abstract class BaseLocatorContextLoader extends 
GenericXmlWebContextLoade
     context.getServletContext().setAttribute(
         InternalHttpService.CLUSTER_MANAGEMENT_SERVICE_CONTEXT_PARAM,
         getClusterManagementService());
+    
context.getServletContext().setAttribute(InternalHttpService.AUTH_TOKEN_ENABLED_PARAM,
+        isAuthTokenEnabled());
     context.getServletContext().setAttribute("locator", this);
   }
 }
diff --git 
a/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/GeodeComponent.java
 
b/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/GeodeComponent.java
index 192dc0b..2375999 100644
--- 
a/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/GeodeComponent.java
+++ 
b/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/GeodeComponent.java
@@ -29,4 +29,8 @@ public interface GeodeComponent {
   SecurityService getSecurityService();
 
   ClusterManagementService getClusterManagementService();
+
+  default boolean isAuthTokenEnabled() {
+    return false;
+  }
 }
diff --git 
a/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/LocatorWebContext.java
 
b/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/LocatorWebContext.java
index b3d1520..084d356 100644
--- 
a/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/LocatorWebContext.java
+++ 
b/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/LocatorWebContext.java
@@ -17,8 +17,6 @@ package org.apache.geode.management.internal.rest;
 
 import static 
org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
 
-import java.util.Properties;
-
 import org.springframework.test.web.client.MockMvcClientHttpRequestFactory;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.RequestBuilder;
@@ -58,13 +56,6 @@ public class LocatorWebContext {
     return (GeodeComponent) 
webApplicationContext.getServletContext().getAttribute("locator");
   }
 
-  public void login(String username, String password) {
-    Properties properties = new Properties();
-    properties.setProperty("security-username", username);
-    properties.setProperty("security-password", password);
-    getLocator().getSecurityService().login(properties);
-  }
-
   public MockMvcClientHttpRequestFactory getRequestFactory() {
     return requestFactory;
   }
diff --git 
a/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/SecuredLocatorContextLoader.java
 
b/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/SecuredLocatorContextLoader.java
index f3e3e2f..af82d9b 100644
--- 
a/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/SecuredLocatorContextLoader.java
+++ 
b/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/SecuredLocatorContextLoader.java
@@ -44,5 +44,4 @@ public class SecuredLocatorContextLoader extends 
BaseLocatorContextLoader {
   public ClusterManagementService getClusterManagementService() {
     return locator.getLocator().getClusterManagementService();
   }
-
 }
diff --git 
a/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/SecuredLocatorContextLoader.java
 
b/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/SecuredLocatorWithAuthTokenEnabledContextLoader.java
similarity index 91%
copy from 
geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/SecuredLocatorContextLoader.java
copy to 
geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/SecuredLocatorWithAuthTokenEnabledContextLoader.java
index f3e3e2f..8f8c62d 100644
--- 
a/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/SecuredLocatorContextLoader.java
+++ 
b/geode-web-management/src/commonTest/java/org/apache/geode/management/internal/rest/SecuredLocatorWithAuthTokenEnabledContextLoader.java
@@ -20,7 +20,7 @@ import org.apache.geode.internal.security.SecurityService;
 import org.apache.geode.management.api.ClusterManagementService;
 import org.apache.geode.test.junit.rules.LocatorStarterRule;
 
-public class SecuredLocatorContextLoader extends BaseLocatorContextLoader {
+public class SecuredLocatorWithAuthTokenEnabledContextLoader extends 
BaseLocatorContextLoader {
 
   private final LocatorStarterRule locator =
       new 
LocatorStarterRule().withSecurityManager(SimpleSecurityManager.class).withAutoStart();
@@ -45,4 +45,7 @@ public class SecuredLocatorContextLoader extends 
BaseLocatorContextLoader {
     return locator.getLocator().getClusterManagementService();
   }
 
+  public boolean isAuthTokenEnabled() {
+    return true;
+  }
 }
diff --git 
a/geode-web-management/src/integrationTest/java/org/apache/geode/management/internal/rest/RequestWithAuthTokenTest.java
 
b/geode-web-management/src/integrationTest/java/org/apache/geode/management/internal/rest/RequestWithAuthTokenTest.java
new file mode 100644
index 0000000..9f5d17b
--- /dev/null
+++ 
b/geode-web-management/src/integrationTest/java/org/apache/geode/management/internal/rest/RequestWithAuthTokenTest.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license
+ * agreements. See the NOTICE file distributed with this work for additional 
information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache 
License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the 
License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.rest;
+
+import static 
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.web.context.WebApplicationContext;
+
+
+@RunWith(SpringRunner.class)
+@ContextConfiguration(locations = 
{"classpath*:WEB-INF/management-servlet.xml"},
+    loader = SecuredLocatorWithAuthTokenEnabledContextLoader.class)
+@WebAppConfiguration
+public class RequestWithAuthTokenTest {
+
+  @Autowired
+  private WebApplicationContext webApplicationContext;
+
+  // needs to be used together with any LocatorContextLoader
+  private LocatorWebContext context;
+
+  @Before
+  public void before() {
+    context = new LocatorWebContext(webApplicationContext);
+
+  }
+
+  @Test
+  public void ping() throws Exception {
+    String accessToken = "foobar";
+    context.perform(get("/experimental/ping")
+        .header("Authorization", "Bearer " + accessToken))
+        .andExpect(status().isOk())
+        .andExpect(content().string("pong"));
+  }
+
+}
diff --git 
a/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/security/GeodeAuthenticationProvider.java
 
b/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/security/GeodeAuthenticationProvider.java
index e2a6cb5..4445529 100644
--- 
a/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/security/GeodeAuthenticationProvider.java
+++ 
b/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/security/GeodeAuthenticationProvider.java
@@ -38,6 +38,7 @@ import org.apache.geode.security.GemFireSecurityException;
 public class GeodeAuthenticationProvider implements AuthenticationProvider, 
ServletContextAware {
 
   private SecurityService securityService;
+  private boolean authTokenEnabled;
 
 
   public SecurityService getSecurityService() {
@@ -46,13 +47,20 @@ public class GeodeAuthenticationProvider implements 
AuthenticationProvider, Serv
 
   @Override
   public Authentication authenticate(Authentication authentication) throws 
AuthenticationException {
+    Properties credentials = new Properties();
     String username = authentication.getName();
     String password = authentication.getCredentials().toString();
-    Properties credentials = new Properties();
-    if (username != null)
-      credentials.put(ResourceConstants.USER_NAME, username);
-    if (password != null)
-      credentials.put(ResourceConstants.PASSWORD, password);
+
+    if (authTokenEnabled) {
+      if (password != null) {
+        credentials.setProperty(ResourceConstants.TOKEN, password);
+      }
+    } else {
+      if (username != null)
+        credentials.put(ResourceConstants.USER_NAME, username);
+      if (password != null)
+        credentials.put(ResourceConstants.PASSWORD, password);
+    }
 
     try {
       securityService.login(credentials);
@@ -68,9 +76,15 @@ public class GeodeAuthenticationProvider implements 
AuthenticationProvider, Serv
     return 
authentication.isAssignableFrom(UsernamePasswordAuthenticationToken.class);
   }
 
+  public boolean isAuthTokenEnabled() {
+    return authTokenEnabled;
+  }
+
   @Override
   public void setServletContext(ServletContext servletContext) {
     securityService = (SecurityService) servletContext
         
.getAttribute(InternalHttpService.SECURITY_SERVICE_SERVLET_CONTEXT_PARAM);
+    authTokenEnabled =
+        (Boolean) 
servletContext.getAttribute(InternalHttpService.AUTH_TOKEN_ENABLED_PARAM);
   }
 }
diff --git 
a/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/security/JwtAuthenticationFilter.java
 
b/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/security/JwtAuthenticationFilter.java
new file mode 100644
index 0000000..79faa29
--- /dev/null
+++ 
b/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/security/JwtAuthenticationFilter.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license
+ * agreements. See the NOTICE file distributed with this work for additional 
information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache 
License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the 
License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.rest.security;
+
+import java.io.IOException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.authentication.BadCredentialsException;
+import 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import 
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
+
+/**
+ * Json Web Token authentication filter. This would filter the requests with 
"Bearer" token in the
+ * authentication header, and put the token in the form of 
UsernamePasswordAuthenticationToken
+ * format for the downstream to consume.
+ */
+public class JwtAuthenticationFilter extends 
AbstractAuthenticationProcessingFilter {
+
+  public JwtAuthenticationFilter() {
+    super("/**");
+  }
+
+  @Override
+  protected boolean requiresAuthentication(HttpServletRequest request,
+      HttpServletResponse response) {
+    return true;
+  }
+
+  @Override
+  public Authentication attemptAuthentication(HttpServletRequest request,
+      HttpServletResponse response) throws AuthenticationException {
+
+    String header = request.getHeader("Authorization");
+
+    if (header == null || !header.startsWith("Bearer ")) {
+      throw new BadCredentialsException("No JWT token found in request 
headers, header: " + header);
+    }
+
+    String[] tokens = header.split(" ");
+
+    if (tokens.length != 2) {
+      throw new BadCredentialsException("Wrong authentication header format: " 
+ header);
+    }
+
+    return new UsernamePasswordAuthenticationToken(tokens[0], tokens[1]);
+  }
+
+  @Override
+  protected void successfulAuthentication(HttpServletRequest request, 
HttpServletResponse response,
+      FilterChain chain, Authentication authResult)
+      throws IOException, ServletException {
+    super.successfulAuthentication(request, response, chain, authResult);
+
+    // As this authentication is in HTTP header, after success we need to 
continue the request
+    // normally and return the response as if the resource was not secured at 
all
+    chain.doFilter(request, response);
+  }
+}
diff --git 
a/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/security/RestSecurityConfiguration.java
 
b/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/security/RestSecurityConfiguration.java
index 3786adc..d06148a 100644
--- 
a/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/security/RestSecurityConfiguration.java
+++ 
b/geode-web-management/src/main/java/org/apache/geode/management/internal/rest/security/RestSecurityConfiguration.java
@@ -36,6 +36,8 @@ import 
org.springframework.security.config.annotation.web.configuration.WebSecur
 import org.springframework.security.config.http.SessionCreationPolicy;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.web.AuthenticationEntryPoint;
+import 
org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import 
org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
 
 import org.apache.geode.management.api.ClusterManagementResult;
 
@@ -73,22 +75,40 @@ public class RestSecurityConfiguration extends 
WebSecurityConfigurerAdapter {
         .anyRequest().authenticated().and().csrf().disable();
 
     if (this.authProvider.getSecurityService().isIntegratedSecurity()) {
-      http.httpBasic().authenticationEntryPoint(new AuthenticationEntryPoint() 
{
-        @Override
-        public void commence(HttpServletRequest request, HttpServletResponse 
response,
-            AuthenticationException authException)
-            throws IOException, ServletException {
-          response.addHeader("WWW-Authenticate", "Basic realm=\"GEODE\"");
-          response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-          response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
-          ClusterManagementResult result =
-              new 
ClusterManagementResult(ClusterManagementResult.StatusCode.UNAUTHENTICATED,
-                  authException.getMessage());
-          objectMapper.writeValue(response.getWriter(), result);
-        }
-      });
+      if (authProvider.isAuthTokenEnabled()) {
+        JwtAuthenticationFilter tokenEndpointFilter = new 
JwtAuthenticationFilter();
+        tokenEndpointFilter.setAuthenticationSuccessHandler((request, 
response, authentication) -> {
+        });
+        tokenEndpointFilter.setAuthenticationFailureHandler(new 
AuthenticationFailedHandler());
+        http.addFilterBefore(tokenEndpointFilter, 
BasicAuthenticationFilter.class);
+      } else {
+        http.httpBasic().authenticationEntryPoint(new 
AuthenticationFailedHandler());
+      }
     } else {
       http.authorizeRequests().anyRequest().permitAll();
     }
   }
+
+  private class AuthenticationFailedHandler
+      implements AuthenticationFailureHandler, AuthenticationEntryPoint {
+    @Override
+    public void commence(HttpServletRequest request, HttpServletResponse 
response,
+        AuthenticationException authException)
+        throws IOException, ServletException {
+      response.addHeader("WWW-Authenticate", "Basic realm=\"GEODE\"");
+      response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+      response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
+      ClusterManagementResult result =
+          new 
ClusterManagementResult(ClusterManagementResult.StatusCode.UNAUTHENTICATED,
+              authException.getMessage());
+      objectMapper.writeValue(response.getWriter(), result);
+    }
+
+    @Override
+    public void onAuthenticationFailure(HttpServletRequest request, 
HttpServletResponse response,
+        AuthenticationException exception)
+        throws IOException, ServletException {
+      commence(request, response, exception);
+    }
+  }
 }
diff --git 
a/geode-web-management/src/test/java/org/apache/geode/management/internal/rest/security/JwtAuthenticationFilterTest.java
 
b/geode-web-management/src/test/java/org/apache/geode/management/internal/rest/security/JwtAuthenticationFilterTest.java
new file mode 100644
index 0000000..524e36d
--- /dev/null
+++ 
b/geode-web-management/src/test/java/org/apache/geode/management/internal/rest/security/JwtAuthenticationFilterTest.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license
+ * agreements. See the NOTICE file distributed with this work for additional 
information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache 
License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the 
License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.rest.security;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.core.Authentication;
+
+public class JwtAuthenticationFilterTest {
+
+  private JwtAuthenticationFilter filter;
+  private HttpServletRequest request;
+
+  @Before
+  public void before() throws Exception {
+    filter = new JwtAuthenticationFilter();
+    request = mock(HttpServletRequest.class);
+  }
+
+  @Test
+  public void nullHeader() throws Exception {
+    when(request.getHeader("Authorization")).thenReturn(null);
+    assertThatThrownBy(() -> filter.attemptAuthentication(request, null))
+        .isInstanceOf(BadCredentialsException.class);
+  }
+
+  @Test
+  public void notBearer() throws Exception {
+    when(request.getHeader("Authorization")).thenReturn("foo bar");
+    assertThatThrownBy(() -> filter.attemptAuthentication(request, null))
+        .isInstanceOf(BadCredentialsException.class);
+  }
+
+  @Test
+  public void wrongFormat() throws Exception {
+    when(request.getHeader("Authorization")).thenReturn("foo bar foo");
+    assertThatThrownBy(() -> filter.attemptAuthentication(request, null))
+        .isInstanceOf(BadCredentialsException.class);
+  }
+
+  @Test
+  public void correctHeader() throws Exception {
+    when(request.getHeader("Authorization")).thenReturn("Bearer bar");
+    Authentication authentication = filter.attemptAuthentication(request, 
null);
+    assertThat(authentication.getPrincipal().toString()).isEqualTo("Bearer");
+    assertThat(authentication.getCredentials().toString()).isEqualTo("bar");
+  }
+}
diff --git 
a/geode-web/src/distributedTest/java/org/apache/geode/management/internal/security/LogNoPasswordDistributedTest.java
 
b/geode-web/src/distributedTest/java/org/apache/geode/management/internal/security/LogNoPasswordDistributedTest.java
index 6d5e6a5..bad4101 100644
--- 
a/geode-web/src/distributedTest/java/org/apache/geode/management/internal/security/LogNoPasswordDistributedTest.java
+++ 
b/geode-web/src/distributedTest/java/org/apache/geode/management/internal/security/LogNoPasswordDistributedTest.java
@@ -81,7 +81,7 @@ public class LogNoPasswordDistributedTest {
     public Object authenticate(Properties properties) throws 
AuthenticationFailedException {
       String user = properties.getProperty("security-username");
       String password = properties.getProperty("security-password");
-      if (PASSWORD.equals(password)) {
+      if (LogNoPasswordDistributedTest.PASSWORD.equals(password)) {
         return user;
       }
 

Reply via email to