Blog

OpenID Connect: Sie verhöhnen

Kristof Riebbels

Kristof Riebbels

Aktualisiert Oktober 15, 2025
16 Minuten

OIDC (OpenID Connect) ist ein Protokoll, das es Unternehmen ermöglicht, die Benutzererfahrung zu optimieren, indem sie Konten an einem Ort zentralisieren. Dies ermöglicht eine bessere Sicherheit und einen besseren Schutz der Privatsphäre. Google, Facebook, Microsoft, Auth0... bieten OIDC-Provider an. Es macht das Leben der Benutzer einfacher, da sie nur einen Benutzernamen und ein Passwort benötigen, die sicher gespeichert werden und somit weniger anfällig für Datenlecks sind. Dies trägt zu einem sichereren Internet bei. Diese Identitätsanbieter fügen weitere Funktionen hinzu, um sicherzustellen, dass es sich bei der Anmeldung eines Benutzers wirklich um den Benutzer handelt, für den er sich ausgibt.

Die Implementierung von OpenID Connect vereinfacht die Anmeldevorgänge auf verschiedenen Websites und in verschiedenen Anwendungen mit einem einzigen Satz von Anmeldeinformationen. Dies verringert die Wahrscheinlichkeit von vergessenen oder unsicheren Passwörtern und beschleunigt die Anmeldung bei neuen Diensten.

Die Nutzung eines OpenID Connect-Anbieters bedeutet, dass Sie ihm wichtige persönliche Informationen anvertrauen: E-Mail-Adressen, Passwörter und andere sensible Daten. Für diese Anbieter ist die Sicherheit Ihrer Daten einer der Eckpfeiler ihrer betrieblichen Verantwortung. Ihre Ressourcen und Strategien sollten darauf ausgerichtet sein, Ihre Daten vor unbefugtem Zugriff oder Verstößen zu schützen. Der Schwerpunkt von Online-Shops und verschiedenen anderen Websites ist grundlegend anders. Sie ergreifen zwar Maßnahmen zum Schutz der Benutzerdaten, aber ihre wichtigsten Geschäftsziele sind auf den Handel und nicht auf den Datenschutz ausgerichtet. Ihre Systeme sind anfälliger für Bedrohungen der Cybersicherheit.

In dem Artikel Let Us Playwright with .NET 6 MVC stellte Mike Playwright vor, ein Framework, das integrierte UI-Tests in CI-Pipelines ermöglicht. Allerdings stieß Mike auf Probleme mit fehlerhaften Builds. Sitzungen und Cookies mit Authentifizierungsinformationen neigen dazu, abzulaufen. Das erfordert die Erneuerung der Sitzung oder die Anmeldung des Benutzers. Die Standardlösung von Playwright zur Erfassung des Kontexts des authentifizierten Benutzers ist nicht ideal, da sie eine erneute Authentifizierung und die erneute Erfassung des Kontexts erfordert. Das macht sie für automatische CI-Pipelines ungeeignet.

In diesem Artikel erfahren Sie, wie Mike diese Probleme gelöst hat, indem er die in Mocking your OpenID Connect Provider und Let Us Playwright with .NET 6 MVC genannten Technologien integriert hat. Ziel ist es, zu sehen, wie sich Mikes Webanwendung verhält, wenn z.B. abgelaufene Token zurückgegeben werden oder Claims, die wichtige Daten über den Benutzer enthalten, wie der id_token, einen Claim mit dem Namen prefered_language haben können. Die Anwendung wird diesen Sprachwert verwenden, um die Webseiten in dieser Sprache auszuliefern. id_token hat einen Rollen-Claim mit dem Wert admin. Wenn ein Administrator angemeldet ist, sollten einige spezielle Einstellungen sichtbar sein. Das Lustige daran ist, dass dies alles von unserem Entwicklungsrechner aus möglich ist. Beim Entwickeln und Testen von Anwendungen beschleunigt es die Entwicklung, wenn Sie nur die Daten von Diensten Dritter erfassen und verwenden. Das bedeutet auch, dass die Fehlerbehebung einfacher wird: Sie können die Daten beeinflussen, um den von einem Endbenutzer gemeldeten Fehler zu provozieren. Das Schöne daran ist, dass die Middleware nicht nachgebildet wird. Das Testen und die Fehlersuche erfolgen so realitätsnah wie möglich.

