GEDOPLAN
Jakarta EE (Java EE)

Bye Bye Basic Auth Popup für Java EE

Jakarta EE (Java EE)

Die wohl einfachste Methode eine Java EE Anwendung ab zu sichern ist durch eine Basic Authentifikation die durch einen entsprechenden Eintrag in der web.xml aktiviert wird. Anfragen ohne berechtigen Benutzer führen dann in der Antwort zu einem 401 Fehler der den Browser dazu veranlasst einen Dialog an zu zeigen der um die Eingabe der Benutzerdaten bittet. Doch was wenn wir diesen Dialog unterbinden wollen und stattdessen z.B. eine eigene Möglichkeit bieten wollen einen Login durch zu führen?

Ein einfach gehaltenes Beispiel zur Basic Authentifizierung

web.xml:

 <security-constraint>
    <web-resource-collection>
        <web-resource-name>webresources</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>admin</role-name>
        <role-name>customer</role-name>
    </auth-constraint>
</security-constraint>

<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>ApplicationRealm</realm-name>
</login-config>
<security-role>
    <role-name>admin</role-name>
</security-role>
<security-role>
    <role-name>customer</role-name>
</security-role>

Eine solche Definition hat zur Folge, dass der angesprochene Dialog vom Browser angezeigt wird:

basicauth_login2

Und hier fangen die Probleme an. Der Browser selbst erkennt den Status (401) und prüft auf das Vorhandensein eines WWW-Authenticate-Headers. Ist dies der Fall zeigt der Browser den dargestellten Dialog an. Auf Clientseite, z.B. einer AngularJS Anwendung, hat der Entwickler keinerlei Chance auf einen solchen Fehler zu reagieren da die Response gar nicht zum aufrufenden Code weiter gegeben wird. Die Lösung des Problems besteht darin auf Seite des Servers sicher zu stellen das in einem solchen Fehlerfall ein anderer Statuscode geliefert wird als der Standard es vorsieht. Wer hier an einen einfachen Servlet-Filter denkt liegt leider falsch, da auch ein Servlet-Filter in einem solchen Fall auf Server Seite nicht angesprochen wird. Trotzdem bietet uns der Java EE Standard eine einfache Möglichkeit auf 401-Fehler zu reagieren

error-page

Die web.xml unserer Anwendung bietet uns die Möglichkeit eigene Fehlerseiten zu definieren um auf spezifische Fehler zu reagieren (basierend auf Statuscode oder Excption-Typ). Dieser Konfigurationswert darf jedoch nicht nur eine statische Seite als Wert annehmen sondern auch ein Servlet. Das machen wir uns zu Nutzen um 401 Fehler auf einen entsprechend eigens definieren Statuscode zu setzen.

<error-page>
    <error-code>401</error-code>
    <location>/AccessExceptionHandler</location>
</error-page>

AccessExceptionHandler:

@WebServlet("/AccessExceptionHandler")
public class AccessExceptionHandler extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processError(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processError(request, response);
    }

    private void processError(HttpServletRequest request, HttpServletResponse response) throws IOException {
         response.setContentType("text/html");
         response.setStatus(455);
         PrintWriter out = response.getWriter();
         out.write("User not allowed to perform specified Method");
    }
}

Der hier gewähle Status-Code “455” ist beliebig Wählbar, jedoch sollte darauf geachtet werden keine bereits im Standard definierten Code zu verwenden (s. HTTP-Spec-StatusCodes ).

Security-Regel auf Service – Ebene

Im obigen Beispiel legen wir unsere Security-Richtlinien auf konkrete Pfade innerhalb unserer Webanwendung. Denkbar wäre jedoch auch auf diese Deklaration zu verzichten und lediglich auf der Ebene unserer Services mit entsprechenden Annotationen zu arbeiten die für eine Benutzer / Rollen Prüfung sorgt.

Beispiel einer Service-EJB (die wiederrum über eine Rest-Ressource verwendet wird):

@RolesAllowed({"admin"})
public Customer updateCustomer(Customer customer)
{
    return customerRepostory.updateCustomer(customer);
}

Dieses Vorgehen hat einen entscheidenden Vorteil: Sowohl jegliche Rest-Zugriffe als auch Serverseitige Aufrufe von z.B. JSF, werden zentral durch diese Annotationen in der Berechtigung geprüft. Aufrufe mittels eines nicht berechtigten Users (oder keinem) führen im Falle eines Fehlers zu einer javax.ejb.EJBAccessException. Zusätzlich zu der obigen Definition eines Servlets als Error-Page können wir  für unsere Rest-Schnittstelle  diesen Fehler mittels eines Exception Mappers abhandeln (ohne diesen würde die Fehler mit einem Statu-Code 500 zurückgewiesen werden):

package de.gedoplan.jaxgui.system.security;

import javax.ejb.EJBAccessException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
public class AccessExceptionHandler implements ExceptionMapper<EJBAccessException> {

    @Override
    public Response toResponse(EJBAccessException exception) {
        return Response.status(455).type("text/html").build();
    }
}

Ergebnis:

basicauth_455

Zugegeben, das Verhindern des Login-Popups ist komplizierter als gedacht. Dennoch bietet auch der Java Standard für diesen Fall entsprechende Mechanismen um in die Verarbeitung ein zu greifen. Der umgeschriebene Fehlercode wird in diesem Beispiel als “normale” Fehlerresponse an die Anwendung weiter gegeben sodass individuell darauf regiert werden kann.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Bitte füllen Sie dieses Feld aus.
Bitte füllen Sie dieses Feld aus.
Bitte gib eine gültige E-Mail-Adresse ein.
Sie müssen den Bedingungen zustimmen, um fortzufahren.

Autor

Diesen Artikel teilen

LinkedIn
Xing

Gibt es noch Fragen?

Fragen beantworten wir sehr gerne! Schreibe uns einfach per Kontaktformular.

Kurse

weitere Blogbeiträge

flasks 606612 640
Web Security, Webprogrammierung

Keycloak + Protractor E2E Test

Keycloak ist eine charmante Authentifizierungs-Lösung die sich dank keycloak-angular relativ Problemlos in der eigenen Anwendung verankern lässt. Im Arbeitsalltag stolpert…
IT-Training - GEDOPLAN
Java SE

Microbenchmarking mit JMH

Microbenchmarking in Java ist kein einfaches Thema. Dies liegt zum einen an den vielen Optimierungen, die der Compiler vornimmt und…

Work Life Balance. Jobs bei Gedoplan

We are looking for you!

Lust bei GEDOPLAN mitzuarbeiten? Wir suchen immer Verstärkung – egal ob Entwickler, Dozent, Trainerberater oder für unser IT-Marketing! Schau doch einfach mal auf unsere Jobseiten! Wir freuen uns auf Dich!

Work Life Balance. Jobs bei Gedoplan

We are looking for you!

Lust bei GEDOPLAN mitzuarbeiten? Wir suchen immer Verstärkung – egal ob Entwickler, Dozent, Trainerberater oder für unser IT-Marketing! Schau doch einfach mal auf unsere Jobseiten! Wir freuen uns auf Dich!