The goals of this project are:
- Create a
Spring Bootapplication that manages books, calledbook-service; - Use
Keycloakas OpenID Connect provider; - Test using
Testcontainers; - Explore the utilities and annotations that
Spring Bootprovides for testing applications.
On ivangfr.github.io, I have compiled my Proof-of-Concepts (PoCs) and articles. You can easily search for the technology you are interested in by using the filter. Who knows, perhaps I have already implemented a PoC or written an article about what you are looking for.
- [Medium] Implementing and Securing a Simple Spring Boot REST API with Keycloak
- [Medium] Implementing and Securing a Simple Spring Boot UI (Thymeleaf + RBAC) with Keycloak
- [Medium] Implementing and Securing a Spring Boot GraphQL API with Keycloak
- [Medium] Building a Single Spring Boot App with Keycloak or Okta as IdP: Introduction
-
Spring BootWeb application that manages books.MongoDBis used as storage, and the application's sensitive endpoints (like create, update and delete books) are secured.
Open a terminal and, inside the springboot-keycloak-mongodb-testcontainers root folder, run the script below
./init-environment.shThere are two ways: running a script or using the Keycloak website
-
In a terminal, make sure you are inside the
springboot-keycloak-mongodb-testcontainersroot folder -
Run the following script to configure
Keycloakforbook-serviceapplication./init-keycloak.sh
This script will create:
company-servicesrealm;book-serviceclient;manage_booksclient role;- user with username
ivan.franchinand password123and with the rolemanage_booksassigned.
-
The
book-serviceclient secret (BOOK_SERVICE_CLIENT_SECRET) is shown at the end of the execution. It will be used in the next step. -
You can check the configuration in
Keycloakby accessing http://localhost:8080. The credentials areadmin/admin.
-
Access http://localhost:8080
-
Login with the credentials
Username: admin Password: admin
- On the left menu, click the dropdown button that contains
Keycloakand then, clickCreate Realmbutton - Set
company-servicesto theRealm namefield and clickCreatebutton
- On the left menu, click
Authentication - Select
Required actionstab - Disable
Verify Profile
- On the left menu, click
Clients - Click
Create clientbutton - In
General Settings- Set
book-servicetoClient ID - Click
Nextbutton
- Set
- In
Capability config- Enable
Client authenticationtoggle switch - Click
Nextbutton
- Enable
- In
Login settingstab- Set
http://localhost:9080/*toValid redirect URIs - Click
Savebutton
- Set
- In
Credentialstab, you can find the secret generated forbook-service - In
Rolestab- Click
Create rolebutton - Set
manage_bookstoRole Name - Click
Savebutton
- Click
- On the left menu, click
Users - Click
Create new userbutton - Set
ivan.franchintoUsernamefield - Click
Create - In
Credentialstab- Click
Set passwordbutton - Set the value
123toPasswordandPassword confirmation - Disable the
Temporarytoggle switch - Click
Savebutton - Confirm by clicking
Save passwordbutton
- Click
- In
Role Mappingstab- Click
Assign rolebutton - Click
Filter by realm rolesdropdown button and selectFilter by clients - Select
[book-service] manage_booksname and clickAssignbutton
- Click
-
Open a new terminal and navigate to the
springboot-keycloak-mongodb-testcontainersroot folder -
Run the following command to start the application
./gradlew book-service:clean book-service:bootRun --args='--server.port=9080'
-
In a terminal, navigate to the
springboot-keycloak-mongodb-testcontainersroot folder -
Build Docker Image
./build-docker-images.sh
Environment Variable Description MONGODB_HOSTSpecify host of the Mongodatabase to use (defaultlocalhost)MONGODB_PORTSpecify port of the Mongodatabase to use (default27017)KEYCLOAK_HOSTSpecify host of the Keycloakto use (defaultlocalhost)KEYCLOAK_PORTSpecify port of the Keycloakto use (default8080) -
Run
book-servicedocker container, joining it to project Docker networkdocker run --rm --name book-service \ -p 9080:8080 \ -e MONGODB_HOST=mongodb \ -e KEYCLOAK_HOST=keycloak \ --network=springboot-keycloak-mongodb-testcontainers-net \ ivanfranchin/book-service:1.0.0
-
In a terminal, create an environment variable that contains the
Client Secretgenerated byKeycloaktobook-serviceat Configure Keycloak stepBOOK_SERVICE_CLIENT_SECRET=...
-
When running book-service with Gradle
Run the commands below to get an access token for
ivan.franchinACCESS_TOKEN=$(curl -s -X POST \ "http://localhost:8080/realms/company-services/protocol/openid-connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=ivan.franchin" \ -d "password=123" \ -d "grant_type=password" \ -d "client_secret=$BOOK_SERVICE_CLIENT_SECRET" \ -d "client_id=book-service" | jq -r .access_token) echo $ACCESS_TOKEN
-
When running book-service as a Docker Container
Run the commands below to get an access token for
ivan.franchinACCESS_TOKEN=$( docker run -t --rm -e CLIENT_SECRET=$BOOK_SERVICE_CLIENT_SECRET --network springboot-keycloak-mongodb-testcontainers-net alpine/curl:latest sh -c ' curl -s -X POST http://keycloak:8080/realms/company-services/protocol/openid-connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=ivan.franchin" \ -d "password=123" \ -d "grant_type=password" \ -d "client_secret=$CLIENT_SECRET" \ -d "client_id=book-service"' | jq -r .access_token) echo $ACCESS_TOKEN
Note: We are running a alpine/curl Docker container and joining it to the project Docker network. By specifying
"keycloak:8080"as host/port, we won't encounter the error related to an invalid token issuer. -
In jwt.io, you can decode and verify the
JWTaccess token
-
In terminal, call the endpoint
GET /api/bookscurl -i http://localhost:9080/api/books
It should return:
HTTP/1.1 200 [] -
Try to call the endpoint
POST /api/books, without access tokencurl -i -X POST http://localhost:9080/api/books \ -H "Content-Type: application/json" \ -d '{"authorName": "Ivan Franchin", "title": "Java 8", "price": 10.5}'
It should return:
HTTP/1.1 401 -
Get the Access Token as explained on section Getting Access Token
-
Call the endpoint
POST /api/books, now informing the access tokencurl -i -X POST http://localhost:9080/api/books \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"authorName": "Ivan Franchin", "title": "Java 8", "price": 10.5}'
It should return something like:
HTTP/1.1 201 {"id":"612f4f9438e39e473c4d098b", "authorName":"Ivan Franchin", "title":"Java 8", "price":10.5}
-
Click
GET /api/booksto open it. Then, clickTry it outbutton and, finally, clickExecutebutton.It will return a HTTP status code
200and an empty list or a list with some books if you've already added them. -
Now, let's try to call a secured endpoint without authentication. Click
POST /api/booksto open it. Then, clickTry it outbutton (you can use the default values) and, finally, clickExecutebutton.It will return:
Code: 401 Details: Error: response status is 401 -
Get the Access Token as explained on section Getting Access Token
-
Copy the token generated and go back to
Swagger -
Click the
Authorizebutton and paste the access token in theValuefield. Then, clickAuthorizeand, to finalize, clickClose -
Go to
POST /api/books, clickTry it outand, finally, clickExecutebutton.It should return something like:
HTTP/1.1 201 { "id": "612f502f38e39e473c4d098c", "authorName": "Ivan Franchin", "title": "SpringBoot", "price": 10.5 }
-
MongoDB
List books
docker exec -it mongodb mongosh bookdb db.books.find()
Type
exitto get out of MongoDB shell
- To stop
book-service, go to the terminal where the application is running and pressCtrl+C; - To stop the Docker containers started using the
./init-environment.shscript, make sure you are inspringboot-keycloak-mongodb-testcontainersand run the script below:./shutdown-environment.sh
To remove the Docker image created by this project, go to a terminal and, inside the springboot-keycloak-mongodb-testcontainers root folder, run the following script:
./remove-docker-images.sh-
In a terminal and inside the
springboot-keycloak-mongodb-testcontainersroot folder, run the command below to run unit and integration tests./gradlew book-service:clean book-service:assemble \ book-service:cleanTest \ book-service:test \ book-service:integrationTest
Note: During integration tests,
Testcontainerswill automatically startMongoDBandKeycloakcontainers before the tests begin and shut them down when the tests finish. -
From the
springboot-keycloak-mongodb-testcontainersroot folder, the Unit Testing Report can be found at:book-service/build/reports/tests/test/index.html -
From the
springboot-keycloak-mongodb-testcontainersroot folder, the Integration Testing Report can be found at:book-service/build/reports/tests/integrationTest/index.html
