Basic-Authentication für Single-User-Applikation mit Quarkus

Basic-Authentication für Single-User-Applikation mit Quarkus

Wir haben eine simple Single-User-Applikation mit Quarkus geschrieben und möchten dieser nun für den Admin-Bereich einen Zugriffsschutz hinzufügen. Es reicht uns vollkommen aus Basic Authentication zu nutzen und die Benutzerdaten embedded (aber konfigurierbar) zu speichern.

Diese Aufgabe ist eigentlich schnell erledigt, aber leider etwas wirr bzw. umständlich dokumentiert [2].

Konfiguration

Die komplette Arbeit können wir in unserer application.properties erledigen:

quarkus.http.auth.basic=true
quarkus.http.auth.policy.admin-policy.roles-allowed=admin
quarkus.http.auth.permission.admin-permission.paths=/admin*
quarkus.http.auth.permission.admin-permission.policy=admin-policy
quarkus.security.users.embedded.enabled=true
quarkus.security.users.embedded.plain-text=true
quarkus.security.users.embedded.users.admin=password
quarkus.security.users.embedded.roles.admin=admin

Gehen wir die Konfiguration Zeile für Zeile durch:

  1. Basic Authentication aktivieren
  2. Policy mit dem Namen admin-policy erstellen zu der alle Benutzer mit der Rolle admin gehören
  3. Permission namens admin-permission erstellen und den Pfad /admin* zuweisen (das * dient hier als Wildcard. Der Pfad matched also sowohl auf /admin als bspw. auch auf /admin/foo/bar)
  4. Zuvor erstellte admin-permission die Policy admin-policy hinzufügen
  5. Embedded Benutzerverwaltung aktivieren
  6. Klartextpasswörter aktivieren (ansonsten werden die Passwörter in dem Format HEX( MD5( username ":" realm ":" password ) ) erwartet
  7. Benutzer admin mit dem Passwort password erstellen
  8. Benutzer admin die Rolle admin zuweisen

Dependencies

Nun müssen wir nur noch die auf WildFly Elytron basierte Quarkus-Extension unserer pom.xml als Abhängigkeit hinzufügen

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-elytron-security-properties-file</artifactId>
</dependency>

Resources

Erstellen wir nun noch zwei Resources bzw. Endpoints um unserer Setup zu testen.

@Path("/admin")
public class AdminResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "hello admin";
    }
}
@Path("/public")
public class PublicResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "hello user";
    }
}

Der /admin-Endpoint dürfte nur für den admin-Benutzer zugreifbar sein und /public für jeden - auch unauthentifizierten - Benutzer. Testen wir das einfach.

Tests

@QuarkusTest
public class AdminResourceTest {

    @Test
    public void testAdminEndpoint() {
        given()
                .when()
                .auth().basic("admin", "password")
                .get("/admin")
                .then()
                .statusCode(Response.Status.OK.getStatusCode())
                .body(is("hello admin"));
    }

    @Test
    public void testAdminEndpoint_WithoutAuth() {
        given()
                .when().get("/admin")
                .then().statusCode(Response.Status.UNAUTHORIZED.getStatusCode());
    }
}
@QuarkusTest
public class PublicResourceTest {

    @Test
    public void testPublicEndpoint() {
        given()
                .when().get("/public")
                .then()
                .statusCode(Response.Status.OK.getStatusCode())
                .body(is("hello user"));
    }
}

Funktioniert!

Fazit

Die gestellte Aufgabe ist wirklich schnell und einfach gelöst. Leider ist die Dokumentation [2] dazu etwas wirr bzw. umständlich gehalten. Das mag sicherlich daran liegen, dass die geschilderte Anforderung doch eher die Ausnahme darstellt und man üblicherweise eine Lösung wie OAuth oder LDAP integrieren möchte.

Die beschriebene Konfiguration könnte nun auch problemlos um weitere Benutzer, Rollen, Permissions und Policies erweitert werden. Man sollte sich jedoch fragen, ob es bei einer Multi-User-Applikation nicht sinnvoller ist zumindest die Benutzerverwaltung in eine Datenbank zu schieben, wenn nicht sogar eher eine der bereits genannten Lösungen zu nutzen.

Eine lauffähige Demo ist auf Github zu finden: github.com/pklink/quarkus-simple-basic-auth

(Titelbild von Ivan Bandura)