Skip to content
This repository has been archived by the owner on Jan 27, 2021. It is now read-only.

Commit

Permalink
GEODE-7851: Pulse Oauth Support (apache#4936)
Browse files Browse the repository at this point in the history
* GEODE-7851: Pulse Oauth Support

- create an OauthSecurityConfig to configure spring using oauth
- add PULSE as an oauth-enabled-component, and if pulse is set to use
  oauth, set the OauthSecurityConfig as the active security profile
- use pulse.properties in the locator's working dir to externalize pulse
  authentication provider configuration

Co-authored-by: Dale Emery <[email protected]>
Co-authored-by: Joris Melchior <[email protected]>
  • Loading branch information
demery-pivotal and jmelchio authored Apr 13, 2020
1 parent a1ed7f2 commit 3f9d32d
Show file tree
Hide file tree
Showing 66 changed files with 1,503 additions and 692 deletions.
3 changes: 3 additions & 0 deletions geode-assembly/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ dependencies {
integrationTestImplementation('org.springframework:spring-beans')
integrationTestImplementation('org.springframework:spring-context')
integrationTestImplementation('org.springframework:spring-web')
integrationTestImplementation('org.springframework.security:spring-security-oauth2-core')
integrationTestImplementation('org.springframework.security:spring-security-oauth2-client')
integrationTestImplementation('org.springframework.security:spring-security-oauth2-jose')
integrationTestImplementation('javax.annotation:javax.annotation-api')
integrationTestImplementation('javax.servlet:javax.servlet-api')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class EmbeddedPulseRule extends ExternalResource {

@Override
protected void before() throws Throwable {
repository = Repository.get();
repository = new Repository();
cleanup();
repository.setHost("localhost");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* 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.tools.pulse;

import static org.apache.geode.cache.RegionShortcut.REPLICATE;
import static org.assertj.core.api.Assertions.assertThat;

import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import org.apache.geode.examples.SimpleSecurityManager;
import org.apache.geode.test.junit.categories.PulseTest;
import org.apache.geode.test.junit.categories.SecurityTest;
import org.apache.geode.test.junit.rules.EmbeddedPulseRule;
import org.apache.geode.test.junit.rules.ServerStarterRule;
import org.apache.geode.tools.pulse.internal.data.Cluster;

@Category({SecurityTest.class, PulseTest.class})
public class EmbeddedPulseClusterSecurityTest {
private static final String QUERY = "select * from /regionA a order by a";

@Rule
public ServerStarterRule server = new ServerStarterRule()
.withSecurityManager(SimpleSecurityManager.class)
.withJMXManager()
.withHttpService()
.withRegion(REPLICATE, "regionA");

@Rule
public EmbeddedPulseRule pulse = new EmbeddedPulseRule();

@Before
public void useServerJmxPort() {
pulse.useJmxPort(server.getJmxPort());
}

@Test
public void acceptsAuthorizedUser() {
// The test security manager authorizes "data" to read data
String authorizedUser = "data";

Cluster cluster = pulse.getRepository()
.getClusterWithUserNameAndPassword(authorizedUser, authorizedUser);
ObjectNode queryResult = cluster.executeQuery(QUERY, null, 0);

assertThat(queryResult.toString())
.contains("No Data Found");
}

@Test
public void rejectsUnauthorizedUser() {
// The test security manager does not authorize "cluster" to read data
String unauthorizedUser = "cluster";

Cluster cluster = pulse.getRepository()
.getClusterWithUserNameAndPassword(unauthorizedUser, unauthorizedUser);
ObjectNode queryResult = cluster.executeQuery(QUERY, null, 0);

assertThat(queryResult.toString())
.contains("not authorized for DATA:READ");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,35 @@

package org.apache.geode.tools.pulse;

import static org.apache.geode.cache.RegionShortcut.REPLICATE;
import static org.assertj.core.api.Assertions.assertThat;

import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.http.HttpResponse;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.examples.SimpleSecurityManager;
import org.apache.geode.test.junit.categories.PulseTest;
import org.apache.geode.test.junit.categories.SecurityTest;
import org.apache.geode.test.junit.rules.EmbeddedPulseRule;
import org.apache.geode.test.junit.rules.GeodeHttpClientRule;
import org.apache.geode.test.junit.rules.ServerStarterRule;
import org.apache.geode.tools.pulse.internal.data.Cluster;


@Category({SecurityTest.class, PulseTest.class})
public class PulseSecurityTest {
public class EmbeddedPulseHttpSecurityTest {

@ClassRule
public static ServerStarterRule server =
new ServerStarterRule().withSecurityManager(SimpleSecurityManager.class)
.withJMXManager().withHttpService()
.withRegion(RegionShortcut.REPLICATE, "regionA");

@Rule
public EmbeddedPulseRule pulse = new EmbeddedPulseRule();
public static ServerStarterRule server = new ServerStarterRule()
.withSecurityManager(SimpleSecurityManager.class)
.withJMXManager()
.withHttpService()
.withRegion(REPLICATE, "regionA");

@Rule
public GeodeHttpClientRule client = new GeodeHttpClientRule(server::getHttpPort);


@Test
public void loginWithIncorrectPassword() throws Exception {
HttpResponse response = client.loginToPulse("data", "wrongPassword");
Expand All @@ -73,7 +67,6 @@ public void loginWithDataOnly() throws Exception {
assertThat(response.getStatusLine().getStatusCode()).isEqualTo(403);
}


@Test
public void loginAllAccess() throws Exception {
client.loginToPulseAndVerify("CLUSTER,DATA", "CLUSTER,DATA");
Expand All @@ -97,20 +90,6 @@ public void loginWithClusterOnly() throws Exception {
assertThat(response.getStatusLine().getStatusCode()).isEqualTo(403);
}

@Test
public void queryUsingEmbededPulseWillHaveAuthorizationEnabled() throws Exception {
pulse.useJmxPort(server.getJmxPort());
// using "cluster" to connect to jmx manager will not get authorized to execute query
Cluster cluster = pulse.getRepository().getCluster("cluster", "cluster");
ObjectNode result = cluster.executeQuery("select * from /regionA a order by a", null, 0);
assertThat(result.toString()).contains("cluster not authorized for DATA:READ");

// using "data" to connect to jmx manager will succeeed
cluster = pulse.getRepository().getCluster("data", "data");
result = cluster.executeQuery("select * from /regionA a order by a", null, 0);
assertThat(result.toString()).contains("No Data Found");
}

@Test
public void loginAfterLogout() throws Exception {
client.loginToPulseAndVerify("data", "data");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ public void setUp() throws Exception {
@Test
public void testConnectToJmx() throws Exception {
pulse.useJmxManager(jmxBindAddress, locator.getJmxPort());
Cluster cluster = pulse.getRepository().getCluster("admin", null);
Cluster cluster = pulse.getRepository().getClusterWithUserNameAndPassword("admin", null);
assertThat(cluster.isConnectedFlag()).isTrue();
assertThat(cluster.getServerCount()).isEqualTo(0);
}

@Test
public void testConnectToLocator() throws Exception {
pulse.useLocatorPort(locator.getPort());
Cluster cluster = pulse.getRepository().getCluster("admin", null);
Cluster cluster = pulse.getRepository().getClusterWithUserNameAndPassword("admin", null);
assertThat(cluster.isConnectedFlag()).isTrue();
assertThat(cluster.getServerCount()).isEqualTo(0);
assertThat(cluster.isAlive()).isTrue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ public class PulseSecurityConfigOAuthProfileTest {
.withSecurityManager(SimpleSecurityManager.class)
.withProperty("security-auth-token-enabled-components", "pulse");

@Rule
public GeodeHttpClientRule client = new GeodeHttpClientRule(locator::getHttpPort);

private static File pulsePropertyFile;

@BeforeClass
Expand All @@ -54,7 +57,8 @@ public static void setupPulsePropertyFile() throws Exception {
// dir as classpath to search for this property file
pulsePropertyFile = new File(locator.getWorkingDir(), "pulse.properties");
Properties properties = new Properties();
properties.setProperty("pulse.oauth.provider", "uaa");
properties.setProperty("pulse.oauth.providerId", "uaa");
properties.setProperty("pulse.oauth.providerName", "UAA");
properties.setProperty("pulse.oauth.clientId", "pulse");
properties.setProperty("pulse.oauth.clientSecret", "secret");
// have the authorization uri point to a known uri that locator itself can serve
Expand All @@ -70,9 +74,6 @@ public static void cleanup() {
pulsePropertyFile.delete();
}

@Rule
public GeodeHttpClientRule client = new GeodeHttpClientRule(locator::getHttpPort);

@Test
public void redirectToAuthorizationUriInPulseProperty() throws Exception {
HttpResponse response = client.get("/pulse/login.html");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class PulseSecurityIntegrationTest {
public EmbeddedPulseRule pulse = new EmbeddedPulseRule();

@Test
public void getAttributesWithSecurityManager() throws Exception {
public void getAttributesWithSecurityManager() {
pulse.useJmxPort(locator.getJmxPort());

ManagementService service =
Expand All @@ -50,9 +50,29 @@ public void getAttributesWithSecurityManager() throws Exception {
await()
.untilAsserted(() -> assertThat(service.getMemberMXBean()).isNotNull());

Cluster cluster = pulse.getRepository().getCluster("cluster", "cluster");
Cluster cluster = pulse.getRepository().getClusterWithUserNameAndPassword("cluster", "cluster");
Cluster.Member[] members = cluster.getMembers();
assertThat(members.length).isEqualTo(1);
assertThat(members[0].getName()).isEqualTo("locator");
}

@Test
public void getAttributesWithSecurityManagerAndTokenLogin() {
String tokenValue = "atleast20charactersoftokenimsure";
String userName = "cluster";

pulse.useJmxPort(locator.getJmxPort());

ManagementService service =
ManagementService.getExistingManagementService(locator.getLocator().getCache());

await()
.untilAsserted(() -> assertThat(service.getMemberMXBean()).isNotNull());

Cluster cluster = pulse.getRepository().getClusterWithCredentials(userName, tokenValue);
Cluster.Member[] members = cluster.getMembers();
assertThat(members.length).isEqualTo(1);
assertThat(members[0].getName()).isEqualTo("locator");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ public static void afterClass() {
@Before
public void before() {
pulseRule.useJmxManager("localhost", locator.getJmxPort());
cluster = pulseRule.getRepository().getCluster("clusterRead", "clusterRead");
cluster =
pulseRule.getRepository().getClusterWithUserNameAndPassword("clusterRead", "clusterRead");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public static void afterClass() {
@Before
public void before() {
pulseRule.useJmxManager("localhost", locator.getJmxPort());
cluster = pulseRule.getRepository().getCluster("admin", null);
cluster = pulseRule.getRepository().getClusterWithUserNameAndPassword("admin", null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void init(final Properties securityProps) {
public Object authenticate(final Properties credentials) throws AuthenticationFailedException {
String token = credentials.getProperty(TOKEN);
if (token != null) {
if (VALID_TOKEN.equals(token)) {
if (VALID_TOKEN.equalsIgnoreCase(token) || token.length() > 20) {
return "Bearer " + token;
} else {
throw new AuthenticationFailedException("Invalid token");
Expand Down
Loading

0 comments on commit 3f9d32d

Please sign in to comment.