Table of Contents

Class SamlSpOptions

Namespace
Fdyay.IdentityServer.Saml.Sp
Assembly
Fdyay.IdentityServer.Saml.dll

Options for acting as a SAML 2.0 service provider toward an upstream identity provider.

public sealed class SamlSpOptions : RemoteAuthenticationOptions
Inheritance
SamlSpOptions
Inherited Members

Properties

AllowIdpInitiatedSignOn

Whether an assertion arriving for a request this server never made is accepted. Defaults to false.

public bool AllowIdpInitiatedSignOn { get; set; }

Property Value

bool

Remarks

Off, because the correlation this gives up is doing real work: a solicited response is tied to state this handler protected into RelayState when it sent the request, which is what says this browser started this sign-on. An unsolicited assertion has none of that, so accepting one is a decision about a partner IdP that a host makes deliberately.

Accepting them never means ignoring InResponseTo. An unsolicited response must name no request at all; one that names a request, arriving with no state, is a solicited response somebody captured.

The sign-in is recorded against this scheme — the scheme item the external sign-in page reads — so the provider's subject is looked up among this provider's users and no other's, whatever the assertion's attributes say. Each assertion is accepted once (SAML Profiles §4.1.4.5). Both since 0.178.0: until then an unsolicited sign-in recorded no scheme, and the page took the provider from the identity's own idp claim, which an attribute could supply. Read since 0.59.0; documented until 0.178.0 as inert, which it was not.

ClockSkew

Tolerance applied when checking assertion time conditions. Defaults to 5 minutes.

public TimeSpan ClockSkew { get; set; }

Property Value

TimeSpan

Remarks

Since 0.178.0 also an inbound LogoutRequest's: its NotOnOrAfter, and an IssueInstant neither further ahead than this nor older than SamlOptions.DefaultRequestMaxAge and this together. An assertion's and a logout request's ID is remembered until its own expiry plus this, which is when it would be refused anyway.

DecryptionCertificate

Our certificate for decrypting an EncryptedAssertion. Null when we publish no encryption key.

public X509Certificate2? DecryptionCertificate { get; set; }

Property Value

X509Certificate2

Remarks

Needs the private key: a partner IdP encrypts the content key to the public half.

IdpEntityId

The upstream IdP's entity ID (expected assertion issuer).

public string IdpEntityId { get; set; }

Property Value

string

IdpInitiatedReturnPath

Where the browser lands after an unsolicited sign-on. Defaults to /.

public PathString IdpInitiatedReturnPath { get; set; }

Property Value

PathString

Remarks

There is no return URL to honour: nothing on this site asked for the sign-on, so there is nowhere it was going. The IdP's RelayState is not that destination either — it is a value the partner chose, and navigating to it would make this a redirector for anyone who can reach the reply address.

The browser lands here with the identity in the external cookie; with the shipped pages it is the external sign-in callback (/Account/ExternalLogin?handler=Callback) that turns it into a session. Read since 0.59.0; documented until 0.178.0 as inert, which it was not.

IdpSigningCertificate

The upstream IdP's signing certificate, used to verify assertions.

public X509Certificate2 IdpSigningCertificate { get; set; }

Property Value

X509Certificate2

IdpSingleLogoutUrl

The upstream IdP's Single Logout URL (HTTP-Redirect binding). Required to initiate SP logout.

public string? IdpSingleLogoutUrl { get; set; }

Property Value

string

IdpSingleSignOnBinding

How the AuthnRequest reaches the upstream IdP's Single Sign-On URL: HTTP-Redirect (the default) or HTTP-POST, as SamlConstants.Bindings names them.

public string IdpSingleSignOnBinding { get; set; }

Property Value

string

Remarks

Duende 8.0.1's service provider binds its request either way (its SamlProvider.BindingType). A posted request is signed inside the XML rather than beside it, and arrives as a form the browser submits. Since 0.109.0.

IdpSingleSignOnUrl

The upstream IdP's Single Sign-On URL (HTTP-Redirect binding).

public string IdpSingleSignOnUrl { get; set; }

Property Value

string

MetadataPath

Where this service provider publishes its metadata. Defaults to /saml-metadata.

public PathString MetadataPath { get; set; }

Property Value

PathString

Remarks

Public information by definition — an entity id, a reply address, and the certificate a partner encrypts to. Set it to Empty to publish nothing, at the cost of handing the same values over by some other route.

NameIdClaimType

