mirror of
https://github.com/DuendeSoftware/products
synced 2026-05-24 01:18:22 +00:00
Include encrypting assertions in SAML sample
This commit is contained in:
parent
e178273d94
commit
6d03bec533
2 changed files with 46 additions and 34 deletions
|
|
@ -4,12 +4,13 @@ This client demonstrates SAML 2.0 single sign-on and single logout against Ident
|
|||
|
||||
## SP Certificate
|
||||
|
||||
The SP certificate is required for two SAML best practices:
|
||||
The SP certificate is required for three SAML best practices:
|
||||
|
||||
- **Signed AuthnRequests** — the SP signs every authentication request it sends to the IdP, proving the request originated from this SP and has not been tampered with.
|
||||
- **SP-initiated Single Logout (SLO)** — the SP signs logout requests sent to the IdP. The IdP always requires signed logout requests.
|
||||
- **Encrypted assertions** — the IdP encrypts assertions using the SP's public key, so assertion content is protected in transit and only this SP can decrypt it.
|
||||
|
||||
Without the certificate, the SSO login flow still works, but AuthnRequest signing is disabled and SP-initiated single logout will fail.
|
||||
Without the certificate, the SSO login flow still works, but AuthnRequest signing is disabled, SP-initiated single logout will fail, and assertions are transmitted in plaintext.
|
||||
|
||||
### Generating the certificate
|
||||
|
||||
|
|
@ -27,13 +28,14 @@ After generating the certificate, **restart both this app and the IdentityServer
|
|||
|
||||
### Why both sides need to restart
|
||||
|
||||
The MvcSaml SP reads the certificate at startup to configure request signing. The IdentityServer host also reads the same certificate file at startup to register the SP's public key for signature validation. Both must be restarted whenever the certificate is regenerated.
|
||||
The MvcSaml SP reads the certificate at startup to configure request signing and assertion decryption. The IdentityServer host also reads the same certificate file at startup to register the SP's public key for signature validation and assertion encryption. Both must be restarted whenever the certificate is regenerated.
|
||||
|
||||
## Without the certificate
|
||||
|
||||
| Feature | Without certificate | With certificate |
|
||||
|---|---|---|
|
||||
| SSO (login) | Works | Works |
|
||||
| Encrypted assertions | Disabled (plaintext) | Enabled |
|
||||
| AuthnRequest signing | Disabled | Enabled (always signed) |
|
||||
| SP-initiated Single Logout | Fails (unsigned logout request rejected by IdP) | Works |
|
||||
| IdP-initiated Single Logout | Works (IdP signs its own requests) | Works |
|
||||
|
|
|
|||
|
|
@ -13,37 +13,48 @@ public static class SamlServiceProviders
|
|||
private const string SpCertificatePath = "../../clients/src/MvcSaml/saml-sp.pfx";
|
||||
private const string SpCertificatePassword = "changeit";
|
||||
|
||||
public static IEnumerable<SamlServiceProvider> Get() =>
|
||||
[
|
||||
new SamlServiceProvider
|
||||
{
|
||||
EntityId = "https://localhost:44350/Saml2",
|
||||
DisplayName = "MvcSaml Sample Client",
|
||||
Enabled = true,
|
||||
// ACS URL follows the Sustainsys.Saml2 convention: <base>/Saml2/Acs
|
||||
AssertionConsumerServiceUrls = [new Uri("https://localhost:44350/Saml2/Acs")],
|
||||
// SLO URL follows the Sustainsys.Saml2 convention: <base>/Saml2/Logout
|
||||
SingleLogoutServiceUrl = new SamlEndpointType
|
||||
{
|
||||
Location = new Uri("https://localhost:44350/Saml2/Logout"),
|
||||
Binding = SamlBinding.HttpRedirect
|
||||
},
|
||||
// Sign the assertion (not the response envelope) — the Sustainsys default expectation
|
||||
SigningBehavior = SamlSigningBehavior.SignAssertion,
|
||||
// When the SP certificate is present, require signed AuthnRequests and register the
|
||||
// SP's public key so the IdP can validate the signatures.
|
||||
RequireSignedAuthnRequests = SpCertificateExists(),
|
||||
SigningCertificates = LoadSpSigningCertificates(),
|
||||
}
|
||||
];
|
||||
|
||||
private static bool SpCertificateExists() => File.Exists(SpCertificatePath);
|
||||
|
||||
private static ICollection<X509Certificate2> LoadSpSigningCertificates()
|
||||
public static IEnumerable<SamlServiceProvider> Get()
|
||||
{
|
||||
if (!SpCertificateExists())
|
||||
// Load the SP certificate once. When present, it enables AuthnRequest signature
|
||||
// validation and assertion encryption. The same certificate serves both purposes.
|
||||
var spCert = LoadSpCertificate();
|
||||
var spCerts = spCert != null ? new[] { spCert } : [];
|
||||
|
||||
return
|
||||
[
|
||||
new SamlServiceProvider
|
||||
{
|
||||
EntityId = "https://localhost:44350/Saml2",
|
||||
DisplayName = "MvcSaml Sample Client",
|
||||
Enabled = true,
|
||||
// ACS URL follows the Sustainsys.Saml2 convention: <base>/Saml2/Acs
|
||||
AssertionConsumerServiceUrls = [new Uri("https://localhost:44350/Saml2/Acs")],
|
||||
// SLO URL follows the Sustainsys.Saml2 convention: <base>/Saml2/Logout
|
||||
SingleLogoutServiceUrl = new SamlEndpointType
|
||||
{
|
||||
Location = new Uri("https://localhost:44350/Saml2/Logout"),
|
||||
Binding = SamlBinding.HttpRedirect
|
||||
},
|
||||
// Sign the assertion (not the response envelope) — the Sustainsys default expectation
|
||||
SigningBehavior = SamlSigningBehavior.SignAssertion,
|
||||
// When the SP certificate is present, require signed AuthnRequests, register the
|
||||
// SP's public key for signature validation, and encrypt assertions with it.
|
||||
// The same certificate serves both purposes — signing and encryption.
|
||||
RequireSignedAuthnRequests = spCert != null,
|
||||
SigningCertificates = spCerts,
|
||||
EncryptAssertions = spCert != null,
|
||||
EncryptionCertificates = spCerts,
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
// Returns null if the certificate file has not been generated yet.
|
||||
// See README.md in the MvcSaml project for generation instructions.
|
||||
private static X509Certificate2? LoadSpCertificate()
|
||||
{
|
||||
if (!File.Exists(SpCertificatePath))
|
||||
{
|
||||
return [];
|
||||
return null;
|
||||
}
|
||||
|
||||
// For ease during development, we load the public key directly from the SP's certificate file.
|
||||
|
|
@ -51,8 +62,7 @@ public static class SamlServiceProviders
|
|||
// another secure channel rather than reading the SP's private key material here.
|
||||
#pragma warning disable SYSLIB0057
|
||||
// Only obsolete in .NET 9+; keeping the older API while we support .NET 8.
|
||||
var cert = new X509Certificate2(SpCertificatePath, SpCertificatePassword);
|
||||
return new X509Certificate2(SpCertificatePath, SpCertificatePassword);
|
||||
#pragma warning restore SYSLIB0057
|
||||
return [cert];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue