Τρίτη 22 Αυγούστου 2023

Overview - Run embedded Keycloak with Spring Boot

             Run embedded Keycloak with Spring Boot



No need to download and setup Keycloak locally. To run embedded Keycloak, we need generally to:

1.
Create a json for our Keycloak:





2.

Import maven dependencies and plugin in pom:


        <dependency>

            <groupId>org.jboss.resteasy</groupId>

           <artifactId>resteasy-jackson2-provider</artifactId>

            <version>${resteasy.version}</version>

        </dependency>


        <dependency>

            <groupId>org.keycloak</groupId>

            <artifactId>keycloak-dependencies-server-all</artifactId>

            <version>${keycloak.version}</version>

            <type>pom</type>

        </dependency>

        

        <dependency>

            <groupId>org.keycloak</groupId>

            <artifactId>keycloak-crypto-default</artifactId>

            <version>${keycloak.version}</version>

        </dependency>


        <dependency>

            <groupId>org.keycloak</groupId>

            <artifactId>keycloak-admin-ui</artifactId>

            <version>${keycloak.version}</version>

        </dependency>


        <dependency>

            <groupId>org.keycloak</groupId>

            <artifactId>keycloak-services</artifactId>

            <version>${keycloak.version}</version>

        </dependency>

    

         <dependency>

    <groupId>org.keycloak</groupId>

    <artifactId>keycloak-rest-admin-ui-ext</artifactId>

    <version>${keycloak.version}</version>

 </dependency>


...


  <plugin>

                <groupId>org.springframework.boot</groupId>

                <artifactId>spring-boot-maven-plugin</artifactId>

                <configuration>

                    <mainClass>com.codeinpackets.auth.

                         AuthorizationServerApp</mainClass>

                    <requiresUnpack>

                        <dependency>

                            <groupId>org.keycloak</groupId>

                            <artifactId>keycloak-model-jpa</artifactId>

                        </dependency>

                    </requiresUnpack>

                </configuration>

            </plugin>



3.
In our application yml, where we mention the json:


server:
  port: 8083

keycloak:
  server:
    contextPath: /auth
    adminUser:
      username: cip-admin
      password: pass
    realmImportFile: cip-realm.json



4.
Create a config properties class to bind our properties above:

@ConfigurationProperties(prefix = "keycloak.server")
public class KeycloakServerProperties {


    String contextPath = "/auth";
    String realmImportFile = "cip-realm.json";
    AdminUser adminUser = new AdminUser();


    // getters, setters
    public String getContextPath() {
        return contextPath;
    }
    public void setContextPath(String contextPath) {
        this.contextPath = contextPath;
    }
    public AdminUser getAdminUser() {
        return adminUser;
    }
    public void setAdminUser(AdminUser adminUser) {
        this.adminUser = adminUser;
    }
    public String getRealmImportFile() {
        return realmImportFile;
    }
    public void setRealmImportFile(String realmImportFile) {
        this.realmImportFile = realmImportFile;
    }
    public static class AdminUser {
        String username = "admin";
        String password = "admin";
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
    }
}



5.
Finally bind and run all together:

@SpringBootApplication
@EnableConfigurationProperties({ KeycloakServerProperties.class })
public class AuthorizationServerApp {


private static final Logger LOG = LoggerFactory.getLogger(AuthorizationServerApp.class);


public static void main(String[] args) throws Exception {
SpringApplication.run(AuthorizationServerApp.class, args);
}

// Log and verify Keycloak runs fine:
@Bean
ApplicationListener<ApplicationReadyEvent> onApplicationReadyEventListener(ServerProperties serverProperties,
KeycloakServerProperties keycloakServerProperties) {


return (evt) -> {
Integer port = serverProperties.getPort();
String keycloakContextPath = keycloakServerProperties.getContextPath();
LOG.info("Embedded Keycloak server has started, use http://localhost:{}{}", port, keycloakContextPath);
};
}
}

Δευτέρα 21 Αυγούστου 2023

@ConstructorBinding in Spring Boot

                  @ConstructorBinding in Spring Boot 3



This annotation is no longer needed along with @ConfigurationProperties classes. If there's at least one constructor, Spring Boot implicitly uses constructor binding for our properties.



@ConfigurationProperties(prefix = "mail.credentials")

public class ImmutableCredentials {


    private final String authMethod;

    private final String username;

    private final String password;


    public ImmutableCredentials(String authMethod, String username, String password) {

        this.authMethod = authMethod;

        this.username = username;

        this.password = password;

    }


    public String getAuthMethod() {

        return authMethod;

    }


    public String getUsername() {

        return username;

    }


    public String getPassword() {

        return password;

    }

}


Only if we have multiple constructors, we have to use it on the prefered constructor:


@ConfigurationProperties(prefix = "mail.credentials")

public class ImmutableCredentials {


    private final String authMethod;

    private final String username;

    private final String password;

 

// constructor 1

    @ConstructorBinding

    public ImmutableCredentials(String authMethod, String username, String password) {

        this.authMethod = authMethod;

        this.username = username;

        this.password = password;

    }


// constructor 2

    public ImmutableCredentials(String authMethod, String username) {

        this.authMethod = authMethod;

        this.username = username;  

    }


    public String getAuthMethod() {

        return authMethod;

    }


    public String getUsername() {

        return username;

    }


    public String getPassword() {

        return password;

    }

}




       @ConstructorBinding was introduced in Spring Boot 2.2


Before version 2.2 one could only use setters to bind properties with Java fields. But after 2.2, this annotation was introduced to allow binding the properties via a parameterized constructor.




Sources:

Spring docs - Constructor Binding

Spring docs - ConfigurationProperties

Spring Boot 3 - Constructor Binding