An additional claim type the SAML NameID is mapped to. Defaults to NameIdentifier, which the external identity carries either way.

public string NameIdClaimType { get; set; }

Property Value

string

Remarks

The NameID always arrives as NameIdentifier, because that is the type the shipped external-login page reads to find the provider subject and the type the sign-out path reads off the local principal to name the user back to the identity provider. Setting this adds a second claim of the given type for a deployment whose own external-login handling reads something else.

It used to replace the canonical type, which made every value but the default a registration that broke sign-in outright and sent a LogoutRequest naming nobody. Fixed in 0.52.0; a host that had set it and worked around the break needs no change, because the claim it asked for is still there.

OutboundSigningAlgorithm

The signature method this service provider signs with, as a URI. Null — the default — follows the key: RSA-SHA256, or ECDSA with the hash its curve pairs with.

public string? OutboundSigningAlgorithm { get; set; }

Property Value

string

Remarks

Duende 8.0.1's OutboundSigningAlgorithm, read for every message it signs: the AuthnRequest, the LogoutRequest and the LogoutResponse. It has to be a method this server accepts — SHA-256, SHA-384 or SHA-512, RSA or ECDSA to match SigningCertificate's key — so SHA-1, which Duende can still be told to use, is refused at startup here. Since 0.109.0.

RequireEncryptedAssertion

Whether an assertion that arrives unencrypted is refused. Defaults to false.

public bool RequireEncryptedAssertion { get; set; }

Property Value

bool

Remarks

Set it once the partner IdP is known to encrypt. Accepting either shape until then is the common case; accepting either shape afterwards lets whoever is on the path strip the encryption.

SignOutScheme

The scheme whose session an inbound LogoutRequest ends. Defaults to the sign-in scheme.

public string? SignOutScheme { get; set; }

Property Value

string

Remarks

The same shape OpenIdConnectOptions has, and for the same reason: the scheme an external identity is written to is not the scheme that holds the session. When the identity provider ends the session at its end and tells us, what has to go is the local session — and dropping that cookie is what makes the rest of the sign-out sequence run, since 0.43.0 wraps the handler that holds it. Left null it falls back to SignInScheme, which is the honest default for a handler registered outside an identity server: there is no other session it knows of.

SignedOutCallbackPath

The path the IdP posts the LogoutResponse back to. Defaults to /signout-saml.

public PathString SignedOutCallbackPath { get; set; }

Property Value

PathString

SigningCertificate

Our certificate for signing the messages we send. Null to send them unsigned.

public X509Certificate2? SigningCertificate { get; set; }

Property Value

X509Certificate2

Remarks

Needs the private key. A partner identity provider that requires signed requests refuses an unsigned one, and until 0.70.0 there was no key here to sign with — so the three messages this handler sends all went out unsigned and the metadata said so.

All three, which is the part worth stating: the AuthnRequest that starts a sign-on, the LogoutRequest that starts a logout, and the LogoutResponse that answers the provider's. Signing the two requests and not the response would satisfy a partner's AuthnRequestsSigned and still fail it at the end of a logout, which is the harder failure to attribute.

Setting it changes what the published metadata claims, because the two cannot honestly disagree: the descriptor's AuthnRequestsSigned follows this, and the certificate is published as a signing KeyDescriptor. Claiming to sign without publishing the key leaves a partner told to expect a signature it has no way to verify.

The messages travel on the HTTP-Redirect binding, so the signature is the detached one on the query string (Bindings §3.4.4.1) rather than an enveloped XML signature — a DEFLATEd message in a URL has nowhere to carry one.

SpEntityId

Our entity ID as an SP (used as the AuthnRequest issuer and expected assertion audience).

public string SpEntityId { get; set; }

Property Value

string

StateDataFormat

Protects the relay state that correlates a response to its request.

public ISecureDataFormat<AuthenticationProperties> StateDataFormat { get; set; }

Property Value

ISecureDataFormat<AuthenticationProperties>

Methods

Validate()

Refuses options the handler cannot run on, at startup rather than at the first sign-on.

public override void Validate()

Exceptions

ArgumentException

SpEntityId, IdpEntityId or IdpSingleSignOnUrl is null or empty.

ArgumentNullException

IdpSigningCertificate is null.

InvalidOperationException

SigningCertificate has no private key; IdpSingleSignOnBinding is neither HTTP-Redirect nor HTTP-POST; or OutboundSigningAlgorithm is set with no signing certificate, or names a method its key cannot make.