Class SamlLogoutRequestValidator
- Namespace
- Fdyay.IdentityServer.Saml.Idp
- Assembly
- Fdyay.IdentityServer.Saml.dll
What a LogoutRequest must be before the single logout endpoint acts on it. Duende 8.0.1's LogoutRequestValidator, its
steps measured and run in its order; until 0.153.0 these checks were the endpoint's own.
public class SamlLogoutRequestValidator : ILogoutRequestValidator
- Inheritance
-
SamlLogoutRequestValidator
- Implements
- Inherited Members
Remarks
ValidateAsync(ValidatedLogoutRequest, CancellationToken) runs the steps and is not virtual, as Duende's is not. Two rules are kept there, out of an override's reach. A request whose signature does not verify against its provider is not checked further and never ends a session by itself — the endpoint hands it to the logout page for the user to confirm, as it always has, where Duende refuses it — whatever ValidateSignatureTrust(ValidatedLogoutRequest) answers. And a request passes only with a provider found.
Duende checks no IssueInstant age on a LogoutRequest, and neither does this; nor, by default, whether its NameID is
this browser's — MatchLogoutRequestToSession turns Duende's session checks on (see
ValidateSessionAsync(ValidatedLogoutRequest, CancellationToken)).
Constructors
SamlLogoutRequestValidator(ISamlServiceProviderStore, IOptions<SamlOptions>?, TimeProvider?, IServerUrls?)
public SamlLogoutRequestValidator(ISamlServiceProviderStore serviceProviders, IOptions<SamlOptions>? options = null, TimeProvider? time = null, IServerUrls? urls = null)
Parameters
serviceProvidersISamlServiceProviderStoreThe registry the request's issuer is looked up in.
optionsIOptions<SamlOptions>The SAML options; the defaults when null.
timeTimeProviderThe clock
NotOnOrAfteris read against; the system's when null.urlsIServerUrlsWhere this server is, which a request's
Destinationmust name; not checked when null.
SamlLogoutRequestValidator(ISamlServiceProviderStore, IOptions<SamlOptions>?, TimeProvider?, IServerUrls?, IUserSession, ILogger<SamlLogoutRequestValidator>?)
The validator with the browser's session, which ValidateSessionAsync(ValidatedLogoutRequest, CancellationToken) matches a request against when
MatchLogoutRequestToSession asks it to. The one AddSaml registers, since 0.159.0.
public SamlLogoutRequestValidator(ISamlServiceProviderStore serviceProviders, IOptions<SamlOptions>? options, TimeProvider? time, IServerUrls? urls, IUserSession userSession, ILogger<SamlLogoutRequestValidator>? logger = null)
Parameters
serviceProvidersISamlServiceProviderStoreThe registry the request's issuer is looked up in.
optionsIOptions<SamlOptions>The SAML options; the defaults when null.
timeTimeProviderThe clock
NotOnOrAfteris read against; the system's when null.urlsIServerUrlsWhere this server is, which a request's
Destinationmust name; not checked when null.userSessionIUserSessionThe SAML sessions this browser holds.
loggerILogger<SamlLogoutRequestValidator>Where a request that matches no session is recorded, as Duende records it; nowhere when null.
Methods
ValidateAsync(ValidatedLogoutRequest, CancellationToken)
Validates request, finding its service provider.
public Task<SamlLogoutRequestValidationResult> ValidateAsync(ValidatedLogoutRequest request, CancellationToken ct)
Parameters
requestValidatedLogoutRequestctCancellationToken
Returns
ValidateDestination(ValidatedLogoutRequest)
Refuses a request addressed to another server. Duende's, measured.
protected virtual SamlLogoutRequestValidationResult ValidateDestination(ValidatedLogoutRequest request)
Parameters
requestValidatedLogoutRequest
Returns
Remarks
Its Destination must be this server's single logout URL, compared ignoring case; a signed request must name
one. Not checked when the validator was given no IServerUrls to know where it is.
ValidateNotOnOrAfter(ValidatedLogoutRequest)
Refuses a request past its NotOnOrAfter, when it has one, by more than the clock skew. Duende's.
protected virtual SamlLogoutRequestValidationResult ValidateNotOnOrAfter(ValidatedLogoutRequest request)
Parameters
requestValidatedLogoutRequest
Returns
Remarks
ValidateSessionAsync(ValidatedLogoutRequest, CancellationToken)
Whether the session the request names is this browser's. Duende's step, measured; passes by default, and runs Duende's checks when MatchLogoutRequestToSession, else MatchLogoutRequestToSession, says so.
protected virtual Task<SamlLogoutRequestValidationResult> ValidateSessionAsync(ValidatedLogoutRequest request, CancellationToken ct)
Parameters
requestValidatedLogoutRequestctCancellationToken
Returns
Remarks
With the checks on, as Duende 8.0.1 makes them: nobody signed in (Subject) passes.
For a signed-in user, a request with no NameID is refused (name_id_required; Duende's "LogoutRequest must contain
a NameID"); one from a provider this browser holds no SAML session with passes with
SessionFound false, which the endpoint answers Success without ending
the session; one whose NameID matches none of the provider's sessions, compared ordinally, is refused
(name_id_mismatch; Duende's "NameID does not match any active session"); and one whose SessionIndex names
none of the sessions with that NameID passes with SessionFound false. Each is logged with Duende's message.
The switch is read here, in the step, rather than in ValidateAsync(ValidatedLogoutRequest, CancellationToken), so an override of this step replaces Duende's checks whatever the switch says, as an override of Duende's does. Nothing here needs keeping from an override: the step is reached only by a request whose signature verified, and it can only refuse a request or leave a session running, never end one.
Ours: off by default (decided 2026-10-14) — Duende always runs them — because each changes what this server does with a verified request: it ends the session. With the switch on, a validator built without IUserSession throws rather than pass a request it was asked to match.
ValidateSignatureTrust(ValidatedLogoutRequest)
Refuses a request whose signature does not verify against a provider that signs. Duende's.
protected virtual SamlLogoutRequestValidationResult ValidateSignatureTrust(ValidatedLogoutRequest request)
Parameters
requestValidatedLogoutRequest
Returns
Remarks
Ours: a provider with no signing certificate passes, and its request goes to the logout page for the user to confirm; Duende refuses every request without a trusted signature ("The LogoutRequest signature is missing or not trusted").
ValidateSpAsync(ValidatedLogoutRequest, CancellationToken)
Finds the service provider the request's issuer names, as ServiceProvider. Duende's.
protected virtual Task<SamlLogoutRequestValidationResult> ValidateSpAsync(ValidatedLogoutRequest request, CancellationToken ct)
Parameters
requestValidatedLogoutRequestctCancellationToken
Returns
Remarks
Ours: a provider with no single logout endpoint is not refused, as Duende refuses it ("SP does not have any SingleLogoutServiceUrls configured"): its session is ended and the failure to answer it recorded, as before. Nor is Enabled read here — the stores answer a disabled provider as none, as the AuthnRequest validator relies on.
ValidateVersion(ValidatedLogoutRequest)
Refuses a request not written under SAML 2.0. Duende's.
protected virtual SamlLogoutRequestValidationResult ValidateVersion(ValidatedLogoutRequest request)
Parameters
requestValidatedLogoutRequest