Chapter 4. Security and Authentication of HawtIO
You can enable access logging on the runtimes/containers (e.g. Quarkus, OpenShift) as a security defensive measure for validating access. Access records can be used to investigate access attempts in the event of a security incident.
HawtIO enables authentication out of the box depending on the runtimes/containers it runs with. To use HawtIO with your application, either setting up authentication for the runtime or disabling HawtIO authentication is necessary.
4.1. Configuration properties
The following table lists the Security-related configuration properties for the HawtIO core system.
Name | Default | Description |
---|---|---|
hawtio.authenticationContainerDiscoveryClasses | io.hawt.web.tomcat.TomcatAuthenticationContainerDiscovery | List of used AuthenticationContainerDiscovery implementations separated by a comma. By default, there is just TomcatAuthenticationContainerDiscovery, which is used to authenticate users on Tomcat from tomcat-users.xml file. Feel free to remove it if you want to authenticate users on Tomcat from the configured JAAS login module or feel free to add more classes of your own. |
hawtio.authenticationContainerTomcatDigestAlgorithm | NONE | When using the Tomcat tomcat-users.xml file, passwords can be hashed instead of plain text. Use this to specify the digest algorithm; valid values are NONE, MD5, SHA, SHA-256, SHA-384, and SHA-512. |
hawtio.authenticationEnabled | true | Whether or not security is enabled. |
hawtio.keycloakClientConfig | classpath:keycloak.json | Keycloak configuration file used for the front end. It is mandatory if Keycloak integration is enabled. |
hawtio.keycloakEnabled | false | Whether to enable or disable Keycloak integration. |
hawtio.noCredentials401 | false | Whether to return HTTP status 401 when authentication is enabled, but no credentials have been provided. Returning 401 will cause the browser popup window to prompt for credentials. By default this option is false, returning HTTP status 403 instead. |
hawtio.realm | hawtio | The security realm used to log in. |
hawtio.rolePrincipalClasses | Fully qualified principal class name(s). A comma can separate multiple classes. | |
hawtio.roles | Admin, manager, viewer | The user roles are required to log in to the console. A comma can separate multiple roles to allow. Set to * or an empty value to disable role checking when HawtIO authenticates a user. |
hawtio.tomcatUserFileLocation | conf/tomcat-users.xml | Specify an alternative location for the tomcat-users.xml file, e.g. /production/userlocation/. |
4.2. Quarkus
HawtIO is secured with the authentication mechanisms that Quarkus and also Keycloak provide.
If you want to disable HawtIO authentication for Quarkus, add the following configuration to application.properties
:
quarkus.hawtio.authenticationEnabled = false
quarkus.hawtio.authenticationEnabled = false
4.2.1. Quarkus authentication mechanisms
HawtIO is just a web application in terms of Quarkus, so the various mechanisms Quarkus provides are used to authenticate HawtIO in the same way it authenticates a Web application.
Here we show how you can use the properties-based authentication with HawtIO for demonstrating purposes.
The properties-based authentication is not recommended for use in production. This mechanism is for development and testing purposes only.
To use the properties-based authentication with HawtIO, add the following dependency to
pom.xml
:<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-elytron-security-properties-file</artifactId> </dependency>
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-elytron-security-properties-file</artifactId> </dependency>
Copy to Clipboard Copied! You can then define users in
application.properties
to enable the authentication. For example, defining a userhawtio
with passwords3cr3t!
and roleadmin
would look like the following:quarkus.security.users.embedded.enabled = true quarkus.security.users.embedded.plain-text = true quarkus.security.users.embedded.users.hawtio = s3cr3t! quarkus.security.users.embedded.roles.hawtio = admin
quarkus.security.users.embedded.enabled = true quarkus.security.users.embedded.plain-text = true quarkus.security.users.embedded.users.hawtio = s3cr3t! quarkus.security.users.embedded.roles.hawtio = admin
Copy to Clipboard Copied!
Example:
See Quarkus example for a working example of the properties-based authentication.
4.2.2. Quarkus with Keycloak
4.3. Spring Boot
In addition to the standard JAAS authentication, HawtIO on Spring Boot can be secured through Spring Security or Keycloak. If you want to disable HawtIO authentication for Spring Boot, add the following configuration to application.properties
:
hawtio.authenticationEnabled = false
hawtio.authenticationEnabled = false
4.3.1. Spring Security
To use Spring Security with HawtIO:
Add
org.springframework.boot:spring-boot-starter-security
to the dependencies inpom.xml
:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
Copy to Clipboard Copied! Spring Security configuration in
src/main/resources/application.properties
should look like the following:spring.security.user.name = hawtio spring.security.user.password = s3cr3t! spring.security.user.roles = admin,viewer
spring.security.user.name = hawtio spring.security.user.password = s3cr3t! spring.security.user.roles = admin,viewer
Copy to Clipboard Copied! A security config class has to be defined to set up how to secure the application with Spring Security:
@EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorize -> authorize .anyRequest().authenticated() ) .formLogin(withDefaults()) .httpBasic(withDefaults()) .csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler()) ) .addFilterAfter(new CsrfCookieFilter(), BasicAuthenticationFilter.class); return http.build(); } }
@EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorize -> authorize .anyRequest().authenticated() ) .formLogin(withDefaults()) .httpBasic(withDefaults()) .csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler()) ) .addFilterAfter(new CsrfCookieFilter(), BasicAuthenticationFilter.class); return http.build(); } }
Copy to Clipboard Copied! NoteRefreshing the token after authentication success and logout success is required because the
CsrfAuthenticationStrategy
andCsrfLogoutHandler
will clear the previous token. The client application will not be able to perform an unsafe HTTP request, such as a POST, without obtaining a fresh token.
Example:
See springboot-security example for a working example.
4.3.1.1. Connecting to a remote application with Spring Security
If you try to connect to a remote Spring Boot application with Spring Security enabled, make sure the Spring Security configuration allows access from the HawtIO console. Most likely, the default CSRF protection prohibits remote access to the Jolokia endpoint and thus causes authentication failures at the HawtIO console.
Be aware that it will expose your application to the risk of CSRF attacks.
The easiest solution is to disable CSRF protection for the Jolokia endpoint at the remote application as follows.
import org.springframework.boot.actuate.autoconfigure.jolokia.JolokiaEndpoint; import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { ... // Disable CSRF protection for the Jolokia endpoint http.csrf().ignoringRequestMatchers(EndpointRequest.to(JolokiaEndpoint.class)); return http.build(); } }
import org.springframework.boot.actuate.autoconfigure.jolokia.JolokiaEndpoint; import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { ... // Disable CSRF protection for the Jolokia endpoint http.csrf().ignoringRequestMatchers(EndpointRequest.to(JolokiaEndpoint.class)); return http.build(); } }
Copy to Clipboard Copied! To secure the Jolokia endpoint even without Spring Security’s CSRF protection, you need to provide a
jolokia-access.xml
file undersrc/main/resources/
like the following (snippet) so that only trusted nodes can access it:<restrict> ... <cors> <allow-origin>http*://localhost:*</allow-origin> <allow-origin>http*://127.0.0.1:*</allow-origin> <allow-origin>http*://*.example.com</allow-origin> <allow-origin>http*://*.example.com:*</allow-origin> <strict-checking /> </cors> </restrict>
<restrict> ... <cors> <allow-origin>http*://localhost:*</allow-origin> <allow-origin>http*://127.0.0.1:*</allow-origin> <allow-origin>http*://*.example.com</allow-origin> <allow-origin>http*://*.example.com:*</allow-origin> <strict-checking /> </cors> </restrict>
Copy to Clipboard Copied!
4.3.2. Spring Boot with Keycloak
4.4. Keycloak Integration
You can secure your HawtIO console with Keycloak. To integration HawtIO with Keycloak, you need to:
- Prepare Keycloak server
- Deploy HawtIO to your favourite runtime (Quarkus, Spring Boot, WildFly, Karaf, Jetty, Tomcat, etc.) and configure it to use Keycloak for authentication
4.4.1. Prepare Keycloak server
Install and run Keycloak server. The easiest way is to use a Docker image:
docker run -d --name keycloak \ -p 18080:8080 \ -e KEYCLOAK_ADMIN=admin \ -e KEYCLOAK_ADMIN_PASSWORD=admin \ quay.io/keycloak/keycloak start-dev
docker run -d --name keycloak \
-p 18080:8080 \
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak start-dev
Here we use port number 18080
for the Keycloak server to avoid potential conflicts with the ports other applications might use.
You can log in to the Keycloak admin console http://localhost:18080/admin/ with user admin
/ password admin
. Import hawtio-demo-realm.json into Keycloak. To do so, click Create Realm
button and then import hawtio-demo-realm.json
. It will create hawtio-demo
realm.
The hawtio-demo
realm has the hawtio-client
application installed as a public client, and defines a couple of realm roles such as admin
and viewer
. The names of these roles are the same as the default HawtIO roles, which are allowed to log in to HawtIO admin console and to JMX.
There are also 3 users:
admin
-
User with password
admin
and roleadmin
, who is allowed to login into HawtIO. viewer
-
User with password
viewer
and roleviewer
, who is allowed to login into HawtIO. jdoe
-
User with password
password
and no role assigned, who is not allowed to login into HawtIO.
Currently, the difference in roles does not affect HawtIO access rights on Quarkus and Spring Boot, as HawtIO RBAC functionality is not yet implemented on those runtimes.
4.4.2. Configuration
HawtIO’s configuration for Keycloak integration consists of two parts: integration with Keycloak in the runtime (server side), and integration with Keycloak in the HawtIO console (client side).
The following settings need to be made for each part:
- Server side
- The runtime-specific configuration for the Keycloak adapter
- Client side
-
The HawtIO Keycloak configuration
keycloak-hawtio.json
4.4.2.1. Quarkus
Firstly, apply the required configuration for attaching HawtIO to a Quarkus application.
What you need to integrate your Quarkus application with Keycloak is Quarkus OIDC extension. Add the following dependency to pom.xml
:
pom.xml
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-oidc</artifactId> </dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc</artifactId>
</dependency>
4.4.2.1.1. Server side
Then add the following lines to application.properties
(which configures the server-side OIDC extension):
application.properties
quarkus.oidc.auth-server-url = http://localhost:18080/realms/hawtio-demo quarkus.oidc.client-id = hawtio-client quarkus.oidc.credentials.secret = secret quarkus.oidc.application-type = web-app quarkus.oidc.token-state-manager.split-tokens = true quarkus.http.auth.permission.authenticated.paths = "/*" quarkus.http.auth.permission.authenticated.policy = authenticated
quarkus.oidc.auth-server-url = http://localhost:18080/realms/hawtio-demo
quarkus.oidc.client-id = hawtio-client
quarkus.oidc.credentials.secret = secret
quarkus.oidc.application-type = web-app
quarkus.oidc.token-state-manager.split-tokens = true
quarkus.http.auth.permission.authenticated.paths = "/*"
quarkus.http.auth.permission.authenticated.policy = authenticated
quarkus.oidc.token-state-manager.split-tokens = true
is important, as otherwise you might encounter a large size session cookie token issue and fail to integrate with Keycloak.
4.4.2.1.2. Client side
Finally create keycloak-hawtio.json
under src/main/resources
in the Quarkus application project (which serves as the client-side HawtIO JS configuration):
keycloak-hawtio.json
{ "realm": "hawtio-demo", "clientId": "hawtio-client", "url": "http://localhost:18080/", "jaas": false, "pkceMethod": "S256" }
{
"realm": "hawtio-demo",
"clientId": "hawtio-client",
"url": "http://localhost:18080/",
"jaas": false,
"pkceMethod": "S256"
}
Set pkceMethod
to S256
depending on Proof Key for Code Exchange Code Challenge Method advanced settings configuration. If PKCE is not enabled, do not set this option.
Build and run the project and it will be integrated with Keycloak.
4.4.2.1.3. Example
See quarkus-keycloak example for a working example.
4.4.2.2. Spring Boot
Firstly, apply the required configuration for attaching HawtIO to a Spring Boot application.
What you need to integrate your Spring Boot application with Keycloak is to add the following dependency to pom.xml
(replace 4.x.y
with the latest HawtIO release version):
pom.xml
<dependency> <groupId>io.hawt</groupId> <artifactId>hawtio-springboot-keycloak</artifactId> <version>4.x.y</version> </dependency>
<dependency>
<groupId>io.hawt</groupId>
<artifactId>hawtio-springboot-keycloak</artifactId>
<version>4.x.y</version>
</dependency>
4.4.2.2.1. Server side
Then add the following lines in application.properties
(which configures the server-side Keycloak adapter):
application.properties
keycloak.realm = hawtio-demo keycloak.resource = hawtio-client keycloak.auth-server-url = http://localhost:18080/ keycloak.ssl-required = external keycloak.public-client = true keycloak.principal-attribute = preferred_username
keycloak.realm = hawtio-demo
keycloak.resource = hawtio-client
keycloak.auth-server-url = http://localhost:18080/
keycloak.ssl-required = external
keycloak.public-client = true
keycloak.principal-attribute = preferred_username
4.4.2.2.2. Client side
Finally create keycloak-hawtio.json
under src/main/resources
in the Spring Boot project (which serves as the client-side HawtIO JS configuration):
keycloak-hawtio.json
{ "realm": "hawtio-demo", "clientId": "hawtio-client", "url": "http://localhost:18080/", "jaas": false }
{
"realm": "hawtio-demo",
"clientId": "hawtio-client",
"url": "http://localhost:18080/",
"jaas": false
}
Build and run the project and it will be integrated with Keycloak.
4.4.2.2.3. Example
See springboot-keycloak example for a working example.