Secure Spring Boot + Angular 9 Application using KeyCloak(2/3)

Part 2: Configuring and Setting up Spring Boot backend as a Resource Server

Kamlesh Badgujar
6 min readMay 31, 2020

In Part 1 of this series, we’ve configured the KeyCloak instance and added the Realm as well as Client level roles. Later on, we’ve created 3 users and assigned them respective roles. In this tutorial, we will configure Spring Boot backend and implement Role-Based Access in our application.

Before proceeding, please make sure that you’ve read my previous tutorial on the configuration of the KeyCloak instance. If not, check out Secure Spring Boot + Angular 9 Application using KeyCloak(1/3).

Spring Boot Application Configuration

Let’s build a new Spring Boot application and configure it with Keycloak Spring Boot Adaptor.

Creating the Spring Boot Application

To generate the initial project structure, visit Spring Initializr: https://start.spring.io/

Provide the below details.

  1. Project: Maven Project
  2. Language: Java
  3. Spring Boot: 2.3.0 or select the latest stable version
  4. Project Metadata: Provide metadata information of your choice.
  5. Packaging: Jar
  6. Java: 11
  7. Dependencies: Add Spring Web, Spring Security, and Spring Boot DevTools
Spring Initializer

Click Generate to download the project zip version and extract it. Open it in Eclipse IDE or any IDE of your choice.

Now we need to do some changes in the pom.xml file.

pom.xml

  1. Add KeyCloak version in properties. It should match with your KeyCloak version.
<properties>
<java.version>11</java.version><keycloak.version>10.0.1</keycloak.version>
</properties>

2. Add KeyCloak dependency.

Find dependencies section and add keycloak-spring-boot-starter.

<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>${keycloak.version}</version>
</dependency>
</dependencies>

3. Add Dependency Management

Add the following code below <dependencies> section.

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId
<version>${keycloak.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

Now, we need to set-up KeyCloak as an authorization server in Spring Boot. For that purpose, we need to configure the KeyCloak server instance in application.properties which is under src/main/resources.

application.properties

server.port=9090
keycloak.realm = heroes
keycloak.auth-server-url = http://127.0.0.1:8080/auth
keycloak.ssl-required = external
keycloak.resource = spa-heroes-backend
keycloak.use-resource-role-mappings = true
keycloak.bearer-only = true

keycloak.realm: Name of the realm. In our case, it is heroes. This is REQUIRED.

keycloak.auth-server-url: The base URL of the Keycloak server. All other Keycloak pages and REST service endpoints are derived from this. It is usually of the form https://host:port/auth. This is REQUIRED.

keycloak.ssl-required: Ensures that all communication to and from the Keycloak server is over HTTPS. In production, this should be set to all. This is OPTIONAL. The default value is external meaning that HTTPS is required by default for external requests. Valid values are 'all', 'external' and 'none'.

keycloak.resource: The client-id of the application we’ve created in the KeyCloak. In our case, it is spa-heroes-backend. This is REQUIRED.

keycloak.use-resource-role-mappings: If set to true, the adapter will look inside the token for client-level role mappings for the user. If false, it will look at the realm level for user role mappings. As we’ve created client-level role mapping, it is set to true. This is OPTIONAL.

keycloak.bearer-only: This should be set to true for services. If enabled the adapter will not attempt to authenticate users, but only verify bearer tokens. In our case, it’ll be set to true because our backend service won’t authenticate user, it’ll be done by our frontend application. Backend service will only authorize bearer tokens supplied by the logged-in user. This is OPTIONAL. The default value is false.

You can find more information about these properties here.

ResourceServerConfig.java

Keycloak provides a KeycloakWebSecurityConfigurerAdapter as a convenient base class for creating a WebSecurityConfigurer instance. The implementation allows customization by overriding methods. While its use is not required, it greatly simplifies our security context configuration.

Create ResourceServerConfig.java class in the config package.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class ResourceServerConfig extends KeycloakWebSecurityConfigurerAdapter { @Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests().anyRequest().permitAll();
http.csrf().disable();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
@Override
protected SessionAuthenticationStrategy
sessionAuthenticationStrategy() {
return new NullAuthenticatedSessionStrategy();
}
@Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
  • configureGlobal: tasks the SimpleAuthorityMapper to make sure roles are not prefixed with ROLE_. By default when used Role-Based mapping, spring-security adds ROLE_ prefix to every role.
  • keycloakConfigResolver: this defines that we want to use the Spring Boot properties file support instead of the default keycloak.json.
  • sessionAuthenticationStrategy: You must provide a session authentication strategy bean which should be of a type RegisterSessionAuthenticationStrategy for public or confidential applications and NullAuthenticatedSessionStrategy for bearer-only applications. Our spa-heroes-backend client is a bearer only application.
  • @EnableGlobalMethodSecurity: The jsr250Enabled property allows us to use the @RolesAllowed annotation. We’ll explore more about this annotation in the next section.

We’re done with setting our Spring boot application as a resource server. Note that in OAuth2.0 terminology, Resource Server is a backend application that is hosting resources(e.g. REST APIs), and Authorization Server is a KeyCloak instance.

Each time user logs in into our application and hits our API, spring boot will verify the bearer token of the user with the KeyCloak server and will grant/deny access based on the KeyCloak’s response.

Hero Model

Create our Hero Model class in com.example.model package.

public class Hero {private final int id;
private final String name;
public Hero(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}

HeroController

Create HeroController.java class in com.example.controller package.

@CrossOrigin("*")
@RestController
@RequestMapping("/api/heroes")

public class HeroController {
private List<Hero> someHeroes = List.of(
new Hero(1, "Ken"),
new Hero(2, "Yannick"),
new Hero(3, "Pieter"));
}
@GetMapping
@RolesAllowed({"heroes-user", "heroes-admin"})
public List<Hero> heroes() {
return someHeroes;
}
@GetMapping("/{id}")
@RolesAllowed("heroes-admin")
public Hero hero(@PathVariable("id") String id) {
return someHeroes.stream()
.filter(h -> Integer.toString(h.getId()).equals(id))
.findFirst()
.orElse(null);
}
}

Through @GetMapping annotation, we’ve exposed our 2 REST APIs, namely public List<Hero> heroes() and public Hero hero() .

We’ve defined Role-Based Access to those 2 REST APIs with @RolesAllowed annotation.

public List<Hero> heroes() : Will be accessible only if logged-in user Role is heroes-user

public Hero hero(): Will be accessible only if logged-in user Role is heroes-admin

NOTE: Make sure your main method class’s package name is com.<your-preferred-name> , like this:

Final Application structure

Otherwise, our HTTP request to REST API will fail.

Now if we try to access API through postman, we will get 401 Unauthorized error.

401 Unauthorized error in Postman

That means our REST APIs are secured now!

Note that we’ve configured the Roles in previous tutorial, Secure Spring Boot + Angular 9 Application using KeyCloak(1/3).

As we’ve registered the KeyCloak as an Authorization Server in our spring boot application through ResourceServerConfig class and application.properties file, each time we hit REST API, spring boot application will check for the Bearer Token from the client and will verify it with the KeyCloak Server. In our case, we didn’t have the Bearer Token. So, we’ve got an error 401 Unauthorized.

Bearer Token will be requested from the KeyCloak Server by our frontend Angular application. We’ll see how to generate Bearer Token request from Angular application and access REST APIs in the next tutorial.

Source code: https://github.com/kamleshbadgujar/heroes-backend

--

--