info@yenlo.com
deu
Menu
WSO2 Identity Server 14 min

Post Authentication Handlers für den WSO2 Identity Server

Erfahren Sie, wie Sie mit den Post-Authentifizierungs-Handlern von WSO2 Identity Server eine benutzerdefinierte Zustimmungsseite zur Login-Flow hinzufügen können. Perfekt für Szenarien, in denen während der Authentifizierung mehrere Zustimmungsbestätigungen erforderlich sind. Optimieren Sie Ihren Anmeldeprozess und verbessern Sie die Benutzererfahrung mit dieser hilfreichen Anleitung.

Denuwanthi De Silva
Denuwanthi De Silva
Solution Architect
Post Authentication Handlers für den WSO2 Identity Server

So fügen Sie eine zusätzliche Seite für Zustimmungen des Benutzer während des Anmeldevorgangs hinzu

In den meisten täglich genutzten Anwendungen werden Sie während des Anmeldevorgangs aufgefordert, der Weitergabe Ihrer Daten oder den Nutzungsbedingungen einer Endbenutzer-Lizenzvereinbarung zuzustimmen. Diese Art von Aufforderungen zur Zustimmung informieren die Benutzer über die Nutzungsbeschränkungen der Anwendung oder geben an, inwieweit der Softwareanbieter für die Nutzung der Anwendung durch die Benutzer haftet. Vor allem in Anbetracht der jüngsten Datenschutzbestimmungen wie der DSGVO und verschiedener Medienberichte über die Verletzung personenbezogener Daten durch bekannte Softwareanbieter ist es wichtig, die Zustimmung des Benutzers zur Weitergabe von Daten einzuholen. In der Regel wird der Anmeldevorgang abgebrochen, wenn die Benutzer nicht zustimmen.

Die Anwendungen fragen entweder während der Anmeldung des Benutzers, der Registrierung des Benutzers oder bei der Installation der Anwendung nach der Zustimmung. Es gibt keine feste Regel, wann diese zusätzlichen Seiten angezeigt werden müssen. Bei einigen Anwendungen werden die Nutzungsbedingungen nicht auf einer separaten Seite angezeigt, sondern in einem Kontrollkästchen auf der Anmelde- oder Registrierungsseite selbst.

Dieser Blogbeitrag bezieht sich auf Fälle, in denen Sie während des Anmeldevorgangs verschiedene Zustimmungen vom Endbenutzer einholen möchten.

Fallbeispiel: Hinzufügen einer zusätzlichen Genehmigungsseite während des Anmeldevorgangs mit dem WSO2 Identity Server

Sie müssen eine zusätzliche Seite einblenden, um die Zustimmung des Benutzers, die Zustimmung zu den Nutzungsbedingungen oder einen Haftungsausschluss einzuholen, bevor der Benutzer sich bei der Verbraucheranwendung anmelden kann.

Hier wird dieser zusätzliche Schritt als Teil des Anmeldevorgangs ausgeführt. In solchen Fällen muss der Identitätsanbieter, der für die Authentifizierung/Anmeldung bei der Anwendung zuständig ist, diese Aufgabe übernehmen. Wenn die Anwendung keinen Identitätsanbieter für die Anmeldung nutzt, ist es Sache der Anwendungsentwickler, diese zusätzliche Lösung und die Zustimmungsseiten zu pflegen.

Heute sehen wir uns an, wie der WSO2 Identity Server – der als Identitätsanbieter für Anwendungen von Drittanbietern fungiert – Ihnen dabei helfen kann, eine solche zusätzliche Genehmigungsseite ganz einfach in den Anmeldevorgang einzufügen.

Lösung: Verwenden von Handlern nach der Authentifizierung im WSO2 Identity Server zur Handhabung zusätzlicher Genehmigungsseiten während des Anmeldevorgangs

Für solche Fälle stellt der WSO2 Identity Server einen Erweiterungspunkt namens „Post Authentication Handler“ bereit.

Verwechseln Sie dies nicht mit dem „Event Handler“-Erweiterungspunkt des WSO2 Identity Server.