Die Idee hinter dem Mocking Ihres OpenID-Anbieters ist es, die Notwendigkeit von Konfigurationsänderungen zu Testzwecken zu minimieren. Dies ist besonders nützlich, wenn Sie eine Webanwendung entwickeln, die Bibliotheken von Drittanbietern verwendet. Wenn Sie diese Bibliotheken aktualisieren oder ändern, können die Tests fehlschlagen, wenn ein anderes Verhalten bekannt wird.

Der frühere Artikel Mock your OpenID Connect Provider konzentriert sich auf die beiden Aufrufe, die an den Provider gerichtet sind:

  • Abrufen der bekannten OpenID-Konfiguration
  • Erstellen eines selbstsignierten Zertifikats, das Folgendes offenlegt
  • den privaten Schlüssel für die Erstellung eines gültigen JWT gegenüber
  • den öffentlichen Schlüssel für die Validierung des JWT unter Verwendung des OIDC JWKS Endpunkts

In diesem Artikel geht es jedoch um die Erstellung einer access_token. Diese access_token ist das Ergebnis des Client Credentials Flow, der bei der Kommunikation von Maschine zu Maschine verwendet wird.

Das Repository, das den Code für diesen Artikel enthält, finden Sie auf meiner GitHub-Seite: https://github.com/kriebb/MockOpenIdConnectIdpAspnetcore

In diesem Artikel werden OIDC-Endpunkte verwendet, um mehr als nur den Teil für die Validierung der Token zu mockieren. Lassen Sie uns in den Codefluss der Autorisierung eintauchen. Der Ablauf wird verwendet, um sich sicher bei Webanwendungen anzumelden und die Zustimmung zu den Daten zu erteilen, die die Webanwendung vom OIDC-Provider anfordern darf.

OIDC-Ströme

Das OpenID Connect-Protokoll unterstützt verschiedene Authentifizierungsabläufe, die jeweils für bestimmte Zwecke konzipiert sind. Diese Abläufe enden damit, dass der OpenID Connect Provider eine access_token und je nach Ablauf eine id_token ausstellt. In einer Front-End-Anwendung wird die id_token für ihre Ansprüche verwendet, während die access_token für den Zugriff auf geschützte Ressourcen verwendet wird, die die Webanwendung benötigt. Ein access_token wird im Format eines JWT (JSON Web Token) bereitgestellt. Bitte beachten Sie, dass das access_token gemäß den Oauth2-Spezifikationen nicht dekodiert werden sollte und als nicht lesbares Token behandelt wird. In der Branche ist es jedoch üblich, dass ein Zugriffstoken im Format eines JWT vorliegt.

Autorisierungscodefluss [mit PKCE (Proof Key for Code Exchange)]

Der Authorization Code Flow ist ein gut etablierter und empfohlener Flow für Webanwendungen, die eine Authentifizierung mit einem OIDC-Anbieter durchführen. Jetzt wurde PKCE (Proof Key for Code Exchange) hinzugefügt, um die Sicherheit dieses Ablaufs zu erhöhen. PKCE fügt eine zusätzliche Sicherheitsebene hinzu, um bestimmte Arten von Angriffen zu verhindern, wie z.B. das Abfangen von Autorisierungscodes. Die Verwendung von PKCE gilt als Best Practice, insbesondere für Clients, die ein Client-Geheimnis nicht sicher speichern können, wie z. B. öffentliche Clients, Single-Page-Anwendungen (SPAs) und mobile Anwendungen. PKCE ersetzt ein client_secret in Umgebungen, in denen es nicht sicher gespeichert werden kann, und sorgt dafür, dass der Datenfluss auch für öffentliche Clients sicher bleibt.

Mike spricht mit einem anderen Entwickler über den Ablauf, und sie kommen zu folgender Analogie:

Stellen Sie sich vor, dass Mike beschließt, eine Konzertkarte online zu kaufen. Er verwendet sein Google Pay, um das Ticket zu kaufen. Google verbirgt Ihre echten Zahlungsdaten und gibt nur einen Alias an. Dieser Alias kann nur einmal verwendet werden. Google zeigt die folgende Meldung an, nachdem die Zahlung erfolgreich war:

A virtual Visa account ending in XXXX was used instead of your actual card number.

