Tuesday, December 7, 2021

Secure Spring boot 2 with Keycloak 15

Secure Spring boot 2 with Keycloak 15

We'll cover the basics of setting up a keycloak server, connecting spring boot microservices, also using spring security.

1. Setting Up a keycloack server.

Please check the steps to install keycloak server here.

2. Creating a Realm

For default the console opens up Master realm, Let's navigate left corner Add realm button.













For this example I typed the name demo1. we'll click the button create.













3. Creating a client









Add a new client with the name springboot-keycloak with openid-connect. click button save.
































We'll be creating a spring boot microservices running at the port 8081, we've used a redirect URL of http://localhost:8081 above on image.

4. Creating a Role








Add next roles, "admin" and "user".
















5. Creating a Users

Add next users: user1 to role user and user2 to role admin.










Set a password. I typed the password for the same user1 and user2. For this example.






















Set a role(s).

















You'll do the same steps with de user2 however the role is "admin".







5. Creating a Spring Boot Application

In this examples we're intregation Spring Boot and keycloack.

  • Configuration Spring boot, Spring Data and Keycloack.
  • Define Datas Models, Repository.
  • Spring Rest Controllers  


Spring Boot Rest  API 

These are APIs that we need to provide:

MethodsUrls
POST/users
GET/users

Technology

  • Java 11
  • Spring Boot 2.6.1
  • Mysql 8.0.23
  • Maven 3.6.3
  • Postman v9.0.8
  • IntelliJ IDEA 2021.2.3 

Project Structure


























Configuration Spring Boot Keycloak project 


pom.xml


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>

application.yml


server:
port: 8081

keycloak:
auth-server-url: http://127.0.0.1:9080/auth
realm: demo1
resource: springboot-keycloack
public-client: true
bearer-only: true

spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/backend?allowPublicKeyRetrieval=true&useSSL=false
username: henry
password: *********
hikari:
initialization-fail-timeout: 0
jpa:
database-platform: org.hibernate.dialect.MySQL5Dialect
generate-ddl: true
show-sql: true
hibernate:
ddl-auto: create

Class Security configuration


I suggest to you, we 'll be reading Spring Boot Adapters, I copied from Spring Boot Adapters the configuration class.

package com.henry.keycloack.springboot2keycloak.configuration;

import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;

@KeycloakConfiguration
@Import(KeycloakSpringBootConfigResolver.class)
@EnableGlobalMethodSecurity(jsr250Enabled = true)//so i need the roles exist environment, @RolesAllowed
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
/**
* Registers the KeycloakAuthenticationProvider with the authentication manager.
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

KeycloakAuthenticationProvider keycloakAuthenticationProvider = new KeycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}

/**
* Defines the session authentication strategy.
*/
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}

@Override
protected void configure(HttpSecurity http) throws Exception
{
super.configure(http);
http
.authorizeRequests()
.anyRequest().permitAll();
http.csrf().disable();
}
}


Data class model


package com.henry.keycloack.springboot2keycloak.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
@Table
public class User {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
}

Repository Interface

package com.henry.keycloack.springboot2keycloak.repository;

import com.henry.keycloack.springboot2keycloak.model.User;
import org.springframework.data.repository.CrudRepository;

public interface UserRepository extends CrudRepository<User,Integer> {
}


Spring Rest APIs Controller

package com.henry.keycloack.springboot2keycloak.controller;

import com.henry.keycloack.springboot2keycloak.model.User;
import com.henry.keycloack.springboot2keycloak.repository.UserRepository;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.security.RolesAllowed;

@RestController
public class UserController {

private final UserRepository userRepository;

public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}

@PostMapping("/users")
@RolesAllowed({"user"})
public ResponseEntity<User> save(@RequestBody User user){
return ResponseEntity.ok(userRepository.save(user));
}

@GetMapping("/users")
@RolesAllowed("admin")
public ResponseEntity<Iterable<User>> findAll(){
return ResponseEntity.ok(userRepository.findAll());
}
}

Run & Test


Run Spring Boot application with command: mvn spring-boot:run. by console, IntelliJ etc.

Keycloak provides a REST API for generating and refreshing access tokens. 

Let's go.


1. We need to acquire an access token from Keycloak from this url. 

  • 127.0.0.1 if you want will change to localhost.
  • Port: 9080 in my case.
  • auth/realms url defined by keycloak.
  • demo1 is the name of your realm.
  • protocol/openid-connect/token url defined by keycloak.

 http://127.0.0.1:9080/auth/realms/demo1/protocol/openid-connect/token


2. Configurate on Postman.


GET. 

I used the user "user2" role "admin", we'll check images. 















Access Token url. http://127.0.0.1:9080/auth/realms/demo1/protocol/openid-connect/token















Click on Get New Acces token.


















Click Use Token.






































POST. 

I used the user "user1" role "user", we'll check images. 




































Source Code


Here on Github.




References.

https://www.baeldung.com/spring-boot-keycloak
https://www.youtube.com/watch?v=rcvAmBoDlLk






Friday, December 3, 2021

Install keycloak 15.0.2 on ubuntu 20.04

Keycloak

Keycloak is an open source identity and access management for modern applications and services, no need to deal with storing users or authenbticating users. it's all available out of the box.

you'll even get advanced features such as user federation (LDAP or kerberos) and social login.


Downloading and installing keycloack

Let's download the keycloak-15.0.2 Standalone server distribution from the official source.

let unzip i suggest change default port 8080, when you run standalone.sh add next argumets port-offset=1000 then (8080+1000=9080).


unzip keycloak-15.0.2.zip
cd keycloak-15.0.2/bin
./standalone.sh -Djboss.socket.binding.port-offset=1000

Open a browser  http://localhost:9080 or http://127.0.0.1:9080 result this.

















Open Create a initial admin user and the password.


























We can now proceed to the Administrative Console.


 


















































That it is.
















Virtual Threads in Java 21: Simplified Concurrency for Modern Applications

  With Java 21, Virtual Threads have redefined how we approach concurrency, offering a lightweight and efficient way to handle parallel and ...