Im Ereignis-Framework des WSO2 Identity Server gibt es Ereignisse, die vor der Authentifizierung und nach der Authentifizierung ausgelöst werden, die jeweils „PRE_AUTHENTICATION“ und „POST_AUTHENTICATION“ genannt werden. Sie können diese Ereignisse abonnieren und Handler schreiben, um benutzerdefinierte Funktionen auszulösen oder auszuführen.

„Post Authentication Handler“ sind allerdings nicht in derselben Kategorie. Sie werden ausgelöst, sobald alle Authentifizierungsschritte abgeschlossen sind.

Using Post Authentication Handlers in WSO2 Identity Server for Handling Additional Approval Pages in Login Flow

Wenn Sie mehrere Authentifizierungsschritte konfigurieren, wie z. B. die Authentifizierung per Benutzername/Passwort + SMS OTP, oder wenn Sie einen föderierten Authentifikator wie die Facebook/Google-Authentifizierung für Ihre Anwendung konfigurieren, werden die Post Authentication Handler erst ausgeführt, wenn alle Authentifizierungsschritte erfolgreich abgeschlossen sind.       

3 Schritte zum Erstellen eines Post Authentication Handlers

Angenommen, Ihre Anwendung nutzt den WSO2 Identity Server für die Benutzerauthentifizierung. Vor kurzem wurde gefordert, eine neue Seite mit den Nutzungsbedingungen hinzuzufügen, um die Zustimmung der Benutzer einzuholen. Es ist zwingend erforderlich, dass Ihre Anwendung für den Zugriff auf Ihre Anwendung die Zustimmung der Benutzer zu den Nutzungsbedingungen einholt, bevor der Anmeldevorgang abgeschlossen werden kann. Im Folgenden finden Sie die wichtigsten Schritte, mit denen Sie diese Anforderung mit Hilfe des WSO2 Identitätsservers erfüllen können.

  1. Erstellen Sie eine jsp-Datei mit der Seite, die die Benutzer sehen und zu der sie ihre Zustimmung geben sollen. Beispiel: terms-and-conditions.jsp. Speichern Sie es im Ordner WSO2-IS/repository/deployment/server/webapps/authenticationendpoint.
  2. Schreiben Sie die Java-Komponente für den Post Authentication Handler (OSGi-Bundle).
    • Erstellen Sie ein Maven-Projekt.
    • Als Hauptabhängigkeit in diesem Projekt müssen Sie „org. wso2.carbon.identity.application. authentication.framework“ verwenden. Fügen Sie die korrekten Versionen des Authentifizierungs-Frameworks hinzu, die zu der von Ihnen verwendeten WSO2 IS-Distribution passen.
    • Erstellen Sie eine neue Java-Klasse, die den „AbstractPostAuthnHandler“ erweitert.
      • Beispiel: öffentliche Klasse TermsAndConditionsPostAuthenticationHandler erweitert AbstractPostAuthnHandler {
    • Überschreiben Sie nun die Methode „handle“ in der neuen Klasse und implementieren Sie die Funktion, um die neue Seite mit den Nutzungsbedingungen aufzurufen und die Anmeldung bei der Anwendung zuzulassen oder abzulehnen, je nachdem, ob der Benutzer zugestimmt hat oder nicht.
@Override
public PostAuthnHandlerFlowStatus handle(HttpServletRequest httpServletRequest,
                                         HttpServletResponse httpServletResponse,
                                         AuthenticationContext authenticationContext)
        throws PostAuthenticationFailedException {
  • Der Rückgabetyp ( PostAuthnHandlerFlowStatus ) dieser Methode ist ein Enum, das aus Werten besteht

SUCCESS_COMPLETED – Gibt an, dass die Aufgaben des Post Authentication Handlers erfolgreich ausgeführt wurden.

INCOMPLETE – Zeigt an, dass die Aufgaben des Post Authentication Handlers noch nicht abgeschlossen sind. Beispiel: Die Seite mit den Nutzungsbedingungen wird dem Benutzer noch nicht angezeigt.

UNSUCCESS_COMPLETED – Zeigt an, dass die Aufgabe des Post Authentication Handlers abgeschlossen wurde, die Ausführung jedoch nicht erfolgreich war. Beispiel: Der authentifizierte Benutzer ist „null“. Überspringen Sie daher die Ausführung des Post Authentication Handlers, indem Sie diesen Wert senden.

  • Innerhalb der „Handle“-Methode muss folgende Funktion implementiert werden.
    • Überprüfen Sie, dass der authentifizierte Benutzer nicht null ist.
    • Überprüfen Sie, ob der Benutzer auf die beabsichtigte Seite weitergeleitet wird. Beispiel: terms-and-conditions.jsp
    • Wenn sich der Benutzer auf der neu hinzugefügten Seite befindet, überprüfen Sie, ob die Genehmigung erteilt wurde oder nicht. Wenn keine Genehmigung erteilt wird, lösen Sie eine Ausnahme aus.
    • Wenn sich der Benutzer immer noch nicht auf der gewünschten Seite befindet, leiten Sie ihn über eine http-Umleitung auf die gewünschte Seite um. Beispiel: httpServletResponse.sendRedirect()
register your handler implementation
  • Registrieren Sie nun die Implementierungsklasse Ihres Handlers als PostAuthenticationHandler-OSGi-Dienst. Beispiel: context.getBundleContext().registerService( PostAuthenticationHandler .class.getName(), TermsAndConditionsPostAuthenticationHandler , null);
  1. Konfigurieren Sie den neuen Handler in der Datei „deployment.toml“.

Bijvoorbeeld:

[[event_listener]]

id = „custom_post_auth_listener“

type = „org.wso2.carbon.identity.core.handler.AbstractIdentityHandler“

name = „org.wso2.carbon.identity.post.authn.handler.custom.

TermsAndConditionsPostAuthenticationHandler

order = 100  

Die Handler werden zuerst mit der niedrigsten Nummer ausgeführt. Hier habe ich 100 eingetragen. Mein Handler wird also ausgeführt, nachdem alle anderen Post Authentication Handler (wie die Standardseite zur Zustimmungsverwaltung) abgeschlossen sind.

Der High-Level-Flow während der Anmeldung sieht wie folgt aus:

high level flow during login

Verwendung von extern gehosteten Seiten: Weiterleitung zu externen Zustimmungs-Seiten von der Implementierung der Post Authentication Handler-Klasse des WSO2 Identity Server

Wie Sie im oben gezeigten Flussdiagramm gesehen haben, leiten wir innerhalb der Implementierung der Handler-Klasse mit Hilfe der sendRedirect Methode auf die gewünschte Seite um.    Anstatt also Ihre Seiten innerhalb der Webapplikation authenticationendpoint zu hosten, können Sie die gewünschten Seiten für Zustimmung/Haftungsausschluss/Nutzungsbedingungen extern hosten und von der Handler-Implementierungsklasse auf die extern oder separat gehostete Seite umleiten.

Zu beachtende Punkte:

  • Stellen Sie sicher, dass Sie den Parameter „sessionDataKey“ als Anfrageparameter bei der Umleitung innerhalb der Implementierungsklasse des Handlers verwenden.

Beispiel: httpServletResponse.sendRedirect(“https://myhost:8080/consent.jsp”+”? sessionDataKey =” + authenticationContext.getContextIdentifier() );

  • Stellen Sie dann sicher, dass Sie denselben seesionDataKey als versteckten Eingabeparameter von Ihrer benutzerdefinierten jsp-Datei zurück an den commonauth-Endpunkt des WSO2 Identity Server übergeben.

Beispiel: <input type=“hidden“ name=“<%=“ sessionDataKey „%>“ value=“<%=Encode.forHtmlAttribute(r equest.getParameter(„sessionDataKey“ )) %>“/>

Dieser Parameter hilft dabei, die Korrelation zwischen verschiedenen Umleitungen innerhalb eines Anfrageflusses aufrechtzuerhalten. Da es sich bei HTTP um ein zustandsloses Protokoll handelt, hilft dieser Parameter dem WSO2 Identity Server dabei, den Status eines bestimmten Anfrageflusses zu verfolgen, der an den WSO2 Identity Server gerichtet ist.

5 Standardimplementierungen von Post Authentication Handlern im WSO2 Identity Server

  1.  ConsentMgtPostAuthnHandler : Verarbeitet Benutzerzustimmungen nach erfolgreicher Authentifizierung. Ruft die Seite für die Benutzerzustimmung auf.
  2. JITProvisioningPostAuthenticationHandler: Erledigt Just-In-Time Provisioning, nachdem ein Benutzer gegenüber einem externen Identitätsanbieter (föderierter IDP) authentifiziert wurde.          Fordert Seiten für Just-In-Time Provisioning an.
  3. PostAuthAssociationHandler: Verantwortlich für die Zuordnung von föderierten Benutzern zu lokalen Benutzerkonten. Bei dieser Implementierung werden keine Seitenumleitungen angefordert. Es werden nur die lokalen Benutzerzuordnungen hinter den Kulissen durchgeführt.           
  4. PostAuthenticatedSubjectIdentifierHandler: Verantwortlich für das Setzen des Subject Identifiers für einen authentifizierten Benutzer.
  5. PostAuthnMissingClaimHandler: Verantwortlich für das Einholen fehlender Pflichtangaben. Ruft eine Seite auf, die den Benutzer auffordert, die Pflichtangaben auszufüllen, sofern diese noch nicht ausgefüllt sind.

Zusammenfassung

Die Verwendung von Post Authentication Handlern im WSO2 Identity Server zum Anfordern zusätzlicher Seiten während des Anmeldeprozesses kann für eine Vielzahl von Anwendungsfällen verwendet werden, z. B. für die Abfrage von Benutzerzustimmungen, Genehmigungen oder Texteingaben.

Post Authentication Handler können auch verwendet werden, um benutzerdefinierte Funktionen während des Anmeldevorgangs auszuführen, ohne dass eine benutzerdefinierte Seitenumleitung erforderlich ist. Es ist wichtig zu beachten, dass diese Handler nur nach Abschluss der Authentifizierungssequenz/-schritte ausgeführt werden.

Die Standardimplementierung des Produkts bietet zusätzliche Funktionen wie JIT-Provisioning und fehlende Claim Handler. Verwenden Sie den folgenden Beispiel-Quellcodeausschnitt, um Ihren eigenen Post Authentication Handler im WSO2 Identity Server zu implementieren. Weitere Beispiele und Informationen finden Sie in unserem Blogpost!

Wenn Sie weitere Beispiele für die Verwendung des WSO2 Identity Server suchen, sollten Sie sich das offizielle GitHub-Repository ansehen. Ausführliche Anleitungen zur Verwendung dieser Beispiele finden Sie auch in diesem hilfreichen Blogbeitrag von Yenlo – Mit den WSO2 Identity Server-Samples arbeiten. Beide Ressourcen bieten Ihnen wertvolle Einblicke und Codeausschnitte, die Ihnen den Einstieg in Ihre Projekte mit dem WSO2 Identity Server erleichtern.

package org.yenlo.carbon.identity.post.authn.handler.termsandconditions;

import org.wso2.carbon.identity.application.authentication.framework.config.ConfigurationFacade;
import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext;
import org.wso2.carbon.identity.application.authentication.framework.exception.PostAuthenticationFailedException;
import org.wso2.carbon.identity.application.authentication.framework.handler.request.AbstractPostAuthnHandler;
import org.wso2.carbon.identity.application.authentication.framework.handler.request.PostAuthnHandlerFlowStatus;
import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser;

import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TermsAndConditionsPostAuthenticationHandler extends AbstractPostAuthnHandler {

    private String CONSENT_POPPED_UP = "consentPoppedUp";

    @Override
    public PostAuthnHandlerFlowStatus handle(HttpServletRequest httpServletRequest,
                                             HttpServletResponse httpServletResponse,
                                             AuthenticationContext authenticationContext)
            throws PostAuthenticationFailedException {

        if (getAuthenticatedUser(authenticationContext) == null) {
            return PostAuthnHandlerFlowStatus.SUCCESS_COMPLETED;
        }

        if (isConsentPoppedUp(authenticationContext)) {
            if (httpServletRequest.getParameter("consent").equalsIgnoreCase("approve")) {
                return PostAuthnHandlerFlowStatus.SUCCESS_COMPLETED;
            } else {
                throw new PostAuthenticationFailedException("Cannot access this application : Consent Denied",
                        "Consent denied");
            }
        } else {
            try {
                httpServletResponse.sendRedirect
                        (ConfigurationFacade.getInstance().getAuthenticationEndpointURL().replace("/login.do", ""
                        ) + "/termsandconditions" + ".jsp?sessionDataKey=" + authenticationContext.getContextIdentifier() +
                                "&application=" + authenticationContext
                                .getSequenceConfig().getApplicationConfig().getApplicationName());
                setConsentPoppedUpState(authenticationContext);
                return PostAuthnHandlerFlowStatus.INCOMPLETE;
            } catch (IOException e) {
                throw new PostAuthenticationFailedException("Invalid Consent", "Error while redirecting", e);
            }
        }
    }

    @Override
    public String getName() {

        return "DisclaimerHandler";
    }

    private AuthenticatedUser getAuthenticatedUser(AuthenticationContext authenticationContext) {

        AuthenticatedUser user = authenticationContext.getSequenceConfig().getAuthenticatedUser();
        return user;
    }

    private void setConsentPoppedUpState(AuthenticationContext authenticationContext) {

        authenticationContext.addParameter(CONSENT_POPPED_UP, true);
    }

    private boolean isConsentPoppedUp(AuthenticationContext authenticationContext) {

        return authenticationContext.getParameter(CONSENT_POPPED_UP) != null;
    }

}

OSGi Service-Komponenten-Klasse:

package org.yenlo.carbon.identity.post.authn.handler.termsandconditions.internal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.wso2.carbon.identity.application.authentication.framework.handler.request.PostAuthenticationHandler;
import org.wso2.carbon.identity.core.util.IdentityCoreInitializedEvent;
import org.yenlo.carbon.identity.post.authn.handler.termsandconditions.TermsAndConditionsPostAuthenticationHandler;

@Component(
        name = "identity.post.authn.termsandconditions.handler",
        immediate = true
)
public class TermsAndConditionsPostAuthnHandlerServiceComponent {

    private static final Log log = LogFactory.getLog(TermsAndConditionsPostAuthnHandlerServiceComponent.class);

    @Activate
    protected void activate(ComponentContext context) {

        try {
            TermsAndConditionsPostAuthenticationHandler termsAndConditionsPostAuthenticationHandler =
                    new TermsAndConditionsPostAuthenticationHandler();
            context.getBundleContext().registerService(PostAuthenticationHandler.class.getName(),
                    termsAndConditionsPostAuthenticationHandler, null);

        } catch (Throwable e) {
            log.error("Error while activating disclaimer post authentication handler.", e);
        }
    }

    protected void unsetIdentityCoreInitializedEventService(IdentityCoreInitializedEvent identityCoreInitializedEvent) {
        /* reference IdentityCoreInitializedEvent service to guarantee that this component will wait until identity core
         is started */
    }

    @Reference(
            name = "identity.core.init.event.service",
            service = IdentityCoreInitializedEvent.class,
            cardinality = ReferenceCardinality.MANDATORY,
            policy = ReferencePolicy.DYNAMIC,
            unbind = "unsetIdentityCoreInitializedEventService"
    )
    protected void setIdentityCoreInitializedEventService(IdentityCoreInitializedEvent identityCoreInitializedEvent) {
        /* reference IdentityCoreInitializedEvent service to guarantee that this component will wait until identity core
         is started */
    }
}

JSP-Datei

<%@ page import="org.owasp.encoder.Encode" %>
<%@ page import="org.wso2.carbon.identity.application.authentication.endpoint.util.Constants" %>

<%
    String app = request.getParameter("application");
    String[] missingClaimList = null;
    String appName = null;
    if (request.getParameter(Constants.MISSING_CLAIMS) != null) {
        missingClaimList = request.getParameter(Constants.MISSING_CLAIMS).split(",");
    }
%>

<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WSO2 Identty Server</title>
    
   <link rel="icon" href="images/favicon.png" type="image/x-icon"/>
    <link href="libs/bootstrap_3.3.5/css/bootstrap.min.css" rel="stylesheet">
    <link href="css/Roboto.css" rel="stylesheet">
    <link href="css/custom-common.css" rel="stylesheet">
    
   <!--[if lt IE 9]>
    <script src="js/html5shiv.min.js"></script>
    <script src="js/respond.min.js"></script>
    <![endif]-->
</head>

<body>

<script type="text/javascript">
    function approved() {
        document.getElementById('consent').value = "approve";
        document.getElementById("profile").submit();
    }
    function deny() {
        document.getElementById('consent').value = "deny";
        document.getElementById("profile").submit();
    }
</script>

<!-- header -->
<header class="header header-default">
    <div class="container-fluid"><br></div>
    <div class="container-fluid">
        <div class="pull-left brand float-remove-xs text-center-xs">
            <a href="#">
                <img src="images/logo-inverse.svg" alt="wso2" title="wso2" class="logo">
                <h1><em> Identity Server </em></h1>
            </a>
        </div>
    </div>
</header>

<!-- page content -->
<div class="container-fluid body-wrapper">
    
   <div class="row">
        <div class="col-md-12">
            
           <!-- content -->
            <div class="container col-xs-10 col-sm-6 col-md-6 col-lg-3 col-centered wr-content wr-login col-centered">
                <div>
                    <h2 class="wr-title uppercase blue-bg padding-double white boarder-bottom-blue margin-none">
                       Terms & Conditions
                    </h2>
                </div>
                
               <div class="boarder-all ">
                    <div class="clearfix"></div>
                    <form action="../commonauth" method="post" id="profile" name=""
                          class="form-horizontal" >
                        <div class="padding-double login-form">
                            <div class="form-group">
                                <p>By using this <strong><%=Encode.forHtml(request.getParameter("application"))%></strong> app, you agree to the terms and conditions outlined below, which are designed to ensure the security and privacy of your personal data and provide a seamless user experience.
                                </p>

                            
                           </div>
                            
                           <table width="100%" class="styledLeft">
                                <tbody>
                                <tr>
                                    <td class="buttonRow" colspan="2">
                                        
                                       <div style="text-align:left;">
                                            <input type="button" class="btn  btn-primary" id="approve" name="approve"
                                                   onclick="javascript: approved(); return false;"
                                                   value="Approve"/>
                                            <input class="btn" type="reset"
                                                   value="Deny"
                                                   onclick="javascript: deny(); return false;"/>
                                        </div>
                                        
                                       <input type="hidden" name="<%="sessionDataKey"%>"
                                               value="<%=Encode.forHtmlAttribute(request.getParameter("sessionDataKey"))%>"/>
                                        <input type="hidden" name="consent" id="consent"
                                               value="deny"/>
                                    </td>
                                </tr>
                                </tbody>
                            </table>
                        </div>
                    </form>
                
               </div>
            </div>
        
       
       </div>
        <!-- /content -->
    
   </div>
</div>
<!-- /content/body -->

</div>

<!-- footer -->
<footer class="footer">
    <div class="container-fluid">
        <p>WSO2 Identity Server | ©
            <script>document.write(new Date().getFullYear());</script>
            <a href="http://wso2.com/" target="_blank"><i class="icon fw fw-wso2"></i>
                Inc
            </a>. All Rights Reserved
        </p>
    </div>
</footer>

<script src="libs/jquery_1.11.3/jquery-1.11.3.js"></script>
<script src="libs/bootstrap_3.3.5/js/bootstrap.min.js"></script>
</body>
</html>
deu
Schließen
Was ist auf unserer Speisekarte