Der Konzertveranstalter schickt Mike ein Ticket in Form eines QR-Codes. Dieses Ticket funktioniert wie ein Autorisierungscode. Es steht für ein Versprechen auf Einlass, aber nicht für die endgültige Zugangskarte selbst. Mike kommt am Konzertort an. Mike zeigt sein Ticket am Eingang vor und der QR-Code (der "Autorisierungscode") wird gescannt. Der Scanner leuchtet grün, was bedeutet, dass der Autorisierungscode für gültig erklärt wurde. Um sicher zu sein, dass Mike derjenige ist, der das Ticket gekauft hat, wird er aufgefordert, einen Zahlungsnachweis vorzulegen. Mike zeigt seine Google-Zahlungskartennummer vor. Dieser Vorgang wird als Proof Key for Code Exchange (PKCE) bezeichnet. Er bestätigt, dass die Person, die das Ticket gekauft hat, auch diejenige ist, die an der Veranstaltung teilnimmt, und stellt sicher, dass das Ticket nicht abgefangen oder verhökert wurde. Sobald Ihr Ticket und Ihre Zahlung verifiziert sind, erhält Mike ein spezielles Armband. In dieser Analogie steht das Armband für einen Token, der Mike Zutritt zum Konzert gewährt.

Mike erstellt das folgende Sequenzdiagramm, um den Ablauf besser zu verstehen:

Der Authorization Code Flow, insbesondere mit PKCE (Proof Key for Code Exchange), wurde entwickelt, um den Austauschprozess weiter abzusichern und sicherzustellen, dass der Flow nicht gekapert oder wiedergegeben werden kann. Dieser Fluss dient der Benutzerauthentifizierung. Das bedeutet, dass die Webanwendung den Benutzer an den OpenID-Anbieter weiterleitet, um einen authorization_code anzufordern. Sobald sich der Benutzer anmeldet, kann der Autorisierungscode verwendet werden, um die und abzurufen. Der Autorisierungscodefluss mit PKCE gewährleistet sichere Transaktionen, indem er die code_challenge und code_verifier abgleicht. Nur der authentische Client, der die Autorisierungsanfrage initiiert hat, kann den Autorisierungscode gegen ein Zugriffstoken austauschen. Dadurch wird das Risiko eines unbefugten Zugriffs in öffentlichen und weniger sicheren Client-Anwendungen verringert.

Mike folgt den OpenID-Spezifikationen, um die selbst erstellten access_token und id_token abzurufen, was das Verhalten seiner Webanwendung beeinflusst. Mike muss diese Token erstellen. Er liest den obigen Ablauf erneut durch und nimmt Anpassungen vor; er ordnet das Wort user mit dem Playwright UI automation, die web application als unser in-memory web application und die OIDC Server wird ein MockedHttpMessageHandler, injiziert in den OpenIdConfigurationManager.

Playwright kann zwar den Netzwerkverkehr zu Testzwecken nachahmen und verändern, aber seine Fähigkeiten konzentrieren sich auf die Interaktion mit dem Browser. Für das API-Mocking ohne den Browser-Kontext gibt es verschiedene Tools, die für das API-Mocking entwickelt wurden. Der Einfachheit halber wird Mike das im Artikel Mocking your OpenID Connect Provider definierte HttpMessageHandler wiederverwenden, um die Antworten des OIDC-Servers zu simulieren.

Spottdiagramm

Mike kümmert sich nicht um die im ersten Diagramm erwähnten code_challenge und code_verifier. Dies ist wichtig, wenn Sie einen OIDC-Server schreiben; Mike hat jedoch nicht die Absicht, die OIDC-Bibliotheken zu bewerten. Um die Anwendung zu beeinflussen, ist Mike an den access_token, id_token und refresh_token interessiert. Diese Token müssen mit einem Zertifikat signiert werden, das später zur Bestätigung der Signatur verwendet werden kann. Bei id_token sollte nonce in der Autorisierungsanfrage angegeben werden, um sich vor einem Replay-Angriff zu schützen. Ein Replay-Angriff besteht darin, dass ein Token erneut ausgestellt werden kann und sich der Benutzer als solcher ausgeben kann.

