Securing Quarkus with Elytron Database Realm

Quarkus security includes several extensions from Elytron. In this tutorial we will learn how to use the Database Realm Authentication with a simple REST Service.

Our project will perform authentication against the H2 in-memory database. In order to bootstrap our project we will need the following extensions

mvn io.quarkus:quarkus-maven-plugin:1.0.0.CR1:create \
    -DprojectGroupId=com.mastertheboss \
    -DprojectArtifactId=quarkus-jdbc-realm \
    -DclassName="com.mastertheboss.SecuredResource" \
    -Dextensions="elytron-security-jdbc,  jdbc-h2, resteasy" \
    -Dpath="/hello"

Now let’s add at first some protected resources in our REST Service. We will add one resource secured against the “admin” Role and one secured against the “guest” Role:

package com.mastertheboss;

import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/")
public class SecuredResource {

    @GET
    @Path("/securedAdmin")
    @RolesAllowed("admin")
    @Produces(MediaType.TEXT_PLAIN)
    public String helloAdmin() {
        return "Hello from secured resource!";

    }

    @GET
    @Path("/securedGuest")
    @RolesAllowed("guest")
    @Produces(MediaType.TEXT_PLAIN)
    public String helloGuest() {
        return "Hello from secured resource!";

    }
}
package com.mastertheboss;

import io.quarkus.test.junit.QuarkusTest;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;

@QuarkusTest
public class SecuredResourceTest {

    @Test
    public void testHelloEndpoint() {

        given()
                .auth().preemptive().basic("admin", "admin")
                .when()
                .get("/securedAdmin")
                .then()
                .statusCode(HttpStatus.SC_OK);

        given()
                .auth().preemptive().basic("guest", "guest")
                .when()
                .get("/securedGuest")
                .then()
                .statusCode(HttpStatus.SC_OK);

    }

}

To have Quarkus bootstrap the H2 Database, include the following class which triggers the H2DatabaseTestResource:

package com.mastertheboss;

import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.h2.H2DatabaseTestResource;

@QuarkusTestResource(H2DatabaseTestResource.class)
public class TestResources {
}

As the above class is included in an external JAR file, you have to add its dependency to the pom.xml file:

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-test-h2</artifactId>
      <scope>test</scope>
    </dependency>

Configuring Elytron Database Realm with Quarkus

Done with the source code, let’s now add the configuration to bootstrap the Database Realm. First of all, an import.sql script to create the Tables at start is needed. It will also add two users for testing our project:

CREATE TABLE test_user (
  id INT,
  username VARCHAR(255),
  password VARCHAR(255),
  role VARCHAR(255)
);

INSERT INTO test_user (id, username, password, role) VALUES (1, 'admin', 'admin', 'admin');
INSERT INTO test_user (id, username, password, role) VALUES (2, 'user','user', 'user');

Then, into the application.properties file, add the configuration of the Elytron Realm, which points to the Table we have just created:

quarkus.datasource.url=jdbc:h2:tcp://localhost/mem:elytron_jdbc_test;DB_CLOSE_DELAY=-1;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM 'classpath:import.sql'
quarkus.datasource.driver=org.h2.Driver
quarkus.datasource.username=username-default

quarkus.security.jdbc.enabled=true
quarkus.security.jdbc.principal-query.sql=SELECT u.password, u.role FROM test_user u WHERE u.username=?
quarkus.security.jdbc.principal-query.clear-password-mapper.enabled=true
quarkus.security.jdbc.principal-query.clear-password-mapper.password-index=1
quarkus.security.jdbc.principal-query.attribute-mappings.0.index=2
quarkus.security.jdbc.principal-query.attribute-mappings.0.to=groups

Here is the full project structure:

src
├── main
│   ├── docker
│   │   ├── Dockerfile.jvm
│   │   └── Dockerfile.native
│   ├── java
│   │   └── com
│   │       └── mastertheboss
│   │           └── SecuredResource.java
│   └── resources
│       ├── application.properties
│       └── META-INF
│           └── resources
│               └── index.html
└── test
    ├── java
    │   └── com
    │       └── mastertheboss
    │           ├── NativeSecuredResourceIT.java
    │           ├── SecuredResourceTest.java
    │           └── TestResources.java
    └── resources
        └── import.sql

Running the Test class

Done with the code and configuration, you can run the Test as follows:

mvn install

As you can see from the logs, the test completed successfully and, behind the hoods, the IT started and stopped the Database when done:

[INFO] H2 database started in TCP server mode; server status: TCP server running at tcp://10.5.126.52:9092 (only local connections)
2019-11-11 18:20:03,126 INFO  [io.qua.dep.QuarkusAugmentor] (main) Beginning quarkus augmentation
2019-11-11 18:20:04,122 INFO  [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed in 996ms
2019-11-11 18:20:04,735 INFO  [io.quarkus] (main) Quarkus 1.0.0.CR1 started in 0.585s. Listening on: http://0.0.0.0:8081
2019-11-11 18:20:04,735 INFO  [io.quarkus] (main) Profile test activated. 
2019-11-11 18:20:04,736 INFO  [io.quarkus] (main) Installed features: [agroal, cdi, jdbc-h2, narayana-jta, resteasy, security, security-jdbc]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 7.258 s - in com.mastertheboss.SecuredResourceTest

That’s all! Source code for this tutorial: https://github.com/fmarchioni/mastertheboss/tree/master/quarkus/quarkus-jdbc-realm

Found the article helpful? if so please follow us on Socials