Skip to content

Commit

Permalink
Add Security Sample Guide and Code.
Browse files Browse the repository at this point in the history
Resolves gh-81.
  • Loading branch information
yozaner1324 authored and jxblum committed Aug 7, 2020
1 parent c2f1ae3 commit 16abdea
Show file tree
Hide file tree
Showing 13 changed files with 605 additions and 0 deletions.
5 changes: 5 additions & 0 deletions spring-geode-docs/src/docs/asciidoc/_includes/samples.adoc
Expand Up @@ -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]
Expand Down
237 changes: 237 additions & 0 deletions 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.
2 changes: 2 additions & 0 deletions 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
10 changes: 10 additions & 0 deletions 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
@@ -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'
}
@@ -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<Long, Customer> 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[]

0 comments on commit 16abdea

Please sign in to comment.