Mike liest sich die Let Us Playwright with .NET 6 MVC zusammen mit dem Artikel über Mocking your OpenID Connect Provider durch. Er hat die Quellen heruntergeladen, um herumzuspielen und Haltepunkte zu setzen. Er fügte eine einfache Webanwendung namens Weather API hinzu. Die Webanwendung zeigt den Namen des eingeloggten Benutzers an. Sie wird die Middleware sein, die den Benutzer automatisch zur Anmeldeseite des OpenID Providers weiterleitet. Der Benutzer meldet sich an und sieht eine Willkommensnachricht, in der sein Name genannt wird. Die Einrichtung, um die Konfiguration mit Hilfe von WebApplicationFactory außer Kraft zu setzen, ist die gleiche wie in den Artikeln Mocking your OpenID Connect Provider und Let Us Playwright with .NET 6 MVC beschrieben.

Mike schreibt einen Test, um das Verhalten der Webanwendung zu überprüfen. Der Test soll zur Startseite navigieren und den Begrüßungstext überprüfen. Die Ausführung des Tests ist erfolgreich, wenn der Begrüßungstext angezeigt wird, und schlägt fehl, wenn der Begrüßungstext nicht angezeigt wird.

[Test]
public async Task WhenWeNavigateToTheHomePage_AWelcomeTextWithTheUserNameIsDisplayed ()
{
_fixture.SetAccessTokenParameter((AuthorizationCodeRequestQuery, TokenRequestQuery, IdTokenParameters ) => new AccessTokenParameters());
_fixture.SetIdTokenParameter((AuthorizationCodeRequestQuery, TokenRequestQuery, IdTokenParameters ) =>
new IdTokenParameters(
sub: "Mike",
nonce: AuthorizationCodeRequestQuery["nonce"]!,
scope: AuthorizationCodeRequestQuery["scope"]!)
);

Page.SetDefaultTimeout(30000);
Page.SetDefaultNavigationTimeout(30000);

await Page.GotoAsync($"{SetUpConfig.UiWebApplicationFactory.ServerAddress}weatherappui");

await Expect(Page.GetByText( "Welcome Mike")).ToBeInViewportAsync();
}

Indem er sich auf die Anfragen und Antworten des OIDC-Providers konzentriert, erweitert Mike den MockingOpenIdProviderMessageHandler. Dieser Handler wird in den OpenIdConfigurationManager injiziert. Im Codeausschnitt unten zeigen die dreifachen Punkte (...) die Entfernung von Code, der für die Lösung benötigt wird. Für diesen Artikel wird es jedoch weniger verständlich sein, dies noch einmal zu erwähnen. Der vollständige Code ist im Artikel Mock your OpenID Connect provider oder auf GitHub zu finden. Im Folgenden finden Sie neuen Code, der der Klasse MockingOpenIdProviderMessageHandler hinzugefügt wurde. Mike fügt eine Funktion ein, die die benötigten Token erzeugt: id_token, access_token und refresh_token. Die Funktion (Func) wird aufgerufen, wenn der Token-Endpunkt des OIDC Providers aufgerufen wird. Die Erstellung der Token basiert auf den Abfragezeichenfolgen, die in den Anfragen an den Autorisierungs-Endpunkt und den Token-Endpunkt angegeben werden. Die Token sollten mit dem privaten Schlüssel des generierten selbstsignierten Zertifikats signiert werden. Ein Bereich steht für einen oder mehrere Ansprüche. Die Ansprüche in den Token sind diejenigen, die unter Verwendung des in der Anfrage an den Autorisierungsendpunkt genannten Bereichs angefordert werden. Die Antwortnachricht enthält die Token.

public sealed class MockingOpenIdProviderMessageHandler : HttpMessageHandler
{
//...
private readonly OpenIdConnectDiscoveryDocumentConfiguration _openIdConnectDiscoveryDocumentConfiguration;

private readonly ConcurrentDictionary<string?, NameValueCollection> _requests = new ();
private readonly Func<(NameValueCollection AuthorizationCodeRequestQuery, NameValueCollection TokenRequestQuery), (string AccessToken, string IDToken, string RefreshToken)> _tokenFactoryFunc;

public MockingOpenIdProviderMessageHandler(
//...
Func<(NameValueCollection AuthorizationCodeRequestQuery, NameValueCollection TokenRequestQuery), (string AccessToken, string IDToken, string RefreshToken)> tokenFactoryFunc)
{
...
_tokenFactoryFunc = tokenFactoryFunc;
})

protected override async Task<httpresponsemessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
//... See earlier article ...</httpresponsemessage>

if (request.RequestUri.AbsoluteUri.Contains(_openIdConnectDiscoveryDocumentConfiguration.AuthorizationEndpoint))
return await GetAuthorizationResponseMessage(request);

