From 16abdea031f9f4c80b9b9a096b7c5a3936fb34b4 Mon Sep 17 00:00:00 2001 From: Patrick Johnson Date: Tue, 21 Apr 2020 16:43:35 -0700 Subject: [PATCH] Add Security Sample Guide and Code. Resolves gh-81. --- .../src/docs/asciidoc/_includes/samples.adoc | 5 + .../docs/asciidoc/guides/boot-security.adoc | 237 ++++++++++++++++++ .../boot/security/lombok.config | 2 + .../boot/security/manifest.yaml | 10 + .../spring-geode-samples-boot-security.gradle | 22 ++ .../BootGeodeSecurityClientApplication.java | 69 +++++ .../client/controller/SecurityController.java | 44 ++++ .../app/security/client/model/Customer.java | 48 ++++ .../BootGeodeSecurityServerApplication.java | 73 ++++++ .../src/main/resources/application.properties | 5 + .../src/main/resources/shiro.properties | 3 + .../src/main/resources/trusted.keystore | Bin 0 -> 1976 bytes ...rityClientApplicationIntegrationTests.java | 87 +++++++ 13 files changed, 605 insertions(+) create mode 100644 spring-geode-docs/src/docs/asciidoc/guides/boot-security.adoc create mode 100644 spring-geode-samples/boot/security/lombok.config create mode 100644 spring-geode-samples/boot/security/manifest.yaml create mode 100644 spring-geode-samples/boot/security/spring-geode-samples-boot-security.gradle create mode 100644 spring-geode-samples/boot/security/src/main/java/example/app/security/client/BootGeodeSecurityClientApplication.java create mode 100644 spring-geode-samples/boot/security/src/main/java/example/app/security/client/controller/SecurityController.java create mode 100644 spring-geode-samples/boot/security/src/main/java/example/app/security/client/model/Customer.java create mode 100644 spring-geode-samples/boot/security/src/main/java/example/app/security/server/BootGeodeSecurityServerApplication.java create mode 100644 spring-geode-samples/boot/security/src/main/resources/application.properties create mode 100644 spring-geode-samples/boot/security/src/main/resources/shiro.properties create mode 100644 spring-geode-samples/boot/security/src/main/resources/trusted.keystore create mode 100644 spring-geode-samples/boot/security/src/test/java/example/app/security/BootGeodeSecurityClientApplicationIntegrationTests.java diff --git a/spring-geode-docs/src/docs/asciidoc/_includes/samples.adoc b/spring-geode-docs/src/docs/asciidoc/_includes/samples.adoc index 48d3b36c..d3930188 100644 --- a/spring-geode-docs/src/docs/asciidoc/_includes/samples.adoc +++ b/spring-geode-docs/src/docs/asciidoc/_includes/samples.adoc @@ -21,6 +21,11 @@ applications with Spring Boot. | Explains what auto-configuration is provided by SBDG out-of-the-box and what the auto-configuration is doing. | {github-samples-url}/boot/configuration[Boot Auto-Configuration] +| link:guides/boot-security.html[Security with Spring Boot for Apache Geode/Pivotal GemFire] +| Explains how to configure auth and SSL/TLS for Apache Geode and Pivotal Cloud Cache powered +applications with Spring Boot. +| {github-samples-url}/boot/security[Boot Security] + | link:guides/boot-actuator.html[Spring Boot Actuator for Apache Geode/Pivotal GemFire] | Explains how to use Spring Boot Actuator for Apache Geode and how it works. | {github-samples-url}/boot/actuator[Boot Actuator] diff --git a/spring-geode-docs/src/docs/asciidoc/guides/boot-security.adoc b/spring-geode-docs/src/docs/asciidoc/guides/boot-security.adoc new file mode 100644 index 00000000..5527031b --- /dev/null +++ b/spring-geode-docs/src/docs/asciidoc/guides/boot-security.adoc @@ -0,0 +1,237 @@ +[[geode-samples-boot-security]] += Spring Boot Security for Apache Geode & Pivotal GemFire +Patrick Johnson +:pcc-docs: https://docs.pivotal.io/p-cloud-cache/1-11 +:shiro-docs: https://shiro.apache.org/realm +:gemfire-name: VMware Tanzu GemFire +:geode-name: Apache Geode +:toc: left +:toclevels: 2 +:stylesdir: ../ +:highlightjsdir: ../js/highlight +:docinfodir: guides + +This guide walks you through building a simple Spring Boot application with security, specifically auth and SSL. You +should already be familiar with Spring Boot and Apache Geode/Tanzu GemFire. + +[#index-link] +link:../index.html[Index] + +link:../index.html#geode-samples[Back to Samples] + +[[geode-samples-boot-security-background]] +== Background + +Security is critical to most applications. +It is important to be able to control who can access your application and what they are allowed to do, this is where +auth (authentication and authorization) comes in. Authentication is used to verify a client’s identity (human or +application) in exchange for some sort of credentials. Once authenticated, a client must be authorized before they can +perform any actions. Authorization checks the permissions required to perform an action (read data, edit data, change +configuration, etc.) against the permissions assigned to the client’s identity. Of course, sending passwords and other +data as plain text isn’t very secure, so we also need to enable SSL/TLS to encrypt those things. Now, our apps are +secure. + +TIP: See the Spring Boot for {geode-name} (SBDG) chapter on link:../index.html#geode-security[Security] for more information. + +[[geode-samples-boot-security-client]] +== Securing a Client Application + +Enabling auth on the client is mostly taken care of by Spring Boot’s Auto-configuration. In the `application.properties` +file, simply set the properties `spring.data.gemfire.security.username` and `spring.data.gemfire.security.password` to +the username and password your app will use to authenticate. +Enabling SSL on the client requires you to put your `trusted.keystore` file (a Java KeyStore) in a well-known place, such +as your application’s working directory or your home directory, and auto-configuration will do the rest. If your +`trusted.keystore` has a password (which it should), you will need to specify it using the +`spring.data.gemfire.security.ssl.keystore.password` property in your `application.properties` file. You can generate a +Keystore using Java Keytool. + + +TIP: See the Spring Boot for {geode-name} (SBDG) chapter on link:../index.html#geode-security-auth-clients[Auth for Clients] +for more information. + +[[geode-samples-boot-security-server]] +== Securing a Server Application + +Auto-configuration doesn’t do as much for you when configuring auth on the server as it does on the client. In order to +enable auth, you need to do two things. First, annotate your configuration class with `@EnableSecurity`. Second, because +Apache Geode’s security is integrated with Apache Shiro, define at least one Shiro Realm as a bean in your Spring +`ApplicationContext`. + +Below is an example Shiro Realm bean: + +[source,java] +---- +include::{samples-dir}/boot/security/src/main/java/example/app/security/server/BootGeodeSecurityServerApplication.java[tags=realm] +---- + +You can find more information on Apache Shiro and how to set up a Realm link:{shiro-docs}[here]. + +Enabling SSL on the server is essentially the same as for the client, just put your `trusted.keystore` file (a Java +KeyStore) in a well-known place, like your application’s working directory or your home directory. If your +`trusted.keystore` has a password (which it should), you will need to specify it using the +`spring.data.gemfire.security.ssl.keystore.password` property in your `application.properties` file. You can generate a +Keystore using Java Keytool. + + +TIP: See the Spring Boot for {geode-name} (SBDG) chapter on link:../index.html#geode-security-auth-servers[Auth for Servers] +for more information. + +[[geode-samples-boot-security-examle]] +== Example + +To demonstrate the proper way to configure a Spring Boot application with security, we have put together a simple +example. The example is made up of two main parts: + +A client - BootGeodeSecurityClientApplication. + +A server - BootGeodeSecurityServerApplication. + +=== What it Does + +The example is very minimal and only performs some basic data operations. The server starts up, and the client then +connects to the server and tries to do two things: + +1. Write a new value into Customers, which succeeds. +2. Read a value from Customers, which fails because the user that the client authenticates with, is only authorized to +write data, not read it. + +This behavior may change, depending on the credentials used to authenticate. For example, using “cluster_operator” +credentials on the platform will result in both read and write operations succeeding. + + +=== Classes + +[[geode-samples-boot-security-example-classes-client]] +==== BootGeodeSecurityClientApplication + +This class is an Apache Geode client application that is configured to authenticate when connecting to a server and to +communicate using SSL. + +[[geode-samples-boot-security-example-classes-server]] +==== BootGeodeSecurityServerApplication + +This class is an Apache Geode server application that requires authentication for clients to connect to it and is +configured to communicate using SSL. + +[[geode-samples-boot-security-example-classes-customer]] +==== Customer + +This is a simple domain class to represent a customer. The `Customers` region will contain `Customer` objects that will +be accessed from the client. + +[[geode-samples-boot-security-example-classes-controller]] +==== SecurityController + +This class is a RestController that exposes an endpoint at “/message” that verifies the clients use of SSL. + +[[geode-samples-boot-security-example-run]] +=== Running the Example + +[[geode-samples-boot-security-example-run-local]] +==== Running Locally + +To run the example, first start the BootGeodeSecurityServerApplication and then run BootGeodeSecurityClientApplication. +In the terminal you should see the following output: + +[source] +---- +Successfully wrote data to region Customers +Attempting to read data from region Customers +Read failed because "jdoe not authorized for DATA:READ:Customers:2" +---- + +You can also hit the endpoint at https://localhost:8080/message[localhost:8080/message] to verify that the application +is using SSL. + +[[geode-samples-boot-security-example-run-platform]] +==== Running on VMware Tanzu GemFire + +In order for this sample to work, your Tanzu GemFire[VMs] tile must be set up to work with TLS. Instructions to enable +TLS for the TanzuGemfire[VMs] can be found link: {pcc-docs}/prepare-TLS.html[here]. + +Once TLS has been enabled, create your service instance with the `-c '{"tls":true}' flag`. + +For example: + +[source] +---- +cf create-service p-cloudcache [plan-name] [service-instance-name] -c '{"tls":true}' +---- + +where `[plan-name]` is replaced with the plan you are selecting and `[service-instance-name]` is replaced with the +desired name of your service. + +Update your `manifest.yml` file with the `[service-instance-name]` +[source] +---- +services: +- [your-service-instance-name] +---- + +Before deploying the application to the platform, you must update the username and password in the +`application.properties` file with the correct credentials for your service instance. + +Once your Service Instance is created you’ll need to create a service-key for the service. +[source] +---- +cf create-service-key [service-instance-name] [service-key-name] +---- + +where `[service-instance-name]` is replaced with the name of your service instance (from above) and `[service-key-name]` +is what you would like to call this service key. + +Once the service key is created, access the credentials in the service with the following command +[source] +---- +cf service-key [service-instance-name] [service-key-name] +---- + +where `[service-instance-name]` is replaced with the name of your service instance and `[service-key-name]` is replaced +with the name of your service key (from the previous step). + +In the output look for the “users” section. For this example, we used the “cluster_operator” user credentials. +[source] +---- +{ +... + "users": [ + { + "password": "xxxxxxxxxxxxxxxxxxxxxxxx", + "roles": [ + "cluster_operator" + ], + "username": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "password": "xxxxxxxxxxxxxxxxxxxxxx", + "roles": [ + "developer" + ], + "username": "xxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "password": "xxxxxxxxxxxxxxxxxxxxx", + "roles": [ + "readonly" + ], + "username": "xxxxxxxxxxxxxxxx" + } + ], + "wan": {} +} +---- + +Now build the sample with Gradle and push the application to the platform using `cf push`. + +Once the app is running, check the logs with `cf logs security-app --recent` and you should see output like the +following: +[source] +---- +Successfully wrote data to region Customers +Attempting to read data from region Customers +---- + +You can also hit the endpoint at +https://security-app.apps.{cf-instance}.cf-app.com/message[https://security-app.apps.{cf-instance}.cf-app.com/message], +where `{cf-instance}` is replaced with the name of your Cloud Foundry instance, to verify that the application is using +SSL. diff --git a/spring-geode-samples/boot/security/lombok.config b/spring-geode-samples/boot/security/lombok.config new file mode 100644 index 00000000..6aa51d71 --- /dev/null +++ b/spring-geode-samples/boot/security/lombok.config @@ -0,0 +1,2 @@ +# This file is generated by the 'io.freefair.lombok' Gradle plugin +config.stopBubbling = true diff --git a/spring-geode-samples/boot/security/manifest.yaml b/spring-geode-samples/boot/security/manifest.yaml new file mode 100644 index 00000000..f592411d --- /dev/null +++ b/spring-geode-samples/boot/security/manifest.yaml @@ -0,0 +1,10 @@ +--- +applications: + - name: security-app + memory: 768M + instances: 1 + path: ./build/libs/spring-geode-samples-boot-security-1.3.0.BUILD-SNAPSHOT.jar + services: + - pccServiceOne + buildpacks: + - https://github.com/cloudfoundry/java-buildpack.git \ No newline at end of file diff --git a/spring-geode-samples/boot/security/spring-geode-samples-boot-security.gradle b/spring-geode-samples/boot/security/spring-geode-samples-boot-security.gradle new file mode 100644 index 00000000..fe528f75 --- /dev/null +++ b/spring-geode-samples/boot/security/spring-geode-samples-boot-security.gradle @@ -0,0 +1,22 @@ +plugins { + id "io.freefair.lombok" version "5.0.0-rc2" +} + +apply plugin: 'io.spring.convention.spring-sample-boot' + +description = "Spring Geode Sample demonstrating Apache Geode security." + +dependencies { + + compile project(":spring-geode-starter") + compile project(":spring-geode-starter-test") + + compile "org.springframework.boot:spring-boot-starter-web" + + compile "org.assertj:assertj-core" + compile "org.projectlombok:lombok" +} + +bootJar { + mainClassName = 'example.app.security.client.BootGeodeSecurityClientApplication' +} diff --git a/spring-geode-samples/boot/security/src/main/java/example/app/security/client/BootGeodeSecurityClientApplication.java b/spring-geode-samples/boot/security/src/main/java/example/app/security/client/BootGeodeSecurityClientApplication.java new file mode 100644 index 00000000..c4639d78 --- /dev/null +++ b/spring-geode-samples/boot/security/src/main/java/example/app/security/client/BootGeodeSecurityClientApplication.java @@ -0,0 +1,69 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed 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 + * + * https://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 example.app.security.client; + +import example.app.security.client.model.Customer; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.client.ClientCache; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.data.gemfire.config.annotation.EnableClusterConfiguration; +import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions; + +/** + * The {@link BootGeodeSecurityClientApplication} class is a Spring Boot, Apache Geode {@link ClientCache} + * application that configures security. + * + * @author Patrick Johnson + * @see org.apache.geode.cache.client.ClientCache + * @see org.springframework.boot.SpringApplication + * @see org.springframework.boot.autoconfigure.SpringBootApplication + * @see org.springframework.context.annotation.Bean + * @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication + * @since 1.3.0 + */ +// tag::class[] +@SpringBootApplication +@EnableClusterConfiguration +@EnableEntityDefinedRegions +public class BootGeodeSecurityClientApplication { + public static void main(String[] args) { + new SpringApplicationBuilder(BootGeodeSecurityClientApplication.class) + .web(WebApplicationType.SERVLET) + .build() + .run(args); + } + + @Bean + ApplicationRunner runner(@Qualifier("Customers") Region customers) { + return args -> { + customers.put(2L, Customer.newCustomer(2L, "William Evans")); + System.out.println(String.format("Successfully wrote data to region %s", customers.getName())); + + try { + System.out.println(String.format("Attempting to read data from region %s", customers.getName())); + customers.get(2L); + } catch (Exception e) { + System.out.println(String.format("Read failed because \"%s\"", e.getCause().getMessage())); + } + }; + } +} +// end::class[] diff --git a/spring-geode-samples/boot/security/src/main/java/example/app/security/client/controller/SecurityController.java b/spring-geode-samples/boot/security/src/main/java/example/app/security/client/controller/SecurityController.java new file mode 100644 index 00000000..2017cef3 --- /dev/null +++ b/spring-geode-samples/boot/security/src/main/java/example/app/security/client/controller/SecurityController.java @@ -0,0 +1,44 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed 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 + * + * https://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 example.app.security.client.controller; + +import example.app.security.client.BootGeodeSecurityClientApplication; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * The {@link SecurityController} class is a RestController used by {@link BootGeodeSecurityClientApplication} + * + * @author Patrick Johnson + * @see org.springframework.web.bind.annotation.RestController + * @since 1.3.0 + */ +// tag::class[] +@RestController +public class SecurityController { + + @Autowired + Environment env; + + @GetMapping("/message") + public String getMessage() { + return "I'm using SSL with this keystore: " + env.getProperty("spring.data.gemfire.security.ssl.keystore"); + } +} +// end::class[] diff --git a/spring-geode-samples/boot/security/src/main/java/example/app/security/client/model/Customer.java b/spring-geode-samples/boot/security/src/main/java/example/app/security/client/model/Customer.java new file mode 100644 index 00000000..afef5ced --- /dev/null +++ b/spring-geode-samples/boot/security/src/main/java/example/app/security/client/model/Customer.java @@ -0,0 +1,48 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed 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 + * + * https://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 example.app.security.client.model; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.ToString; +import org.springframework.data.annotation.Id; +import org.springframework.data.gemfire.mapping.annotation.Region; + +/** + * An Abstract Data Type (ADT) modeling a {@literal Customer}. + * + * @author John Blum + * @see Id + * @see Region + * @since 1.0.0 + */ +// tag::class[] +@Region("Customers") +@EqualsAndHashCode +@ToString(of = "name") +@RequiredArgsConstructor(staticName = "newCustomer") +public class Customer { + + @Id @NonNull @Getter + private Long id; + + @NonNull @Getter + private String name; + +} +// end::class[] diff --git a/spring-geode-samples/boot/security/src/main/java/example/app/security/server/BootGeodeSecurityServerApplication.java b/spring-geode-samples/boot/security/src/main/java/example/app/security/server/BootGeodeSecurityServerApplication.java new file mode 100644 index 00000000..af2d6ada --- /dev/null +++ b/spring-geode-samples/boot/security/src/main/java/example/app/security/server/BootGeodeSecurityServerApplication.java @@ -0,0 +1,73 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed 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 + * + * https://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 example.app.security.server; + +import org.apache.geode.cache.server.CacheServer; +import org.apache.geode.internal.security.shiro.GeodePermissionResolver; +import org.apache.shiro.realm.text.PropertiesRealm; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.data.gemfire.config.annotation.CacheServerApplication; +import org.springframework.data.gemfire.config.annotation.EnableSecurity; + +/** + * The {@link BootGeodeSecurityServerApplication} class is a Spring Boot, Apache Geode {@literal peer} + * {@link CacheServer} application serving cache clients. + * + * This Apache Geode peer member server configures security. + * + * @author Patrick Johnson + * @see org.apache.geode.cache.Cache + * @see org.apache.geode.cache.Region + * @see org.apache.geode.cache.server.CacheServer + * @see org.springframework.boot.autoconfigure.SpringBootApplication + * @see org.springframework.context.annotation.Bean + * @see org.springframework.data.gemfire.config.annotation.CacheServerApplication + * @since 1.3.0 + */ +// tag::class[] +@SpringBootApplication +public class BootGeodeSecurityServerApplication { + + public static void main(String[] args) { + new SpringApplicationBuilder(BootGeodeSecurityServerApplication.class) + .web(WebApplicationType.NONE) + .build() + .run(args); + } + + @CacheServerApplication + @EnableSecurity + static class GeodeServerConfig { + + // tag::realm[] + @Bean + PropertiesRealm shiroRealm() { + + PropertiesRealm propertiesRealm = new PropertiesRealm(); + + propertiesRealm.setResourcePath("classpath:shiro.properties"); + propertiesRealm.setPermissionResolver(new GeodePermissionResolver()); + + return propertiesRealm; + } + // end::realm[] + } +} +// end::class[] + diff --git a/spring-geode-samples/boot/security/src/main/resources/application.properties b/spring-geode-samples/boot/security/src/main/resources/application.properties new file mode 100644 index 00000000..37911852 --- /dev/null +++ b/spring-geode-samples/boot/security/src/main/resources/application.properties @@ -0,0 +1,5 @@ +# Spring Boot client application.properties + +spring.data.gemfire.security.ssl.keystore.password=s3cr3t +spring.data.gemfire.security.username = jdoe +spring.data.gemfire.security.password = p@55w0rd \ No newline at end of file diff --git a/spring-geode-samples/boot/security/src/main/resources/shiro.properties b/spring-geode-samples/boot/security/src/main/resources/shiro.properties new file mode 100644 index 00000000..356746a2 --- /dev/null +++ b/spring-geode-samples/boot/security/src/main/resources/shiro.properties @@ -0,0 +1,3 @@ +# assign user jdoe the role fo viewer and give him DATA:WRITE permissions +user.jdoe = p@55w0rd, viewer +role.viewer = DATA:WRITE \ No newline at end of file diff --git a/spring-geode-samples/boot/security/src/main/resources/trusted.keystore b/spring-geode-samples/boot/security/src/main/resources/trusted.keystore new file mode 100644 index 0000000000000000000000000000000000000000..18c35a2ac5ba4dcb1da475f6c9e52df32b9a636b GIT binary patch literal 1976 zcmchX*H@E?7R8e<6(S`fbwV#8g777Pp+_kbB&a~*h$0Y`071$~7bymmDj|*|Wk3lU z5RoE^h9U|K!Uzr`O%W+kAc9830vTlRqU-u{|A70jAAaYYhqLxNXRk}vB@hS%*bwx) z6l0=dqhnZsX2)13qGKYXSR0MwW!qq=jUhgm29$#GNLdpk6b{`AV4+Y11fB+Dtq07T zUhHHG6!$%w9y?vDerSG}SzW9i)MHktdZ0F+J>sgt9j|q;+LpqHtj%)jx2B$aXy4v4 z5&G#zj@W7$CLO(FA#{|G^YsQA&}B!i2wo)rUM1Lc z)N{1`MUP-`jklv}G1?Ec>GMHwRG4*SiiAk3h>hT{pJ+C$&LubO&VEvSTUjIJDKt|3 z0+qX#+$8+#?7nNh*Gu#r>eJkdSEMMk#j2N}pt%Y&XqCQlK|VXt3m?aiD@~GRmZl7M zsN!)UNZT)2C*!F051a2ISk#~1g^xUv@_Z|66LZVL92Skz&+Ra|h2_*5ot$%vcrIsa zEAf}qOkj_H*|#{)LtWq;R?n%oejC$N#|zkdMwzbG%Q1OH2d58d%NqLC9eCwoRQ3is z)}S>ta-Fh-63N{#<_=5+M|G4a&=a~}D>sBi>qBrLrAkGa6#^if9^DEMn3A=W@PEgP||sC0`uPrL*o8{@%Mz> zkDQv+PSE2kD|?Tsc-UpooOyR!`6J7(oO{A)L4)ny<_A~eSI<4p=)Hk5NauSwrBub6 zHy1Izd%>bq{(H}gf|-4Mp-{02Bb=iC^>zK{=!h zGs6wag27<`0s;mSF`x_*whxX}0%D_yn?c2IfL4+@8W|B38_kZ4Aj*TAzSU4l2-e}K zn2;YVtAvO-9FZ9NgE2oC3o3k@hbf^$BSRu|0wY3p)^O+s7z1fgC?x-c)mU@&{Qc{ati;E=yzYE7dvM9Fo~-tI zp{qdK@!#!8v9s5;E;S3ACK+*O9gbddmFjzD09)JCcp@`)*J<{l8u|P!x3;5=FPpF8 zv9bhL}xV!SCXgv%bh1_L0{oK$C1Y>`XZm<%x?62sxI!C zX0Lul7XJf;}jRpgnke20w$}xSqvPiJ>z-KPO5uLEoaJ*{%Y+Wb@JvPfHUqQiy#;exv;m%bTTMRsUBh%4 zF>TPE=iC=)o(0*-l>E~xb4w@gYALA_|AFdwF0u;{LF0#b89HE+GXr;-UVSaYYSQwMpi(M~Kn5V~;s)UvWCE zQF6mPi8n7O7^?82`@UIo9bQ&nrZ`AiGi?kzKNw8M6A9r}nQyhIZqk%50h2<;Y2q%Nv)uk~JtkT|_gXzu^zLYqth!$1HCt+zD zQUA>d_t0gVvw0H&P*>~xVnbO}SZp^QX8U|80EUZEpR4=1Sc-XEck7q>pGIJy;&VZ3|MF$5P6c)XS~c$`enZxd+m zV7pvTqM>^VJLUX4O}-SsK4sD4s?et*`N_3aQMhtA*+Tg$&`VB}c343{c zq&Y4{a)9hkZJB$VrHRcR%IlEzfOGw8%qHdeD6VeIFM})6defobX|L~%ZH~aJFJ93F zwL#5|2iKH`tH8H#XAGYa(9Y7F^7$9+i+cBao=6}5PsYF~5YQgLSw6X+;{9R4{j0`R z;2m|c-=8v!n_F%?=qfrA4B+T@w30Ab>Cq%cDC$y6DL0&%&AtyKbXJJkTf3Ya2y9~~ RvXP+Im2#NK)A6hL`#=9?OqT!v literal 0 HcmV?d00001 diff --git a/spring-geode-samples/boot/security/src/test/java/example/app/security/BootGeodeSecurityClientApplicationIntegrationTests.java b/spring-geode-samples/boot/security/src/test/java/example/app/security/BootGeodeSecurityClientApplicationIntegrationTests.java new file mode 100644 index 00000000..25df8d7d --- /dev/null +++ b/spring-geode-samples/boot/security/src/test/java/example/app/security/BootGeodeSecurityClientApplicationIntegrationTests.java @@ -0,0 +1,87 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed 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 + * + * https://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 example.app.security; + +import example.app.security.client.BootGeodeSecurityClientApplication; +import example.app.security.client.model.Customer; +import example.app.security.server.BootGeodeSecurityServerApplication; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.client.ServerOperationException; +import org.apache.geode.security.NotAuthorizedException; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.gemfire.tests.integration.ClientServerIntegrationTestsSupport; +import org.springframework.data.gemfire.tests.process.ProcessWrapper; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; +import java.io.IOException; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * Integration Tests for {@link BootGeodeSecurityClientApplication} and {@link BootGeodeSecurityServerApplication}. + * + * @author Patrick Johsnon + * @see org.springframework.boot.test.context.SpringBootTest + * @see org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport + * @see org.springframework.test.context.junit4.SpringRunner + * @see example.app.security.client.BootGeodeSecurityClientApplication + * @since 1.3.0 + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BootGeodeSecurityClientApplication.class) +public class BootGeodeSecurityClientApplicationIntegrationTests extends ClientServerIntegrationTestsSupport { + + private static ProcessWrapper geodeServer; + + @Resource(name = "Customers") + private Region customers; + + @BeforeClass + public static void setup() throws IOException { + int availablePort = findAvailablePort(); + + geodeServer = run(BootGeodeSecurityServerApplication.class, + String.format("-D%s=%d", GEMFIRE_CACHE_SERVER_PORT_PROPERTY, availablePort)); + + waitForServerToStart("localhost", availablePort); + + System.setProperty(GEMFIRE_POOL_SERVERS_PROPERTY, String.format("%s[%d]", "localhost", availablePort)); + } + + @Test + public void dataReadNotAllowed() { + Exception exception = assertThrows(ServerOperationException.class, () -> customers.get(2L).getName()); + assertThat(exception.getCause()).isInstanceOf(NotAuthorizedException.class); + assertThat(exception.getCause().getMessage()).contains("jdoe not authorized for DATA:READ"); + } + + @Test + public void dataWriteAllowed() { + customers.put(3L, Customer.newCustomer(3L, "Samantha Rogers")); + } + + @AfterClass + public static void cleanup() { + stop(geodeServer); + System.clearProperty(GEMFIRE_CACHE_SERVER_PORT_PROPERTY); + } +}