Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[work in progress] Rework samples #1632

Merged
merged 11 commits into from
Oct 30, 2024
Merged
130 changes: 48 additions & 82 deletions docs/HowToFetchToken.md
finkmanAtSap marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -3,113 +3,79 @@ Get your service configuration:
- In CF from [VCAP_SERVICES](https://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html#VCAP-SERVICES) environment variable
- In K8s/Kyma from configuration [secrets](https://kubernetes.io/docs/concepts/configuration/secret/)

The documentation assumes the utility `curl` and `awk` to be installed (Mac OS: brew install curl, Ubuntu: sudo apt-get install curl). Alternatively, use [Postman Rest Client](https://www.postman.com/downloads/).
The documentation assumes the utilities `curl` and `awk` to be installed (Mac OS: brew install curl, Ubuntu: sudo apt-get install curl).

## IAS Tokens
<details>
<summary>Using <b>X.509</b> Client Certificate</summary>
<summary>Using X.509 Client Certificate</summary>

1. Store the `certificate` and `key` from your service configuration in separate files in [PEM](https://www.ssl.com/guide/pem-der-crt-and-cer-x-509-encodings-and-conversions/#ftoc-heading-1) format.
> In case you experience invalid PEM file errors, \\n characters might have to be replaced by newlines \n to have the PEM in the correct format.
> ```shell script
> :warning: In case you experience invalid PEM file errors, \\n characters might have to be replaced by newlines \n to have the PEM in the correct format.
> ```shell
> awk '{gsub(/\\n/,"\n")}1' <file>.pem
> ```

2. Fetch the token using:

<details>
<summary>curl command</summary>
❗Replace the `<<>>` placeholders with the values from the service configuration.
```shell script
curl --cert certificate.pem --key key.pem -XPOST <<credentials.url>>/oauth2/token \
-d 'grant_type=password&client_id=<<credentials.clientid>>&username=<<your ias user>>&password=<<your ias password>>'
```shell
curl --cert certificate.pem --key key.pem \
-X POST <<credentials.url>>/oauth2/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<<credentials.clientid>>' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'username=<<name of requesting user>>' \
--data-urlencode 'password=<<password of requesting user>>'
```
</details>
<details>
<summary>Postman</summary>

1. In Postman navigate to Settings -> Certificates, click on "Add Certificate" and provide the certificate and key `PEM` files and host name.
<br>![](./postman-mtls.png)
2. Import [Postman Collection](./IAS_XSUAA_token_fetch.postman_collection.json). For more info on how to import it in the Postman see [learning.postman.com](https://learning.postman.com/docs/getting-started/importing-and-exporting-data/#importing-postman-data)
3. Fill in the corresponding ias_* Postman variables
<br>![](./postman-variables.png)
4. Open the 'IAS Token | pswd grant' Postman Collection and send the request
</details>
:grey_exclamation: Replace the `<<>>` placeholders with values from the service configuration and user credentials.
</details>
<details>
<summary>Using <b>Client Credentials</b></summary>
<summary>Using Client Credentials</summary>

1. Fetch the token using:
<details>
<summary>curl command</summary>
❗Replace the `<<>>` placeholders with the values from the service configuration.
```shell script
curl -XPOST -u '<<credentials.clientid>>:<<credentials.clientsecret>>' https://<<credentials.url>>/oauth2/token \
-d 'grant_type=password&username=<<your ias user>>&password=<<your ias password>>'
```shell
curl -u '<<credentials.clientid>>:<<credentials.clientsecret>>' \
-X POST <<credentials.url>>/oauth2/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'username=<<name of requesting user>>' \
--data-urlencode 'password=<<password of requesting user>>'
```
</details>
<details>
<summary>Postman</summary>

1. Import [Postman Collection](./IAS_XSUAA_token_fetch.postman_collection.json). For more info how to import it in Postman see [learning.postman.com](https://learning.postman.com/docs/getting-started/importing-and-exporting-data/#importing-postman-data)
2. Fill in the corresponding ias_* Postman variables
<br>![](./postman-variables.png)
3. Open the 'Ias Token | pswd grant' Postman Collection and send the request
</details>
:grey_exclamation: Replace the `<<>>` placeholders with values from the service configuration and user credentials.
</details>

## XSUAA Tokens
<details>
<summary>Using <b>X.509</b> Client Certificate</summary>
<summary>Using X.509 Client Certificate</summary>

1. Store the `certificate` and `key` from your service configuration in separate files in [PEM](https://www.ssl.com/guide/pem-der-crt-and-cer-x-509-encodings-and-conversions/#ftoc-heading-1) format.
> In case you experience invalid PEM file errors, \\n characters might have to be replaced by newlines \n to have the PEM in the correct format.
> ```shell script
1. Store the `certificate` and `key` from your service configuration in separate files in [PEM](https://www.ssl.com/guide/pem-der-crt-and-cer-x-509-encodings-and-conversions/#ftoc-heading-1) format.
> :warning: In case you experience invalid PEM file errors, \\n characters might have to be replaced by newlines \n to have the PEM in the correct format.
> ```shell
> awk '{gsub(/\\n/,"\n")}1' <file>.pem
> ```
2. Fetch the token using:
<details>
<summary>curl command</summary>

❗Replace the `<<>>` placeholders with the values from the service configuration.
```shell script
curl --cert certificate.pem --key key.pem -XPOST <<credentials.certurl>>/oauth/token \
-d 'grant_type=password&client_id=<<credentials.clientid>>&username=<<your xsuaa username>>&password=<<your xsuaa password>>'
```
</details>
<details>
<summary>Postman</summary>

1. In Postman navigate to Settings -> Certificates, click on "Add Certificate" and provide the certificate and key `PEM` files and host name.
<br>![](./postman-mtls.png)
2. Import [Postman Collection](./IAS_XSUAA_token_fetch.postman_collection.json). For more info on how to import it in the Postman see [learning.postman.com](https://learning.postman.com/docs/getting-started/importing-and-exporting-data/#importing-postman-data)
3. Fill in the corresponding xsuaa_* Postman variables
<br>![](./postman-variables.png)
4. Open the 'Xsuaa Token | pswd grant mTLS' Postman Collection and send the request
</details>
```shell
curl --cert certificate.pem --key key.pem \
-X POST <<credentials.certurl>>/oauth/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<<credentials.clientid>>' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'username=<<name of requesting user>>' \
--data-urlencode 'password=<<password of requesting user>>'
```
:grey_exclamation: Replace the `<<>>` placeholders with values from the service configuration and user credentials.
</details>
<details>
<summary>Using <b>Client Credentials</b></summary>
<summary>Using Client Credentials</summary>

1. Fetch the token using:
<details>
<summary>curl command</summary>

❗Replace the `<<>>` placeholders with the values from the service configuration.
```
curl -X POST <<credentials.url>>/oauth/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'client_id=<<credentials.clientid>>&client_secret=<<credentials.clientsecret>>&grant_type=password&username=<<your xsuaa username>>&password=<<your xsuaa password>>'
1. Fetch the token using:
```shell
curl \
-X POST <<credentials.url>>/oauth/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<<credentials.clientid>>' \
--data-urlencode 'client_secret=<<credentials.clientsecret>>' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'username=<<name of requesting user>>' \
--data-urlencode 'password=<<password of requesting user>>'
```
</details>
<details>
<summary>Postman</summary>

1. Import [Postman Collection](./IAS_XSUAA_token_fetch.postman_collection.json). For more info how to import it in Postman see [learning.postman.com](https://learning.postman.com/docs/getting-started/importing-and-exporting-data/#importing-postman-data)
2. Fill in the corresponding xsuaa_* Postman variables
<br>![](./postman-variables.png)
3. Open the 'Xsuaa Token | pswd grant' Postman Collection and send the request
</details>
:grey_exclamation: Replace the `<<>>` placeholders with values from the service configuration and user credentials.
</details>
2 changes: 1 addition & 1 deletion samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
- [sap-java-buildpack-api-usage](./sap-java-buildpack-api-usage): Sample showcasing how to use SAP Java Buildpack to secure a Java J2EE web application.

## Java 17 using Tomcat 10 servlet
- [java-security-usage](./java-security-usage): Sample demonstrating how to use the `java-security` library for authentication and authorization checks in a Java application when bound to an Xsuaa service.
- [java-security-usage](./java-security-usage): Sample demonstrating how to use the `java-security` library for authentication and authorization checks in a Java application when bound to an XSUAA service.
Additionally, it explains how to implement JUnit Tests using the `java-security-test` library.
</br>:heavy_check_mark: compatible with Kubernetes/Kyma environment<br/>

Expand Down
10 changes: 5 additions & 5 deletions samples/deploy_and_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def test_hello_java_security_authz(self):
resp = self.perform_get_request_with_token('/hello-java-security-authz')
self.assertEqual(403, resp.status, EXPECT_403)

self.add_user_to_role('JAVA_SECURITY_SAMPLE_Viewer')
self.add_user_to_role('Sample Viewer (java-security-usage)')
resp = self.perform_get_request_with_token('/hello-java-security-authz')
self.assertEqual(200, resp.status, EXPECT_200)

Expand All @@ -301,7 +301,7 @@ def test_sayHello_xsuaa(self):
resp = self.perform_get_request_with_token('/sayHello')
self.assertEqual(403, resp.status, EXPECT_403)

self.add_user_to_role('XSUAA-Viewer')
self.add_user_to_role('Sample Viewer (spring-security-hybrid-usage)')
resp = self.perform_get_request_with_token('/sayHello')
self.assertEqual(200, resp.status, EXPECT_200)
clientid = self.get_deployed_app().get_credentials_property('clientid')
Expand Down Expand Up @@ -437,7 +437,7 @@ def test_hello_token_servlet(self):
resp = self.perform_get_request_with_token('/hello-token')
self.assertEqual(403, resp.status, EXPECT_403)

self.add_user_to_role('Buildpack_API_Viewer')
self.add_user_to_role('Sample Viewer (sap-java-buildpack-api-usage)')
resp = self.perform_get_request_with_token('/hello-token')
self.assertEqual(200, resp.status, EXPECT_200)
self.assertRegex(resp.body, self.credentials.username, 'Expected to find username in response')
Expand All @@ -463,7 +463,7 @@ def test_fetch_token_status_ok(self):
# app restart needed because tokens are cached in application
self.cf_app.restart()
logging.info(RUN_TEST.format("SpringSecurityBasicAuthTest.test_fetch_token_status_ok"))
self.add_user_to_role('BASIC_AUTH_API_Viewer')
self.add_user_to_role('Sample Viewer (spring-security-basic-auth)')
resp = self.perform_get_request('/fetchToken', username=self.credentials.username,
password=self.credentials.password)
self.assertEqual(200, resp.status, EXPECT_200)
Expand All @@ -487,7 +487,7 @@ def test_say_hello(self):
resp = self.perform_get_request_with_token('/v1/sayHello')
self.assertEqual(403, resp.status, EXPECT_403)

self.add_user_to_role('Webflux_API_Viewer')
self.add_user_to_role('Sample Viewer (spring-webflux-security-hybrid-usage)')
resp = self.perform_get_request_with_token('/v1/sayHello')
self.assertEqual(200, resp.status, EXPECT_200)
self.assertRegex(resp.body, self.credentials.username, 'Expected to find username in response')
Expand Down
5 changes: 5 additions & 0 deletions samples/java-security-usage-ias/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM --platform=linux/amd64 tomcat:10-jre17

ADD target/java-security-usage-ias.war /usr/local/tomcat/webapps/

EXPOSE 8080
149 changes: 110 additions & 39 deletions samples/java-security-usage-ias/README.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,135 @@
# Description
This sample is a Java Back-End application that utilizes the [Java Security](../../java-security/) client library to validate JWT tokens issued by the `Identity` service.
It inspects incoming requests to determine if the user has the appropriate access to resource
by using the [`IasTokenAuthenticator`](/java-security/src/main/java/com/sap/cloud/security/servlet/IasTokenAuthenticator.java).
# SAP BTP Java Security Client Library with XSUAA sample application
This Java backend application uses the [java-security](/java-security/) module to validate JWT tokens issued by the `Identity` service.
It inspects incoming requests and handles authentication and authorization by using the [`IasTokenAuthenticator`](/java-security/src/main/java/com/sap/cloud/security/servlet/IasTokenAuthenticator.java).

**Disclaimer: as of now the Identity tokens can only be validated in case the token from the consuming application is issued for the same Identity tenant.**

# Deployment on Cloud Foundry
To deploy the application, the following steps are required:
- Compile the Java application
- Create a ias service instance
- Configure the manifest
- Deploy the application
- Access the application

## Compile the Java application
Run maven to package the application
## Build and Deploy
### 1. Run maven to compile and package the sample application:
```shell
mvn clean package
```

## Create the ias service instance
Use the ias service broker and create a service instance (don't forget to replace the placeholders)
### 2. The following steps deploy the application using either Cloud Foundry or Kyma/Kubernetes.
<details>
<summary>Deployment on Cloud Foundry</summary>

#### Create the IAS service instance
Use the cf CLI to create an IAS service instance.
```shell
cf create-service identity application ias-java-security
```

## Configure the manifest
The [vars](../vars.yml) contains hosts and paths that need to be adopted.
#### Configure the manifest
The [vars](../vars.yml) contain hosts and paths that need to be adapted.

## Deploy the application
Deploy the application using cf push. It will expect 1 GB of free memory quota.
#### Deploy the application
Deploy the application using the cf CLI.

```shell
cf push --vars-file ../vars.yml
```
:warning: This will expect 1 GB of free memory quota.
</details>

<details>
<summary>Deployment on Kubernetes</summary>

#### Build and tag docker image and push to repository
Execute the following docker commands to build and push the docker image to a repository.
Replace `<repository>/<image>` with your repository and image name.
```shell
docker build -t <repository>/<image> .
docker push <repository>/<image>
```

#### Configure the deployment.yml
In deployment.yml replace the placeholder `<YOUR IMAGE TAG>` with the image tag created in the previous step.

:warning: If you are [using a private repository](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/),
you also need to provide the image pull secret in the deployment.yml.

#### Deploy the application
Deploy the application using [kubectl](https://kubernetes.io/docs/reference/kubectl/).
```shell
kubectl apply -f k8s/deployment.yml
```
</details>

### 3. Access the application
The sample application provides three HTTP endpoints:
- `/health` - accessible without authentication
- `/hello-java-security-ias` - authenticated access only

Before sending requests to the latter endpoint we need to obtain a valid access token for a user.
To this we need to retrieve the `ias-java-security` service instance credentials from Cloud Foundry or Kubernetes.

<details>
<summary>Retrieve IAS credentials from Cloud Foundry</summary>

Either use the cockpit to navigate to your application (via subaccount and space) and click on 'Environment Variables' or use the cf CLI command
```shell
cf env java-security-usage-ias
```
to retrieve the application environment.
The environment variable `VCAP_SERVICES` contains a `credentials` section for the `xsuaa-java-security` service instance.
</details>

<details>
<summary>Retrieve IAS credentials from Kubernetes</summary>

Use the following Kubernetes CLI command to retrieve the `ias-java-security` service instance credentials by reading the `ias-service-binding` secret.
```shell
kubectl get secret "ias-service-binding" -o go-template='{{range $k,$v := .data}}{{"### "}}{{$k}}{{"\n"}}{{$v|base64decode}}{{"\n\n"}}{{end}}'
```
</details>

## Access the application
1. Follow [HowToFetchToken](../../docs/HowToFetchToken.md#ias-tokens) guide to fetch IAS id token.

You can get the information to fill the placeholders from your system environment `cf env java-security-usage-ias`
Use the IAS credentials to retrieve an access token for the sample application by following the [HowToFetchToken](../../docs/HowToFetchToken.md#ias-tokens) guide.

Copy the `id_token` to your clipboard.
Now you can use the access token to access the application via curl.

2. Access the app via `curl`. Don't forget to fill the placeholders.
```
curl -X GET \
https://java-security-usage-ias-<<ID>>.<<LANDSCAPE_APPS_DOMAIN>>/hello-java-security-ias \
-H 'Authorization: Bearer <<your id_token>>'
```
<details>
<summary>curl command to access Cloud Foundry deployment</summary>

3. You should see something like this:
```
You ('<your email>') are authenticated and can access the application.
```
:bulb: If you call the same endpoint without `Authorization` header you should get a `401`.
```
curl -X GET \
https://java-security-usage-ias-<<ID>>.<<LANDSCAPE_APPS_DOMAIN>>/hello-java-security-ias \
-H 'Authorization: Bearer <<id token>>'
```
</details>

<details>
<summary>curl command to access Kubernetes deployment</summary>

```shell
curl -X GET \
https://java-security-ias-api.<<K8S DOMAIN>>/java-security-usage-ias/hello-java-security-ias \
-H 'Authorization: Bearer <<access token>>'
```
</details>

## Clean-Up
Finally, delete your application and your service instances using the following commands:
You should see something like this:
```
cf us java-security-usage-ias ias-java-security
You ('<your user>') can access the application with the following scopes: '<your scopes>'.
```

### 4. Cleanup
If you no longer need the sample application, you can free up resources using the cf CLI or the Kubernetes CLI.

<details>
<summary>Cleanup commands for Cloud Foundry</summary>

```shell
cf unbind-service java-security-usage-ias ias-java-security
cf delete -f java-security-usage-ias
cf delete-service -f ias-java-security
```
</details>

<details>
<summary>Cleanup command for Kubernetes</summary>

```shell
kubectl delete -f k8s/deployment.yml
```
</details>
Loading
Loading