fix: set certificate validity for SAML IdPs (#8170)

# Which Problems Are Solved

Certificates created for a SAML IdP (used for metadata and request
singing) did not have any validity set. While it's not required for
SAML, when trying to import the certificate into a (keychain) tool it
might fail.

# How the Problems Are Solved

The validity is set based on the `CertificateLifetime` set in the
runtime config.

## After the fix:
If an IdP was created with a certificate without validity, an admin can
regenerate the certificate:
- for instance wide IdPs:
https://zitadel.com/docs/apis/resources/admin/admin-service-regenerate-saml-provider-certificate#regenerate-saml-identity-provider-certificate
- for organization specific IdPs:
https://zitadel.com/docs/apis/resources/mgmt/management-service-regenerate-saml-provider-certificate#regenerate-saml-identity-provider-certificate

Due to the new certificate, the metadata will change and will need to be
updated at the external IdP.

# Additional Changes

Additionally the `CertificateSize` instead of the `Size` (used for keys)
is used for generating the certificate, resp. the underlying key pair.

# Additional Context

- noted by a customer
- needs backports

---------

Co-authored-by: Elio Bischof <elio@zitadel.com>
This commit is contained in:
Livio Spring 2024-06-20 16:09:20 +02:00 committed by GitHub
parent 669ac6bda2
commit 00b5e55565
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -156,7 +156,7 @@ func StartCommands(
defaultRefreshTokenLifetime: defaultRefreshTokenLifetime,
defaultRefreshTokenIdleLifetime: defaultRefreshTokenIdleLifetime,
defaultSecretGenerators: defaultSecretGenerators,
samlCertificateAndKeyGenerator: samlCertificateAndKeyGenerator(defaults.KeyConfig.Size),
samlCertificateAndKeyGenerator: samlCertificateAndKeyGenerator(defaults.KeyConfig.CertificateSize, defaults.KeyConfig.CertificateLifetime),
// always true for now until we can check with an eventlist
EventExisting: func(event string) bool { return true },
// always true for now until we can check with an eventlist
@ -223,7 +223,7 @@ func exists(ctx context.Context, filter preparation.FilterToQueryReducer, wm exi
return wm.Exists(), nil
}
func samlCertificateAndKeyGenerator(keySize int) func(id string) ([]byte, []byte, error) {
func samlCertificateAndKeyGenerator(keySize int, lifetime time.Duration) func(id string) ([]byte, []byte, error) {
return func(id string) ([]byte, []byte, error) {
priv, pub, err := crypto.GenerateKeyPair(keySize)
if err != nil {
@ -234,12 +234,15 @@ func samlCertificateAndKeyGenerator(keySize int) func(id string) ([]byte, []byte
if err != nil {
return nil, nil, err
}
now := time.Now()
template := x509.Certificate{
SerialNumber: big.NewInt(int64(serial)),
Subject: pkix.Name{
Organization: []string{"ZITADEL"},
SerialNumber: id,
},
NotBefore: now,
NotAfter: now.Add(lifetime),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,