if (request.RequestUri.AbsoluteUri.Contains(_openIdConnectDiscoveryDocumentConfiguration.TokenEndpoint))
return await GetTokenResponseMessage(request);
//...
}

Der erste Schritt im Ablauf des Autorisierungscodes mit PKCE besteht darin, dass der Autorisierungsendpunkt eine state empfängt und dem Anrufer mit einer Umleitungsanfrage antwortet, in der eine authorization_code und dieselbe state erwähnt werden. Während des gesamten Ablaufs wird derselbe state verwendet. Mit diesem Autorisierungscode und Status erstellt die Anwendung eine neue Anfrage an den Token-Endpunkt, um den Autorisierungscode gegen die dringend benötigten Token auszutauschen.Im folgenden Code extrahiert Mike für die Umleitung zurück zur Anwendung den mit dem und fügt einen festen hinzu. Die state wird später verwendet, um die in der Autorisierungsanfrage angegebenen Abfrageparameter abzurufen.

private async Task<httpresponsemessage> GetAuthorizationResponseMessage(HttpRequestMessage request)
{
var queryString = HttpUtility.ParseQueryString(request.RequestUri?.Query);
var redirectUri = queryString["redirect_uri"];
var code = Consts.AuthorizationCode; //better is to generate a unique number.
string locationHeader = Uri.UnescapeDataString(redirectUri);
locationHeader += $"?code={code}&state={state}";
if(!_requests.Contains(code)) //we are not intrested in the entire flow called each time. just the tokens.
_requests.Add(code, queryString);</httpresponsemessage>

var message = new HttpResponseMessage(HttpStatusCode.Redirect);
message.Headers.Location =new Uri(locationHeader);
return message;
}

Der Token-Endpunkt muss ein access_token, id_token und ein refresh_token zurückgeben. Die Methode TokenFactoryFunc erstellt die Token auf der Grundlage des Abfrage-Strings, der in der Anfrage an den Autorisierungs-Endpunkt und den Token-Endpunkt angegeben wurde.

private async Task<httpresponsemessage> GetTokenResponseMessage(HttpRequestMessage request)
{
var queryString = HttpUtility.ParseQueryString(request.RequestUri?.Query);
var code = queryString["code"];
var authorizationCodeQueryString = _requests[code]; //exception when not available. authorize should be called first.
var state = authorizationCodeQueryString["state"]!; //XSS protection</httpresponsemessage>

var generatedTokens = _tokenFuncFactory(new(authorizationCodeQueryString!,queryString!));

var message = new HttpResponseMessage(HttpStatusCode.OK);
message.Headers.CacheControl = new CacheControlHeaderValue { NoStore = true};

var tokenMessage = new
{
access_token = generatedTokens.AccessToken,
token_type = "Bearer",
expires_in = 3600, //tests can play with these values as well to see what happens in the app
refresh_token = generatedTokens.RefreshToken,
id_token = generatedTokens.IDToken,
state = state
};
message.Content = JsonContent.Create(tokenMessage, mediaType: MediaTypeHeaderValue.Parse("application/json"));

return message;
}

Die nachfolgende Methode verwendet die im Artikel Mock your OpenID Connect provider definierte Klasse JwtBearerAccessTokenFactory wieder. Die Methode Create akzeptiert nicht nur die Klasse AccessTokenParameters, sondern auch die Klasse IdTokenParameters. Die für die Erstellung der Token benötigten Daten sollten in dem unten stehenden Test oder in der Testvorrichtung bereitgestellt werden. Die Methode CreateRefreshToken erstellt ein Aktualisierungs-Token. Die Methode TokenFactoryFunc gibt die Token zurück.

public (string AccessToken, string IDToken, string RefreshToken) TokenFactoryFunc(
(NameValueCollection AuthorizationCodeRequestQuery, NameValueCollection TokenRequestQuery) arg)
{
var accessToken = JwtBearerAccessTokenFactory.Create(AccessTokenParameter(arg.AuthorizationCodeRequestQuery, arg.TokenRequestQuery));
var idToken = JwtBearerAccessTokenFactory.Create(IdTokenParameter(arg.AuthorizationCodeRequestQuery, arg.TokenRequestQuery));
var refreshToken = JwtBearerAccessTokenFactory.CreateRefreshToken();
return (accessToken, idToken, refreshToken);
}

Um ein id_token zu erstellen, werden sub, nonce und scope im Konstruktor der Klasse IdTokenParameters übergeben. sub ist die Abkürzung für subject. Es steht dafür, für was oder wen das Token bestimmt ist. Im Falle des Autorisierungscodeflusses mit PKCE ist der Sub beispielsweise die Kennung des Benutzers. Das Sub eines Tokens, das mit dem Credential-Flow erstellt wurde, steht für die Client-ID. Die nonce (Zahl wird nur einmal verwendet) ist eine zufällige Zeichenfolge, die zum Schutz vor Wiederholungsangriffen verwendet wird. Durch Hinzufügen der nonce zur id_token kann die id_token mit der ursprünglichen Anfrage an den Autorisierungsendpunkt verknüpft werden. Die scope ist der in der Autorisierungsanfrage angeforderte Bereich, der für die benötigten Daten im eigentlichen ID-Token steht.

public record IdTokenParameters: TokenParameters
{
public IdTokenParameters(string sub, string nonce, string scope)
{
Audience = Consts.ValidAudience;
Issuer = Consts.ValidIssuer;
SigningCertificate = Consts.ValidSigningCertificate.ToX509Certificate2();
Claims = new List<claim>
{
new(Consts.SubClaimType, sub),
new(Consts.ScopeClaimType, scope),
new(Consts.CountryClaimType, Consts.CountryClaimValidValue),
new("auth_time", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString()),
new("nonce", nonce)
};
//...

Alle Bausteine sind nun vorhanden! Mike kann seinen Test durchführen und sehen, ob sich die Webanwendung wie erwartet verhält. Das ist nicht der Fall. Der Test schlägt fehl. Der Browser leitet auf die URL https://i.do.not.exist/authorize?client_id=69313df8..&redirect_uri=https%3A%2F%2Flocalhost%3A56407%2Fsignin-oidc&response_type=code&prompt=select_account&scope=openid...&code_challenge=hWoEjZ4unyaDNrT...&code_challenge_method=S256&nonce=6384990...NDlmNDJhNGIt...&state=CfDJ8...&x-client-SKU=ID_NET8_0&x-client-ver=7.1.2.0 um. Nachdem er nachgeforscht und sich das erste Sequenzdiagramm angesehen hat, bemerkt er die Pfeilnummer 3. Die Webanwendung fordert den Browser auf, zu OIDC Server zu navigieren.

Der Autorisierungscode wird über den Browser abgerufen. Die Klasse MockingOpenIdProviderMessageHandler wird von ConfigurationManager verwendet, um Konfigurationsanfragen abzufangen. Es ist der Browser, der eine Umleitungsuri von der Webanwendung erhält. Mike erstellt eine neue Methode GetAuthorizationLocationHeaderFromFullUri, die auf GetAuthorizationResponseMessage basiert. Die Methode GetAuthorizationLocationHeaderFromFullUri gibt eine URL zurück, zu der der Browser navigieren wird. Diese URL enthält einen Autorisierungscode und einen Status, wodurch die Ausführung der Autorisierungsanfrage übersprungen wird. In diesem Fall ist der Autorisierungscode 12345678 und der Status wird von der Autorisierungsanfrage wiederverwendet: https://localhost:56567/signin-oidc?code=123456789&state=CfDJ8Hy8.... Durch die Konfiguration des Ereignisses OnRedirectToIdentityProvider mit der Methode PostConfigure in der Klasse PlaywrightCompatibleWebApplicationFactory kann Mike sicherstellen, dass der Browser nicht zu https://i.do.not.exist umleitet."

protected override IHost CreateHost(IHostBuilder builder)
{
builder.ConfigureServices(services =>
{
//...
services.PostConfigure<openidconnectoptions>(OpenIdConnectDefaults.AuthenticationScheme,
options =>
{
MockingOpenIdProviderMessageHandler backChannelMessageHandler = ConfigForMockedOpenIdConnectServer.CreateHttpHandler(Constants.ValidIssuer, TokenFactoryFunc, UserInfoResponseFunc);
options.ConfigurationManager = ConfigForMockedOpenIdConnectServer.Create(backChannelMessageHandler);</openidconnectoptions>

options.Events = new OpenIdConnectEvents()
{
//...
OnRedirectToIdentityProvider = context =>
{
//code that happens in the OpenIdConnectHanlder of asp.net core, but not exeucte due to context.HandleResponse()
context.Properties.Items.Add(OpenIdConnectDefaults.RedirectUriForCodePropertiesKey, context.ProtocolMessage?.RedirectUri);
context.ProtocolMessage!.State = context.Options.StateDataFormat.Protect(context.Properties);

var authorizationRequestUri = context.ProtocolMessage?.BuildRedirectUrl()!;
//Use the backChannelMessageHandler to generate the URL and ensure that it can be linked to the tokenrequest by using the same instance
var mockedAuthorizationCode = backChannelMessageHandler.GetAuthorizationLocationHeaderFromFullUri(authorizationRequestUri);

logger?.LogInformation("Override Browser Redirect! Redirected to authorization endpoint:" + mockedAuthorizationCode);

context.HandleResponse();
context.Response.Redirect(mockedAuthorizationCode);

return Task.CompletedTask;
},
//...
}
}
}
//...
}

Der anschließende Test schlägt leider fehl, wenn Sie versuchen, den Autorisierungscode einzulösen. Mike untersucht dies, indem er sich das erste Sequenzdiagramm noch einmal ansieht, insbesondere den Pfeil Nummer 6, der veranschaulicht, dass die Webanwendung den Autorisierungscode über einen backchannel gegen Token austauschen sollte. Ein Rückkanal ist ein spezieller HttpClient, der für die sichere, interne Kommunikation zwischen der Webanwendung und dem OIDC-Server entwickelt wurde.


protected override IHost CreateHost(IHostBuilder builder)
{
builder.ConfigureServices(services =>
{
//...
services.PostConfigure< OpenIdConnectOptions >(OpenIdConnectDefaults.AuthenticationScheme,
options =>
{
MockingOpenIdProviderMessageHandler backChannelMessageHandler = ConfigForMockedOpenIdConnectServer.CreateHttpHandler(Constants.ValidIssuer, TokenFactoryFunc, UserInfoResponseFunc); //generic handler
options.ConfigurationManager = ConfigForMockedOpenIdConnectServer.Create(backChannelMessageHandler); //jwks_uri and .wellknown
options.Backchannel = ConfigForMockedOpenIdConnectServer.CreateHttpClient(backChannelMessageHandler); //fetch the tokens, userinfo,...

Mike kann diesen Rückkanal so konfigurieren, dass er auch die Erfassung von Benutzerinformationen vom userinfo-Endpunkt abfängt. Auf diese Weise kann er auch andere Kommunikationen über den Rückkanal überwachen und abfangen.

Mike führt den Test erneut aus und dieses Mal ist er erfolgreich. Der Benutzername wird korrekt angezeigt, was den ordnungsgemäßen Ablauf der Anwendungsauthentifizierungsprozesse bestätigt.

Einpacken

Auf seiner Reise lernte Mike Mocking-Strategien sehr zu schätzen und stellte fest, wie solche Ansätze die Entwicklungszyklen in seinen Projekten dramatisch beschleunigen. Seine neu gewonnene Sicherheit bei der Arbeit mit externen Abhängigkeiten war eine bedeutende Veränderung.

Die Konzentration dieses Artikels auf den Autorisierungscodefluss mit PKCE hat einen systematischen Verteidigungsmechanismus gegen das Abfangen von Autorisierungscodes beleuchtet und die Bedeutung der Sicherheit bei Authentifizierungsprozessen hervorgehoben.

Durch die Weitergabe seiner Erfahrungen möchte Mike anderen Entwicklern ein tieferes Verständnis der OIDC-Abläufe vermitteln und sie in die Lage versetzen, den komplexen Bereich der Authentifizierung mit größerer Leichtigkeit und Zuversicht zu bewältigen.

Quellen

 

Dieser Artikel ist Teil von XPRT.#16. Laden Sie das Magazin hier herunter.

XMS XPRT16

Verfasst von

Kristof Riebbels

Kristof is a dynamic Software Developer, Coach, and DevOps enthusiast who loves travelling, coding, and sci-fi. He's passionate about staying physically active and thrives on positive team dynamics, where collaboration results in "1+1=3." His key talent lies in effectively transmitting knowledge to ensure it resonates with his audience. Kristoff finds joy in every "aha" moment and starts his days with epic modern orchestral music, while dance and trance music keep him focused during work.

Contact

Let’s discuss how we can support your journey.