From f0b6a961fdfdafab2a9e8134fca6ef8493c60d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kara=C5=9B?= Date: Fri, 25 Apr 2025 11:45:31 +0200 Subject: [PATCH 01/13] CRD changes --- api/v1/mdb/mongodb_types.go | 85 ++++++- api/v1/mdb/mongodb_validation.go | 2 +- api/v1/mdbmulti/mongodb_multi_types.go | 10 +- config/crd/bases/mongodb.com_mongodb.yaml | 74 ++++++ .../mongodb.com_mongodbmulticluster.yaml | 74 ++++++ config/crd/bases/mongodb.com_opsmanagers.yaml | 74 ++++++ helm_chart/crds/mongodb.com_mongodb.yaml | 74 ++++++ .../crds/mongodb.com_mongodbmulticluster.yaml | 74 ++++++ helm_chart/crds/mongodb.com_opsmanagers.yaml | 74 ++++++ pkg/util/constants.go | 1 + public/crds.yaml | 222 ++++++++++++++++++ 11 files changed, 757 insertions(+), 7 deletions(-) diff --git a/api/v1/mdb/mongodb_types.go b/api/v1/mdb/mongodb_types.go index 9cf672d4e..21929bb90 100644 --- a/api/v1/mdb/mongodb_types.go +++ b/api/v1/mdb/mongodb_types.go @@ -57,6 +57,12 @@ const ( ClusterTopologySingleCluster = "SingleCluster" ClusterTopologyMultiCluster = "MultiCluster" + OIDCAuthorizationTypeGroupMembership = "GroupMembership" + OIDCAuthorizationTypeUserID = "UserID" + + OIDCAuthorizationMethodWorkforceIdentityFederation = "WorkforceIdentityFederation" + OIDCAuthorizationMethodWorkloadIdentityFederation = "WorkloadIdentityFederation" + LabelResourceOwner = "mongodb.com/v1.mongodbResourceOwner" ) @@ -878,7 +884,7 @@ func (s Security) RequiresClientTLSAuthentication() bool { return false } - if len(s.Authentication.Modes) == 1 && IsAuthPresent(s.Authentication.Modes, util.X509) { + if len(s.Authentication.Modes) == 1 && s.Authentication.IsX509Enabled() { return true } @@ -912,6 +918,8 @@ type Authentication struct { // +optional Ldap *Ldap `json:"ldap,omitempty"` + OIDCProviderConfigs []OIDCProviderConfig `json:"oidcProviderConfigs,omitempty"` + // Agents contains authentication configuration properties for the agents // +optional Agents AgentAuthentication `json:"agents,omitempty"` @@ -920,7 +928,7 @@ type Authentication struct { RequiresClientTLSAuthentication bool `json:"requireClientTLSAuthentication,omitempty"` } -// +kubebuilder:validation:Enum=X509;SCRAM;SCRAM-SHA-1;MONGODB-CR;SCRAM-SHA-256;LDAP +// +kubebuilder:validation:Enum=X509;SCRAM;SCRAM-SHA-1;MONGODB-CR;SCRAM-SHA-256;LDAP;OIDC type AuthMode string func ConvertAuthModesToStrings(authModes []AuthMode) []string { @@ -993,10 +1001,15 @@ func (a *Authentication) IsX509Enabled() bool { } // IsLDAPEnabled determines if LDAP is to be enabled at the project level -func (a *Authentication) isLDAPEnabled() bool { +func (a *Authentication) IsLDAPEnabled() bool { return stringutil.Contains(a.GetModes(), util.LDAP) } +// IsOIDCEnabled determines if OIDC is to be enabled at the project level +func (a *Authentication) IsOIDCEnabled() bool { + return stringutil.Contains(a.GetModes(), util.OIDC) +} + // GetModes returns the modes of the Authentication instance of an empty // list if it is nil func (a *Authentication) GetModes() []string { @@ -1033,6 +1046,63 @@ type Ldap struct { UserCacheInvalidationInterval int `json:"userCacheInvalidationInterval"` } +type OIDCProviderConfig struct { + // TODO add proper validation + // Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when + // creating users and roles for authorization. It is case-sensitive and can only contain the following characters: + // - alphanumeric characters (combination of a to z and 0 to 9) + // - hyphens (-) + // - underscores (_) + ConfigurationName string `json:"configurationName"` + + // TODO add URI validation + // Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider + // Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. + IssuerURI string `json:"issuerURI"` + + // Entity that your external identity provider intends the token for. + // Enter the audience value from the app you registered with external Identity Provider. + Audience string `json:"audience"` + + // Select GroupMembership to grant authorization based on IdP user group membership, or select UserID to grant + // an individual user authorization. + AuthorizationType OIDCAuthorizationType `json:"authorizationType"` + + // The identifier of the claim that includes the user principal identity. + // Accept the default value unless your IdP uses a different claim. + // +default:value:sub + UserClaim string `json:"userClaim"` + + // The identifier of the claim that includes the principal's IdP user group membership information. + // Accept the default value unless your IdP uses a different claim, or you need a custom claim. + // Required when selected GroupMembership as the authorization type, ignored otherwise + // +default:value:groups + // +optional + GroupsClaim string `json:"groupsClaim"` + + // Configure single-sign-on for human user access to Ops Manager deployments with Workforce Identity Federation. + // For programmatic, application access to Ops Manager deployments use Workload Identity Federation. + // Only one Workforce Identity Federation IdP can be configured per MongoDB resource + AuthorizationMethod OIDCAuthorizationMethod `json:"authorizationMethod"` + + // Unique identifier for your registered application. Enter the clientId value from the app you + // registered with an external Identity Provider. + // Required when selected Workforce Identity Federation authorization method + // +optional + ClientId string `json:"clientId"` + + // Tokens that give users permission to request data from the authorization endpoint. + // Only used for Workforce Identity Federation authorization method + // +optional + RequestedScopes []string `json:"requestedScopes"` +} + +// +kubebuilder:validation:Enum=GroupMembership;UserID +type OIDCAuthorizationType string + +// +kubebuilder:validation:Enum=WorkforceIdentityFederation;WorkloadIdentityFederation +type OIDCAuthorizationMethod string + type SecretRef struct { // +kubebuilder:validation:Required Name string `json:"name"` @@ -1142,7 +1212,14 @@ func (m *MongoDB) IsLDAPEnabled() bool { if m.Spec.Security == nil || m.Spec.Security.Authentication == nil { return false } - return IsAuthPresent(m.Spec.Security.Authentication.Modes, util.LDAP) + return m.Spec.Security.Authentication.IsLDAPEnabled() +} + +func (m *MongoDB) IsOIDCEnabled() bool { + if m.Spec.Security == nil || m.Spec.Security.Authentication == nil { + return false + } + return m.Spec.Security.Authentication.IsOIDCEnabled() } func (m *MongoDB) UpdateStatus(phase status.Phase, statusOptions ...status.Option) { diff --git a/api/v1/mdb/mongodb_validation.go b/api/v1/mdb/mongodb_validation.go index e0d16dfdd..9b811cf48 100644 --- a/api/v1/mdb/mongodb_validation.go +++ b/api/v1/mdb/mongodb_validation.go @@ -107,7 +107,7 @@ func scramSha1AuthValidation(d DbCommonSpec) v1.ValidationResult { func ldapAuthRequiresEnterprise(d DbCommonSpec) v1.ValidationResult { authSpec := d.Security.Authentication - if authSpec != nil && authSpec.isLDAPEnabled() && !strings.HasSuffix(d.Version, "-ent") { + if authSpec != nil && authSpec.IsLDAPEnabled() && !strings.HasSuffix(d.Version, "-ent") { return v1.ValidationError("Cannot enable LDAP authentication with MongoDB Community Builds") } return v1.ValidationSuccess() diff --git a/api/v1/mdbmulti/mongodb_multi_types.go b/api/v1/mdbmulti/mongodb_multi_types.go index 3768b99ad..efb15c567 100644 --- a/api/v1/mdbmulti/mongodb_multi_types.go +++ b/api/v1/mdbmulti/mongodb_multi_types.go @@ -23,7 +23,6 @@ import ( "github.com/mongodb/mongodb-kubernetes/pkg/multicluster/failedcluster" "github.com/mongodb/mongodb-kubernetes/pkg/util" intp "github.com/mongodb/mongodb-kubernetes/pkg/util/int" - "github.com/mongodb/mongodb-kubernetes/pkg/util/stringutil" ) func init() { @@ -123,7 +122,14 @@ func (m *MongoDBMultiCluster) IsLDAPEnabled() bool { if m.Spec.Security == nil || m.Spec.Security.Authentication == nil { return false } - return stringutil.Contains(m.Spec.GetSecurityAuthenticationModes(), util.LDAP) + return m.Spec.Security.Authentication.IsLDAPEnabled() +} + +func (m *MongoDBMultiCluster) IsOIDCEnabled() bool { + if m.Spec.Security == nil || m.Spec.Security.Authentication == nil { + return false + } + return m.Spec.Security.Authentication.IsOIDCEnabled() } func (m *MongoDBMultiCluster) GetLDAP(password, caContents string) *ldap.Ldap { diff --git a/config/crd/bases/mongodb.com_mongodb.yaml b/config/crd/bases/mongodb.com_mongodb.yaml index a5b0287c2..d93468b13 100644 --- a/config/crd/bases/mongodb.com_mongodb.yaml +++ b/config/crd/bases/mongodb.com_mongodb.yaml @@ -1521,8 +1521,82 @@ spec: - MONGODB-CR - SCRAM-SHA-256 - LDAP + - OIDC type: string type: array + oidcProviderConfigs: + items: + properties: + audience: + description: |- + Entity that your external identity provider intends the token for. + Enter the audience value from the app you registered with external Identity Provider. + type: string + authorizationMethod: + description: |- + Configure single-sign-on for human user access to Ops Manager deployments with Workforce Identity Federation. + For programmatic, application access to Ops Manager deployments use Workload Identity Federation. + Only one Workforce Identity Federation IdP can be configured per MongoDB resource + enum: + - WorkforceIdentityFederation + - WorkloadIdentityFederation + type: string + authorizationType: + description: |- + Select GroupMembership to grant authorization based on IdP user group membership, or select UserID to grant + an individual user authorization. + enum: + - GroupMembership + - UserID + type: string + clientId: + description: |- + Unique identifier for your registered application. Enter the clientId value from the app you + registered with an external Identity Provider. + Required when selected Workforce Identity Federation authorization method + type: string + configurationName: + description: |- + TODO add proper validation + Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when + creating users and roles for authorization. It is case-sensitive and can only contain the following characters: + - alphanumeric characters (combination of a to z and 0 to 9) + - hyphens (-) + - underscores (_) + type: string + groupsClaim: + description: |- + The identifier of the claim that includes the principal's IdP user group membership information. + Accept the default value unless your IdP uses a different claim, or you need a custom claim. + Required when selected GroupMembership as the authorization type, ignored otherwise + type: string + issuerURI: + description: |- + TODO add URI validation + Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider + Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. + type: string + requestedScopes: + description: |- + Tokens that give users permission to request data from the authorization endpoint. + Only used for Workforce Identity Federation authorization method + items: + type: string + type: array + userClaim: + description: |- + The identifier of the claim that includes the user principal identity. + Accept the default value unless your IdP uses a different claim. + type: string + required: + - audience + - authorizationMethod + - authorizationType + - configurationName + - issuerURI + - userClaim + type: object + type: array requireClientTLSAuthentication: description: Clients should present valid TLS certificates type: boolean diff --git a/config/crd/bases/mongodb.com_mongodbmulticluster.yaml b/config/crd/bases/mongodb.com_mongodbmulticluster.yaml index 0e1d65480..f9fed2293 100644 --- a/config/crd/bases/mongodb.com_mongodbmulticluster.yaml +++ b/config/crd/bases/mongodb.com_mongodbmulticluster.yaml @@ -781,8 +781,82 @@ spec: - MONGODB-CR - SCRAM-SHA-256 - LDAP + - OIDC type: string type: array + oidcProviderConfigs: + items: + properties: + audience: + description: |- + Entity that your external identity provider intends the token for. + Enter the audience value from the app you registered with external Identity Provider. + type: string + authorizationMethod: + description: |- + Configure single-sign-on for human user access to Ops Manager deployments with Workforce Identity Federation. + For programmatic, application access to Ops Manager deployments use Workload Identity Federation. + Only one Workforce Identity Federation IdP can be configured per MongoDB resource + enum: + - WorkforceIdentityFederation + - WorkloadIdentityFederation + type: string + authorizationType: + description: |- + Select GroupMembership to grant authorization based on IdP user group membership, or select UserID to grant + an individual user authorization. + enum: + - GroupMembership + - UserID + type: string + clientId: + description: |- + Unique identifier for your registered application. Enter the clientId value from the app you + registered with an external Identity Provider. + Required when selected Workforce Identity Federation authorization method + type: string + configurationName: + description: |- + TODO add proper validation + Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when + creating users and roles for authorization. It is case-sensitive and can only contain the following characters: + - alphanumeric characters (combination of a to z and 0 to 9) + - hyphens (-) + - underscores (_) + type: string + groupsClaim: + description: |- + The identifier of the claim that includes the principal's IdP user group membership information. + Accept the default value unless your IdP uses a different claim, or you need a custom claim. + Required when selected GroupMembership as the authorization type, ignored otherwise + type: string + issuerURI: + description: |- + TODO add URI validation + Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider + Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. + type: string + requestedScopes: + description: |- + Tokens that give users permission to request data from the authorization endpoint. + Only used for Workforce Identity Federation authorization method + items: + type: string + type: array + userClaim: + description: |- + The identifier of the claim that includes the user principal identity. + Accept the default value unless your IdP uses a different claim. + type: string + required: + - audience + - authorizationMethod + - authorizationType + - configurationName + - issuerURI + - userClaim + type: object + type: array requireClientTLSAuthentication: description: Clients should present valid TLS certificates type: boolean diff --git a/config/crd/bases/mongodb.com_opsmanagers.yaml b/config/crd/bases/mongodb.com_opsmanagers.yaml index 72c2ce553..adac7f2ae 100644 --- a/config/crd/bases/mongodb.com_opsmanagers.yaml +++ b/config/crd/bases/mongodb.com_opsmanagers.yaml @@ -843,8 +843,82 @@ spec: - MONGODB-CR - SCRAM-SHA-256 - LDAP + - OIDC type: string type: array + oidcProviderConfigs: + items: + properties: + audience: + description: |- + Entity that your external identity provider intends the token for. + Enter the audience value from the app you registered with external Identity Provider. + type: string + authorizationMethod: + description: |- + Configure single-sign-on for human user access to Ops Manager deployments with Workforce Identity Federation. + For programmatic, application access to Ops Manager deployments use Workload Identity Federation. + Only one Workforce Identity Federation IdP can be configured per MongoDB resource + enum: + - WorkforceIdentityFederation + - WorkloadIdentityFederation + type: string + authorizationType: + description: |- + Select GroupMembership to grant authorization based on IdP user group membership, or select UserID to grant + an individual user authorization. + enum: + - GroupMembership + - UserID + type: string + clientId: + description: |- + Unique identifier for your registered application. Enter the clientId value from the app you + registered with an external Identity Provider. + Required when selected Workforce Identity Federation authorization method + type: string + configurationName: + description: |- + TODO add proper validation + Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when + creating users and roles for authorization. It is case-sensitive and can only contain the following characters: + - alphanumeric characters (combination of a to z and 0 to 9) + - hyphens (-) + - underscores (_) + type: string + groupsClaim: + description: |- + The identifier of the claim that includes the principal's IdP user group membership information. + Accept the default value unless your IdP uses a different claim, or you need a custom claim. + Required when selected GroupMembership as the authorization type, ignored otherwise + type: string + issuerURI: + description: |- + TODO add URI validation + Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider + Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. + type: string + requestedScopes: + description: |- + Tokens that give users permission to request data from the authorization endpoint. + Only used for Workforce Identity Federation authorization method + items: + type: string + type: array + userClaim: + description: |- + The identifier of the claim that includes the user principal identity. + Accept the default value unless your IdP uses a different claim. + type: string + required: + - audience + - authorizationMethod + - authorizationType + - configurationName + - issuerURI + - userClaim + type: object + type: array requireClientTLSAuthentication: description: Clients should present valid TLS certificates type: boolean diff --git a/helm_chart/crds/mongodb.com_mongodb.yaml b/helm_chart/crds/mongodb.com_mongodb.yaml index a5b0287c2..d93468b13 100644 --- a/helm_chart/crds/mongodb.com_mongodb.yaml +++ b/helm_chart/crds/mongodb.com_mongodb.yaml @@ -1521,8 +1521,82 @@ spec: - MONGODB-CR - SCRAM-SHA-256 - LDAP + - OIDC type: string type: array + oidcProviderConfigs: + items: + properties: + audience: + description: |- + Entity that your external identity provider intends the token for. + Enter the audience value from the app you registered with external Identity Provider. + type: string + authorizationMethod: + description: |- + Configure single-sign-on for human user access to Ops Manager deployments with Workforce Identity Federation. + For programmatic, application access to Ops Manager deployments use Workload Identity Federation. + Only one Workforce Identity Federation IdP can be configured per MongoDB resource + enum: + - WorkforceIdentityFederation + - WorkloadIdentityFederation + type: string + authorizationType: + description: |- + Select GroupMembership to grant authorization based on IdP user group membership, or select UserID to grant + an individual user authorization. + enum: + - GroupMembership + - UserID + type: string + clientId: + description: |- + Unique identifier for your registered application. Enter the clientId value from the app you + registered with an external Identity Provider. + Required when selected Workforce Identity Federation authorization method + type: string + configurationName: + description: |- + TODO add proper validation + Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when + creating users and roles for authorization. It is case-sensitive and can only contain the following characters: + - alphanumeric characters (combination of a to z and 0 to 9) + - hyphens (-) + - underscores (_) + type: string + groupsClaim: + description: |- + The identifier of the claim that includes the principal's IdP user group membership information. + Accept the default value unless your IdP uses a different claim, or you need a custom claim. + Required when selected GroupMembership as the authorization type, ignored otherwise + type: string + issuerURI: + description: |- + TODO add URI validation + Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider + Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. + type: string + requestedScopes: + description: |- + Tokens that give users permission to request data from the authorization endpoint. + Only used for Workforce Identity Federation authorization method + items: + type: string + type: array + userClaim: + description: |- + The identifier of the claim that includes the user principal identity. + Accept the default value unless your IdP uses a different claim. + type: string + required: + - audience + - authorizationMethod + - authorizationType + - configurationName + - issuerURI + - userClaim + type: object + type: array requireClientTLSAuthentication: description: Clients should present valid TLS certificates type: boolean diff --git a/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml b/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml index 0e1d65480..f9fed2293 100644 --- a/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml +++ b/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml @@ -781,8 +781,82 @@ spec: - MONGODB-CR - SCRAM-SHA-256 - LDAP + - OIDC type: string type: array + oidcProviderConfigs: + items: + properties: + audience: + description: |- + Entity that your external identity provider intends the token for. + Enter the audience value from the app you registered with external Identity Provider. + type: string + authorizationMethod: + description: |- + Configure single-sign-on for human user access to Ops Manager deployments with Workforce Identity Federation. + For programmatic, application access to Ops Manager deployments use Workload Identity Federation. + Only one Workforce Identity Federation IdP can be configured per MongoDB resource + enum: + - WorkforceIdentityFederation + - WorkloadIdentityFederation + type: string + authorizationType: + description: |- + Select GroupMembership to grant authorization based on IdP user group membership, or select UserID to grant + an individual user authorization. + enum: + - GroupMembership + - UserID + type: string + clientId: + description: |- + Unique identifier for your registered application. Enter the clientId value from the app you + registered with an external Identity Provider. + Required when selected Workforce Identity Federation authorization method + type: string + configurationName: + description: |- + TODO add proper validation + Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when + creating users and roles for authorization. It is case-sensitive and can only contain the following characters: + - alphanumeric characters (combination of a to z and 0 to 9) + - hyphens (-) + - underscores (_) + type: string + groupsClaim: + description: |- + The identifier of the claim that includes the principal's IdP user group membership information. + Accept the default value unless your IdP uses a different claim, or you need a custom claim. + Required when selected GroupMembership as the authorization type, ignored otherwise + type: string + issuerURI: + description: |- + TODO add URI validation + Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider + Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. + type: string + requestedScopes: + description: |- + Tokens that give users permission to request data from the authorization endpoint. + Only used for Workforce Identity Federation authorization method + items: + type: string + type: array + userClaim: + description: |- + The identifier of the claim that includes the user principal identity. + Accept the default value unless your IdP uses a different claim. + type: string + required: + - audience + - authorizationMethod + - authorizationType + - configurationName + - issuerURI + - userClaim + type: object + type: array requireClientTLSAuthentication: description: Clients should present valid TLS certificates type: boolean diff --git a/helm_chart/crds/mongodb.com_opsmanagers.yaml b/helm_chart/crds/mongodb.com_opsmanagers.yaml index 72c2ce553..adac7f2ae 100644 --- a/helm_chart/crds/mongodb.com_opsmanagers.yaml +++ b/helm_chart/crds/mongodb.com_opsmanagers.yaml @@ -843,8 +843,82 @@ spec: - MONGODB-CR - SCRAM-SHA-256 - LDAP + - OIDC type: string type: array + oidcProviderConfigs: + items: + properties: + audience: + description: |- + Entity that your external identity provider intends the token for. + Enter the audience value from the app you registered with external Identity Provider. + type: string + authorizationMethod: + description: |- + Configure single-sign-on for human user access to Ops Manager deployments with Workforce Identity Federation. + For programmatic, application access to Ops Manager deployments use Workload Identity Federation. + Only one Workforce Identity Federation IdP can be configured per MongoDB resource + enum: + - WorkforceIdentityFederation + - WorkloadIdentityFederation + type: string + authorizationType: + description: |- + Select GroupMembership to grant authorization based on IdP user group membership, or select UserID to grant + an individual user authorization. + enum: + - GroupMembership + - UserID + type: string + clientId: + description: |- + Unique identifier for your registered application. Enter the clientId value from the app you + registered with an external Identity Provider. + Required when selected Workforce Identity Federation authorization method + type: string + configurationName: + description: |- + TODO add proper validation + Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when + creating users and roles for authorization. It is case-sensitive and can only contain the following characters: + - alphanumeric characters (combination of a to z and 0 to 9) + - hyphens (-) + - underscores (_) + type: string + groupsClaim: + description: |- + The identifier of the claim that includes the principal's IdP user group membership information. + Accept the default value unless your IdP uses a different claim, or you need a custom claim. + Required when selected GroupMembership as the authorization type, ignored otherwise + type: string + issuerURI: + description: |- + TODO add URI validation + Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider + Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. + type: string + requestedScopes: + description: |- + Tokens that give users permission to request data from the authorization endpoint. + Only used for Workforce Identity Federation authorization method + items: + type: string + type: array + userClaim: + description: |- + The identifier of the claim that includes the user principal identity. + Accept the default value unless your IdP uses a different claim. + type: string + required: + - audience + - authorizationMethod + - authorizationType + - configurationName + - issuerURI + - userClaim + type: object + type: array requireClientTLSAuthentication: description: Clients should present valid TLS certificates type: boolean diff --git a/pkg/util/constants.go b/pkg/util/constants.go index 77cfbb57c..415b334ff 100644 --- a/pkg/util/constants.go +++ b/pkg/util/constants.go @@ -147,6 +147,7 @@ const ( MONGODBCR = "MONGODB-CR" SCRAMSHA256 = "SCRAM-SHA-256" LDAP = "LDAP" + OIDC = "OIDC" MinimumScramSha256MdbVersion = "4.0.0" // these were historically used and constituted a security issue—if set they should be changed diff --git a/public/crds.yaml b/public/crds.yaml index 37c001ac6..68ee6ff03 100644 --- a/public/crds.yaml +++ b/public/crds.yaml @@ -1521,8 +1521,82 @@ spec: - MONGODB-CR - SCRAM-SHA-256 - LDAP + - OIDC type: string type: array + oidcProviderConfigs: + items: + properties: + audience: + description: |- + Entity that your external identity provider intends the token for. + Enter the audience value from the app you registered with external Identity Provider. + type: string + authorizationMethod: + description: |- + Configure single-sign-on for human user access to Ops Manager deployments with Workforce Identity Federation. + For programmatic, application access to Ops Manager deployments use Workload Identity Federation. + Only one Workforce Identity Federation IdP can be configured per MongoDB resource + enum: + - WorkforceIdentityFederation + - WorkloadIdentityFederation + type: string + authorizationType: + description: |- + Select GroupMembership to grant authorization based on IdP user group membership, or select UserID to grant + an individual user authorization. + enum: + - GroupMembership + - UserID + type: string + clientId: + description: |- + Unique identifier for your registered application. Enter the clientId value from the app you + registered with an external Identity Provider. + Required when selected Workforce Identity Federation authorization method + type: string + configurationName: + description: |- + TODO add proper validation + Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when + creating users and roles for authorization. It is case-sensitive and can only contain the following characters: + - alphanumeric characters (combination of a to z and 0 to 9) + - hyphens (-) + - underscores (_) + type: string + groupsClaim: + description: |- + The identifier of the claim that includes the principal's IdP user group membership information. + Accept the default value unless your IdP uses a different claim, or you need a custom claim. + Required when selected GroupMembership as the authorization type, ignored otherwise + type: string + issuerURI: + description: |- + TODO add URI validation + Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider + Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. + type: string + requestedScopes: + description: |- + Tokens that give users permission to request data from the authorization endpoint. + Only used for Workforce Identity Federation authorization method + items: + type: string + type: array + userClaim: + description: |- + The identifier of the claim that includes the user principal identity. + Accept the default value unless your IdP uses a different claim. + type: string + required: + - audience + - authorizationMethod + - authorizationType + - configurationName + - issuerURI + - userClaim + type: object + type: array requireClientTLSAuthentication: description: Clients should present valid TLS certificates type: boolean @@ -4081,8 +4155,82 @@ spec: - MONGODB-CR - SCRAM-SHA-256 - LDAP + - OIDC type: string type: array + oidcProviderConfigs: + items: + properties: + audience: + description: |- + Entity that your external identity provider intends the token for. + Enter the audience value from the app you registered with external Identity Provider. + type: string + authorizationMethod: + description: |- + Configure single-sign-on for human user access to Ops Manager deployments with Workforce Identity Federation. + For programmatic, application access to Ops Manager deployments use Workload Identity Federation. + Only one Workforce Identity Federation IdP can be configured per MongoDB resource + enum: + - WorkforceIdentityFederation + - WorkloadIdentityFederation + type: string + authorizationType: + description: |- + Select GroupMembership to grant authorization based on IdP user group membership, or select UserID to grant + an individual user authorization. + enum: + - GroupMembership + - UserID + type: string + clientId: + description: |- + Unique identifier for your registered application. Enter the clientId value from the app you + registered with an external Identity Provider. + Required when selected Workforce Identity Federation authorization method + type: string + configurationName: + description: |- + TODO add proper validation + Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when + creating users and roles for authorization. It is case-sensitive and can only contain the following characters: + - alphanumeric characters (combination of a to z and 0 to 9) + - hyphens (-) + - underscores (_) + type: string + groupsClaim: + description: |- + The identifier of the claim that includes the principal's IdP user group membership information. + Accept the default value unless your IdP uses a different claim, or you need a custom claim. + Required when selected GroupMembership as the authorization type, ignored otherwise + type: string + issuerURI: + description: |- + TODO add URI validation + Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider + Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. + type: string + requestedScopes: + description: |- + Tokens that give users permission to request data from the authorization endpoint. + Only used for Workforce Identity Federation authorization method + items: + type: string + type: array + userClaim: + description: |- + The identifier of the claim that includes the user principal identity. + Accept the default value unless your IdP uses a different claim. + type: string + required: + - audience + - authorizationMethod + - authorizationType + - configurationName + - issuerURI + - userClaim + type: object + type: array requireClientTLSAuthentication: description: Clients should present valid TLS certificates type: boolean @@ -5396,8 +5544,82 @@ spec: - MONGODB-CR - SCRAM-SHA-256 - LDAP + - OIDC type: string type: array + oidcProviderConfigs: + items: + properties: + audience: + description: |- + Entity that your external identity provider intends the token for. + Enter the audience value from the app you registered with external Identity Provider. + type: string + authorizationMethod: + description: |- + Configure single-sign-on for human user access to Ops Manager deployments with Workforce Identity Federation. + For programmatic, application access to Ops Manager deployments use Workload Identity Federation. + Only one Workforce Identity Federation IdP can be configured per MongoDB resource + enum: + - WorkforceIdentityFederation + - WorkloadIdentityFederation + type: string + authorizationType: + description: |- + Select GroupMembership to grant authorization based on IdP user group membership, or select UserID to grant + an individual user authorization. + enum: + - GroupMembership + - UserID + type: string + clientId: + description: |- + Unique identifier for your registered application. Enter the clientId value from the app you + registered with an external Identity Provider. + Required when selected Workforce Identity Federation authorization method + type: string + configurationName: + description: |- + TODO add proper validation + Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when + creating users and roles for authorization. It is case-sensitive and can only contain the following characters: + - alphanumeric characters (combination of a to z and 0 to 9) + - hyphens (-) + - underscores (_) + type: string + groupsClaim: + description: |- + The identifier of the claim that includes the principal's IdP user group membership information. + Accept the default value unless your IdP uses a different claim, or you need a custom claim. + Required when selected GroupMembership as the authorization type, ignored otherwise + type: string + issuerURI: + description: |- + TODO add URI validation + Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider + Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. + type: string + requestedScopes: + description: |- + Tokens that give users permission to request data from the authorization endpoint. + Only used for Workforce Identity Federation authorization method + items: + type: string + type: array + userClaim: + description: |- + The identifier of the claim that includes the user principal identity. + Accept the default value unless your IdP uses a different claim. + type: string + required: + - audience + - authorizationMethod + - authorizationType + - configurationName + - issuerURI + - userClaim + type: object + type: array requireClientTLSAuthentication: description: Clients should present valid TLS certificates type: boolean From 7c231436177bb5b2c7eb2aee4adbb4f4e515994f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kara=C5=9B?= Date: Fri, 25 Apr 2025 12:54:46 +0200 Subject: [PATCH 02/13] Added validation logic + tests --- api/v1/mdb/mongodb_types.go | 23 +- api/v1/mdb/mongodb_types_test.go | 69 +++++ api/v1/mdb/mongodb_validation.go | 151 +++++++++- api/v1/mdb/mongodb_validation_test.go | 271 ++++++++++++++++++ config/crd/bases/mongodb.com_mongodb.yaml | 2 +- .../mongodb.com_mongodbmulticluster.yaml | 2 +- config/crd/bases/mongodb.com_opsmanagers.yaml | 2 +- helm_chart/crds/mongodb.com_mongodb.yaml | 2 +- .../crds/mongodb.com_mongodbmulticluster.yaml | 2 +- helm_chart/crds/mongodb.com_opsmanagers.yaml | 2 +- pkg/util/util.go | 7 + public/crds.yaml | 6 +- 12 files changed, 526 insertions(+), 13 deletions(-) diff --git a/api/v1/mdb/mongodb_types.go b/api/v1/mdb/mongodb_types.go index 21929bb90..31c3ee3f9 100644 --- a/api/v1/mdb/mongodb_types.go +++ b/api/v1/mdb/mongodb_types.go @@ -807,6 +807,22 @@ func (s *Security) IsTLSEnabled() bool { return s.CertificatesSecretsPrefix != "" } +func (s *Security) IsOIDCEnabled() bool { + if s == nil { + return false + } + + if s.Authentication == nil { + return false + } + + if !s.Authentication.Enabled { + return false + } + + return s.Authentication.IsOIDCEnabled() +} + // GetAgentMechanism returns the authentication mechanism that the agents will be using. // The agents will use X509 if it is the only mechanism specified, otherwise they will use SCRAM if specified // and no auth if no mechanisms exist. @@ -1047,12 +1063,13 @@ type Ldap struct { } type OIDCProviderConfig struct { - // TODO add proper validation + // TODO add proper validation and test it // Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when // creating users and roles for authorization. It is case-sensitive and can only contain the following characters: // - alphanumeric characters (combination of a to z and 0 to 9) // - hyphens (-) // - underscores (_) + // +kubebuilder:validation:Pattern:"^[a-zA-Z0-9-_]+$" ConfigurationName string `json:"configurationName"` // TODO add URI validation @@ -1280,6 +1297,10 @@ func (m *MongoDB) GetStatus(...status.Option) interface{} { return m.Status } +func (m *MongoDB) GetStatusWarnings() []status.Warning { + return m.Status.Warnings +} + func (m *MongoDB) GetCommonStatus(...status.Option) *status.Common { return &m.Status.Common } diff --git a/api/v1/mdb/mongodb_types_test.go b/api/v1/mdb/mongodb_types_test.go index b17bbc04e..8566d6f71 100644 --- a/api/v1/mdb/mongodb_types_test.go +++ b/api/v1/mdb/mongodb_types_test.go @@ -61,6 +61,75 @@ func TestGetAgentAuthentication(t *testing.T) { assert.Equal(t, util.X509, sec.GetAgentMechanism("SCRAM-SHA-256"), "transitioning from SCRAM -> X509 is allowed") } +func TestGetAuthenticationIsEnabledMethods(t *testing.T) { + tests := []struct { + name string + authentication *Authentication + expectedX509 bool + expectedLDAP bool + expectedOIDC bool + }{ + { + name: "Nil authentication", + authentication: nil, + expectedX509: false, + expectedLDAP: false, + expectedOIDC: false, + }, + { + name: "Empty authentication", + authentication: newAuthentication(), + expectedX509: false, + expectedLDAP: false, + expectedOIDC: false, + }, + { + name: "Authentication with x509 only", + authentication: &Authentication{ + Modes: []AuthMode{util.X509}, + }, + expectedX509: true, + expectedLDAP: false, + expectedOIDC: false, + }, + { + name: "Authentication with LDAP only", + authentication: &Authentication{ + Modes: []AuthMode{util.LDAP}, + }, + expectedX509: false, + expectedLDAP: true, + expectedOIDC: false, + }, + { + name: "Authentication with OIDC only", + authentication: &Authentication{ + Modes: []AuthMode{util.OIDC}, + }, + expectedX509: false, + expectedLDAP: false, + expectedOIDC: true, + }, + { + name: "Authentication with multiple modes", + authentication: &Authentication{ + Modes: []AuthMode{util.X509, util.LDAP, util.OIDC, util.SCRAM}, + }, + expectedX509: true, + expectedLDAP: true, + expectedOIDC: true, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + auth := test.authentication + assert.Equal(t, test.expectedX509, auth.IsX509Enabled()) + assert.Equal(t, test.expectedLDAP, auth.IsLDAPEnabled()) + assert.Equal(t, test.expectedOIDC, auth.IsOIDCEnabled()) + }) + } +} + func TestMinimumMajorVersion(t *testing.T) { mdbSpec := MongoDbSpec{ DbCommonSpec: DbCommonSpec{ diff --git a/api/v1/mdb/mongodb_validation.go b/api/v1/mdb/mongodb_validation.go index 9b811cf48..a91f983bf 100644 --- a/api/v1/mdb/mongodb_validation.go +++ b/api/v1/mdb/mongodb_validation.go @@ -2,6 +2,7 @@ package mdb import ( "errors" + "fmt" "strings" "k8s.io/apimachinery/pkg/runtime" @@ -105,6 +106,146 @@ func scramSha1AuthValidation(d DbCommonSpec) v1.ValidationResult { return v1.ValidationSuccess() } +func oidcAuthValidators(db DbCommonSpec) []func(DbCommonSpec) v1.ValidationResult { + validators := make([]func(DbCommonSpec) v1.ValidationResult, 0) + if !db.Security.IsOIDCEnabled() { + return validators + } + + authentication := db.Security.Authentication + validators = append(validators, oidcAuthModeValidator(authentication)) + + providerConfigs := authentication.OIDCProviderConfigs + if len(providerConfigs) == 0 { + return validators + } + + validators = append(validators, + oidcProviderConfigsUniqueNameValidation(providerConfigs), + oidcProviderConfigsSingleWorkforceIdentityFederationValidation(providerConfigs), + ) + + for _, config := range providerConfigs { + validators = append(validators, + oidcProviderConfigIssuerURIValidator(config), + oidcProviderConfigClientIdValidator(config), + oidcProviderConfigRequestedScopesValidator(config), + oidcProviderConfigAuthorizationTypeValidator(config), + ) + } + + return validators +} + +func oidcAuthModeValidator(authentication *Authentication) func(DbCommonSpec) v1.ValidationResult { + return func(spec DbCommonSpec) v1.ValidationResult { + // OIDC cannot be used for agent authentication so other auth mode has to enabled as well + if len(authentication.Modes) == 1 { + return v1.ValidationError("OIDC authentication cannot be used as the only authentication mechanism") + } + + oidcProviderConfigs := authentication.OIDCProviderConfigs + if len(oidcProviderConfigs) == 0 { + return v1.ValidationError("At least one OIDC provider config needs to be specified when OIDC authentication is enabled") + } + + return v1.ValidationSuccess() + } +} + +func oidcProviderConfigsUniqueNameValidation(configs []OIDCProviderConfig) func(DbCommonSpec) v1.ValidationResult { + return func(spec DbCommonSpec) v1.ValidationResult { + configNames := make(map[string]bool) + for _, config := range configs { + if _, ok := configNames[config.ConfigurationName]; ok { + return v1.ValidationError("OIDC provider config name %s is not unique", config.ConfigurationName) + } + + configNames[config.ConfigurationName] = true + } + + return v1.ValidationSuccess() + } +} + +func oidcProviderConfigsSingleWorkforceIdentityFederationValidation(configs []OIDCProviderConfig) func(DbCommonSpec) v1.ValidationResult { + return func(spec DbCommonSpec) v1.ValidationResult { + workforceIdentityFederationConfigs := make([]string, 0) + for _, config := range configs { + if config.AuthorizationMethod == OIDCAuthorizationMethodWorkforceIdentityFederation { + workforceIdentityFederationConfigs = append(workforceIdentityFederationConfigs, config.ConfigurationName) + } + } + + if len(workforceIdentityFederationConfigs) > 1 { + msg := fmt.Sprintf("Only one OIDC provider config can be configured with Workforce Identity Federation. "+ + "The following configs are configured with Workforce Identity Federation: %s", strings.Join(workforceIdentityFederationConfigs, ", ")) + return v1.ValidationError("%s", msg) + } + + return v1.ValidationSuccess() + } +} + +func oidcProviderConfigIssuerURIValidator(config OIDCProviderConfig) func(DbCommonSpec) v1.ValidationResult { + return func(_ DbCommonSpec) v1.ValidationResult { + ok, url := util.IsURL(config.IssuerURI) + if !ok { + return v1.ValidationError("Invalid IssuerURI in OIDC provider config %q", config.ConfigurationName) + } + + if url.Scheme != "https" { + return v1.ValidationWarning("IssuerURI in OIDC provider config %q in not secure endpoint", config.ConfigurationName) + } + + return v1.ValidationSuccess() + } +} + +func oidcProviderConfigClientIdValidator(config OIDCProviderConfig) func(DbCommonSpec) v1.ValidationResult { + return func(_ DbCommonSpec) v1.ValidationResult { + if config.AuthorizationMethod == OIDCAuthorizationMethodWorkforceIdentityFederation { + if config.ClientId == "" { + return v1.ValidationError("ClientId has to be specified in OIDC provider config %q with Workforce Identity Federation", config.ConfigurationName) + } + } else if config.AuthorizationMethod == OIDCAuthorizationMethodWorkloadIdentityFederation { + if config.ClientId != "" { + return v1.ValidationWarning("ClientId will be ignored in OIDC provider config %q with Workload Identity Federation", config.ConfigurationName) + } + } + + return v1.ValidationSuccess() + } +} + +func oidcProviderConfigRequestedScopesValidator(config OIDCProviderConfig) func(DbCommonSpec) v1.ValidationResult { + return func(_ DbCommonSpec) v1.ValidationResult { + if config.AuthorizationMethod == OIDCAuthorizationMethodWorkloadIdentityFederation { + if len(config.RequestedScopes) > 0 { + return v1.ValidationWarning("RequestedScopes will be ignored in OIDC provider config %q with Workload Identity Federation", config.ConfigurationName) + } + } + + return v1.ValidationSuccess() + } +} + +func oidcProviderConfigAuthorizationTypeValidator(config OIDCProviderConfig) func(DbCommonSpec) v1.ValidationResult { + return func(_ DbCommonSpec) v1.ValidationResult { + if config.AuthorizationType == OIDCAuthorizationTypeGroupMembership { + if config.GroupsClaim == "" { + return v1.ValidationError("GroupsClaim has to be specified in OIDC provider config %q when using Group Membership authorization", config.ConfigurationName) + } + } else if config.AuthorizationType == OIDCAuthorizationTypeUserID { + if config.GroupsClaim != "" { + return v1.ValidationWarning("GroupsClaim will be ignored in OIDC provider config %q when using User ID authorization", config.ConfigurationName) + } + } + + return v1.ValidationSuccess() + } +} + func ldapAuthRequiresEnterprise(d DbCommonSpec) v1.ValidationResult { authSpec := d.Security.Authentication if authSpec != nil && authSpec.IsLDAPEnabled() && !strings.HasSuffix(d.Version, "-ent") { @@ -187,8 +328,8 @@ func specWithExactlyOneSchema(d DbCommonSpec) v1.ValidationResult { return v1.ValidationSuccess() } -func CommonValidators() []func(d DbCommonSpec) v1.ValidationResult { - return []func(d DbCommonSpec) v1.ValidationResult{ +func CommonValidators(db DbCommonSpec) []func(d DbCommonSpec) v1.ValidationResult { + validators := []func(d DbCommonSpec) v1.ValidationResult{ replicaSetHorizonsRequireTLS, deploymentsMustHaveTLSInX509Env, deploymentsMustHaveAtLeastOneAuthModeIfAuthIsEnabled, @@ -201,6 +342,10 @@ func CommonValidators() []func(d DbCommonSpec) v1.ValidationResult { specWithExactlyOneSchema, featureCompatibilityVersionValidation, } + + validators = append(validators, oidcAuthValidators(db)...) + + return validators } func featureCompatibilityVersionValidation(d DbCommonSpec) v1.ValidationResult { @@ -245,7 +390,7 @@ func (m *MongoDB) RunValidations(old *MongoDB) []v1.ValidationResult { } } - for _, validator := range CommonValidators() { + for _, validator := range CommonValidators(m.Spec.DbCommonSpec) { res := validator(m.Spec.DbCommonSpec) if res.Level > 0 { validationResults = append(validationResults, res) diff --git a/api/v1/mdb/mongodb_validation_test.go b/api/v1/mdb/mongodb_validation_test.go index 21f2263d1..4a3db9da4 100644 --- a/api/v1/mdb/mongodb_validation_test.go +++ b/api/v1/mdb/mongodb_validation_test.go @@ -8,6 +8,7 @@ import ( "k8s.io/utils/ptr" v1 "github.com/mongodb/mongodb-kubernetes/api/v1" + "github.com/mongodb/mongodb-kubernetes/api/v1/status" "github.com/mongodb/mongodb-kubernetes/pkg/util" ) @@ -200,3 +201,273 @@ func TestReplicasetFCV(t *testing.T) { }) } } + +func TestOIDCAuthValidation(t *testing.T) { + tests := []struct { + name string + auth *Authentication + expectedErrorMessage string + expectedWarning status.Warning + }{ + { + name: "Authentication disabled", + auth: &Authentication{ + Enabled: false, + }, + }, + { + name: "OIDC not enabled", + auth: &Authentication{ + Enabled: true, + Modes: []AuthMode{util.SCRAMSHA256}, + }, + }, + { + name: "OIDC cannot be only authentication mode enabled", + auth: &Authentication{ + Enabled: true, + Modes: []AuthMode{util.OIDC}, + }, + expectedErrorMessage: "OIDC authentication cannot be used as the only authentication mechanism", + }, + { + name: "Agent authentication mode not specified, but required", + auth: &Authentication{ + Enabled: true, + Modes: []AuthMode{util.OIDC, util.SCRAMSHA256}, + }, + expectedErrorMessage: "spec.security.authentication.agents.mode must be specified if more than one entry is present in spec.security.authentication.modes", + }, + { + name: "OIDC enabled but without provider configs", + auth: &Authentication{ + Enabled: true, + Agents: AgentAuthentication{Mode: util.SCRAMSHA256}, + Modes: []AuthMode{util.OIDC, util.SCRAMSHA256}, + }, + expectedErrorMessage: "At least one OIDC provider config needs to be specified when OIDC authentication is enabled", + }, + { + name: "Multiple non unique configuration names", + auth: &Authentication{ + Enabled: true, + Agents: AgentAuthentication{Mode: util.SCRAMSHA256}, + Modes: []AuthMode{util.OIDC, util.SCRAMSHA256}, + OIDCProviderConfigs: []OIDCProviderConfig{ + { + ConfigurationName: "provider", + IssuerURI: "https://example1.com", + AuthorizationMethod: OIDCAuthorizationMethodWorkforceIdentityFederation, + ClientId: "clientId1", + }, + { + ConfigurationName: "provider", + IssuerURI: "https://example2.com", + AuthorizationMethod: OIDCAuthorizationMethodWorkforceIdentityFederation, + ClientId: "clientId2", + }, + }, + }, + expectedErrorMessage: "OIDC provider config name provider is not unique", + }, + { + name: "Multiple Workforce Identity Federation configs", + auth: &Authentication{ + Enabled: true, + Agents: AgentAuthentication{Mode: util.SCRAMSHA256}, + Modes: []AuthMode{util.OIDC, util.SCRAMSHA256}, + OIDCProviderConfigs: []OIDCProviderConfig{ + { + ConfigurationName: "test-provider1", + IssuerURI: "https://example1.com", + AuthorizationMethod: OIDCAuthorizationMethodWorkforceIdentityFederation, + ClientId: "clientId1", + }, + { + ConfigurationName: "test-provider2", + IssuerURI: "https://example2.com", + AuthorizationMethod: OIDCAuthorizationMethodWorkforceIdentityFederation, + ClientId: "clientId2", + }, + }, + }, + expectedErrorMessage: "Only one OIDC provider config can be configured with Workforce Identity Federation. The following configs are configured with Workforce Identity Federation: test-provider1, test-provider2", + }, + { + name: "Invalid issuer URI", + auth: &Authentication{ + Enabled: true, + Agents: AgentAuthentication{Mode: util.SCRAMSHA256}, + Modes: []AuthMode{util.OIDC, util.SCRAMSHA256}, + OIDCProviderConfigs: []OIDCProviderConfig{ + { + ConfigurationName: "test-provider", + IssuerURI: "invalid-uri", + }, + }, + }, + expectedErrorMessage: "Invalid IssuerURI in OIDC provider config \"test-provider\"", + }, + // TODO fix validation, we should not return warnings immediately, only add them to the result + { + name: "Non-HTTPS issuer URI - warning", + auth: &Authentication{ + Enabled: true, + Agents: AgentAuthentication{Mode: util.SCRAMSHA256}, + Modes: []AuthMode{util.OIDC, util.SCRAMSHA256}, + OIDCProviderConfigs: []OIDCProviderConfig{ + { + ConfigurationName: "test-provider", + IssuerURI: "http://example.com", + }, + }, + }, + expectedWarning: "IssuerURI in OIDC provider config \"test-provider\" in not secure endpoint", + }, + { + name: "Workforce Identity Federation without ClientId", + auth: &Authentication{ + Enabled: true, + Agents: AgentAuthentication{Mode: util.SCRAMSHA256}, + Modes: []AuthMode{util.OIDC, util.SCRAMSHA256}, + OIDCProviderConfigs: []OIDCProviderConfig{ + { + ConfigurationName: "test-provider", + IssuerURI: "https://example.com", + AuthorizationMethod: OIDCAuthorizationMethodWorkforceIdentityFederation, + }, + }, + }, + expectedErrorMessage: "ClientId has to be specified in OIDC provider config \"test-provider\" with Workforce Identity Federation", + }, + { + name: "Workload Identity Federation with ClientId - warning", + auth: &Authentication{ + Enabled: true, + Agents: AgentAuthentication{Mode: util.SCRAMSHA256}, + Modes: []AuthMode{util.OIDC, util.SCRAMSHA256}, + OIDCProviderConfigs: []OIDCProviderConfig{ + { + ConfigurationName: "test-provider", + IssuerURI: "https://example.com", + AuthorizationMethod: OIDCAuthorizationMethodWorkloadIdentityFederation, + ClientId: "clientId", + }, + }, + }, + expectedWarning: "ClientId will be ignored in OIDC provider config \"test-provider\" with Workload Identity Federation", + }, + { + name: "Workload Identity Federation with RequestedScopes - warning", + auth: &Authentication{ + Enabled: true, + Agents: AgentAuthentication{Mode: util.SCRAMSHA256}, + Modes: []AuthMode{util.OIDC, util.SCRAMSHA256}, + OIDCProviderConfigs: []OIDCProviderConfig{ + { + ConfigurationName: "test-provider", + IssuerURI: "https://example.com", + AuthorizationMethod: OIDCAuthorizationMethodWorkloadIdentityFederation, + RequestedScopes: []string{"openid", "email"}, + }, + }, + }, + expectedWarning: "RequestedScopes will be ignored in OIDC provider config \"test-provider\" with Workload Identity Federation", + }, + { + name: "Group Membership authorization without GroupsClaim", + auth: &Authentication{ + Enabled: true, + Agents: AgentAuthentication{Mode: util.SCRAMSHA256}, + Modes: []AuthMode{util.OIDC, util.SCRAMSHA256}, + OIDCProviderConfigs: []OIDCProviderConfig{ + { + ConfigurationName: "test-provider1", + IssuerURI: "https://example.com", + AuthorizationType: OIDCAuthorizationTypeGroupMembership, + GroupsClaim: "groups", + }, + { + ConfigurationName: "test-provider2", + IssuerURI: "https://example.com", + AuthorizationType: OIDCAuthorizationTypeGroupMembership, + }, + }, + }, + expectedErrorMessage: "GroupsClaim has to be specified in OIDC provider config \"test-provider2\" when using Group Membership authorization", + }, + { + name: "User ID authorization with GroupsClaim - warning", + auth: &Authentication{ + Enabled: true, + Agents: AgentAuthentication{Mode: util.SCRAMSHA256}, + Modes: []AuthMode{util.OIDC, util.SCRAMSHA256}, + OIDCProviderConfigs: []OIDCProviderConfig{ + { + ConfigurationName: "test-provider1", + IssuerURI: "https://example.com", + AuthorizationType: OIDCAuthorizationTypeUserID, + GroupsClaim: "groups", + UserClaim: "sub", + }, + { + ConfigurationName: "test-provider2", + IssuerURI: "https://example.com", + AuthorizationType: OIDCAuthorizationTypeUserID, + UserClaim: "sub", + }, + }, + }, + expectedWarning: "GroupsClaim will be ignored in OIDC provider config \"test-provider1\" when using User ID authorization", + }, + { + name: "Valid OIDC configuration", + auth: &Authentication{ + Enabled: true, + Agents: AgentAuthentication{Mode: util.MONGODBCR}, + Modes: []AuthMode{util.OIDC, util.MONGODBCR}, + OIDCProviderConfigs: []OIDCProviderConfig{ + { + ConfigurationName: "test-provider1", + IssuerURI: "https://example.com", + AuthorizationType: OIDCAuthorizationTypeGroupMembership, + GroupsClaim: "groups", + }, + { + ConfigurationName: "test-provider2", + IssuerURI: "https://example.com", + AuthorizationType: OIDCAuthorizationTypeGroupMembership, + GroupsClaim: "groups", + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rs := NewReplicaSetBuilder(). + SetSecurityTLSEnabled(). + Build() + + rs.Spec.CloudManagerConfig = &PrivateCloudConfig{ + ConfigMapRef: ConfigMapRef{Name: "cloud-manager"}, + } + rs.Spec.Security.Authentication = tt.auth + + err := rs.ProcessValidationsOnReconcile(nil) + + if tt.expectedErrorMessage != "" { + assert.NotNil(t, err) + assert.Equal(t, tt.expectedErrorMessage, err.Error()) + } else { + assert.Nil(t, err) + } + + if tt.expectedWarning != "" { + warnings := rs.GetStatusWarnings() + assert.Contains(t, warnings, tt.expectedWarning) + } + }) + } +} diff --git a/config/crd/bases/mongodb.com_mongodb.yaml b/config/crd/bases/mongodb.com_mongodb.yaml index d93468b13..33115441b 100644 --- a/config/crd/bases/mongodb.com_mongodb.yaml +++ b/config/crd/bases/mongodb.com_mongodb.yaml @@ -1557,7 +1557,7 @@ spec: type: string configurationName: description: |- - TODO add proper validation + TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) diff --git a/config/crd/bases/mongodb.com_mongodbmulticluster.yaml b/config/crd/bases/mongodb.com_mongodbmulticluster.yaml index f9fed2293..28087ec50 100644 --- a/config/crd/bases/mongodb.com_mongodbmulticluster.yaml +++ b/config/crd/bases/mongodb.com_mongodbmulticluster.yaml @@ -817,7 +817,7 @@ spec: type: string configurationName: description: |- - TODO add proper validation + TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) diff --git a/config/crd/bases/mongodb.com_opsmanagers.yaml b/config/crd/bases/mongodb.com_opsmanagers.yaml index adac7f2ae..e54059ce5 100644 --- a/config/crd/bases/mongodb.com_opsmanagers.yaml +++ b/config/crd/bases/mongodb.com_opsmanagers.yaml @@ -879,7 +879,7 @@ spec: type: string configurationName: description: |- - TODO add proper validation + TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) diff --git a/helm_chart/crds/mongodb.com_mongodb.yaml b/helm_chart/crds/mongodb.com_mongodb.yaml index d93468b13..33115441b 100644 --- a/helm_chart/crds/mongodb.com_mongodb.yaml +++ b/helm_chart/crds/mongodb.com_mongodb.yaml @@ -1557,7 +1557,7 @@ spec: type: string configurationName: description: |- - TODO add proper validation + TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) diff --git a/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml b/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml index f9fed2293..28087ec50 100644 --- a/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml +++ b/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml @@ -817,7 +817,7 @@ spec: type: string configurationName: description: |- - TODO add proper validation + TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) diff --git a/helm_chart/crds/mongodb.com_opsmanagers.yaml b/helm_chart/crds/mongodb.com_opsmanagers.yaml index adac7f2ae..e54059ce5 100644 --- a/helm_chart/crds/mongodb.com_opsmanagers.yaml +++ b/helm_chart/crds/mongodb.com_opsmanagers.yaml @@ -879,7 +879,7 @@ spec: type: string configurationName: description: |- - TODO add proper validation + TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) diff --git a/pkg/util/util.go b/pkg/util/util.go index ef2a8a654..f941b4bb7 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -6,6 +6,7 @@ import ( "encoding/gob" "encoding/hex" "fmt" + "net/url" "regexp" "strings" "time" @@ -184,3 +185,9 @@ func TransformToMap[T any, K comparable, V any](objs []T, f func(obj T, idx int) } return result } + +// IsURL checks if the given string is a valid URL and returns the parsed URL if valid. +func IsURL(str string) (bool, *url.URL) { + u, err := url.Parse(str) + return err == nil && u.Scheme != "" && u.Host != "", u +} diff --git a/public/crds.yaml b/public/crds.yaml index 68ee6ff03..ca76be53b 100644 --- a/public/crds.yaml +++ b/public/crds.yaml @@ -1557,7 +1557,7 @@ spec: type: string configurationName: description: |- - TODO add proper validation + TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) @@ -4191,7 +4191,7 @@ spec: type: string configurationName: description: |- - TODO add proper validation + TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) @@ -5580,7 +5580,7 @@ spec: type: string configurationName: description: |- - TODO add proper validation + TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) From 8cba1c1a7ad5d2b543999e221519f1c31ef1ca6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kara=C5=9B?= Date: Sun, 27 Apr 2025 16:40:23 +0200 Subject: [PATCH 03/13] Add URL test validation --- api/v1/mdb/mongodb_types.go | 1 - pkg/util/util_test.go | 80 +++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/api/v1/mdb/mongodb_types.go b/api/v1/mdb/mongodb_types.go index 31c3ee3f9..a12933875 100644 --- a/api/v1/mdb/mongodb_types.go +++ b/api/v1/mdb/mongodb_types.go @@ -1072,7 +1072,6 @@ type OIDCProviderConfig struct { // +kubebuilder:validation:Pattern:"^[a-zA-Z0-9-_]+$" ConfigurationName string `json:"configurationName"` - // TODO add URI validation // Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider // Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. IssuerURI string `json:"issuerURI"` diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index 00548660b..7ffe59f80 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -2,6 +2,7 @@ package util import ( "fmt" + "net/url" "testing" "github.com/stretchr/testify/assert" @@ -197,6 +198,85 @@ func TestTransformToMap(t *testing.T) { })) } +// TestIsURL tests the IsURL function with various inputs. +// +//goland:noinspection HttpUrlsUsage +func TestIsURL(t *testing.T) { + tests := []struct { + name string + input string + isValid bool + checkURL func(*url.URL) bool + }{ + { + name: "valid http URL", + input: "http://example.com", + isValid: true, + checkURL: func(u *url.URL) bool { + return u.Scheme == "http" && u.Host == "example.com" + }, + }, + { + name: "valid https URL with path", + input: "https://example.com/path", + isValid: true, + checkURL: func(u *url.URL) bool { + return u.Scheme == "https" && u.Host == "example.com" && u.Path == "/path" + }, + }, + { + name: "valid URL with port", + input: "http://example.com:8080", + isValid: true, + checkURL: func(u *url.URL) bool { + return u.Host == "example.com:8080" + }, + }, + { + name: "missing scheme", + input: "example.com", + isValid: false, + }, + { + name: "missing host", + input: "http://", + isValid: false, + }, + { + name: "empty string", + input: "", + isValid: false, + }, + { + name: "invalid URL", + input: ":invalid-url", + isValid: false, + }, + { + name: "file scheme", + input: "file:///path/to/file", + isValid: true, + checkURL: func(u *url.URL) bool { + return u.Scheme == "file" && u.Path == "/path/to/file" + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + valid, u := IsURL(tt.input) + assert.Equal(t, tt.isValid, valid) + + if tt.isValid { + assert.NotNil(t, u) + if tt.checkURL != nil { + assert.True(t, tt.checkURL(u)) + } + } + }) + } +} + func pair(left, right identifiable.Identifiable) []identifiable.Identifiable { return []identifiable.Identifiable{left, right} } From 25288928c1103f4c5555ac313142e96adb0f8b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kara=C5=9B?= Date: Sun, 27 Apr 2025 16:48:22 +0200 Subject: [PATCH 04/13] Fixed MDB Multi code --- api/v1/mdbmulti/mongodbmulti_validation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1/mdbmulti/mongodbmulti_validation.go b/api/v1/mdbmulti/mongodbmulti_validation.go index be2e3cae9..ff33ed781 100644 --- a/api/v1/mdbmulti/mongodbmulti_validation.go +++ b/api/v1/mdbmulti/mongodbmulti_validation.go @@ -53,7 +53,7 @@ func (m *MongoDBMultiCluster) RunValidations(old *MongoDBMultiCluster) []v1.Vali var validationResults []v1.ValidationResult - for _, validator := range mdbv1.CommonValidators() { + for _, validator := range mdbv1.CommonValidators(m.Spec.DbCommonSpec) { res := validator(m.Spec.DbCommonSpec) if res.Level > 0 { validationResults = append(validationResults, res) From 7a53fd7f8d426e7ce60c524e0903708cfc3cc686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kara=C5=9B?= Date: Sun, 27 Apr 2025 17:20:54 +0200 Subject: [PATCH 05/13] Fixed unit tests + CRD generation --- config/crd/bases/mongodb.com_mongodb.yaml | 1 - config/crd/bases/mongodb.com_mongodbmulticluster.yaml | 1 - config/crd/bases/mongodb.com_opsmanagers.yaml | 1 - helm_chart/crds/mongodb.com_mongodb.yaml | 1 - helm_chart/crds/mongodb.com_mongodbmulticluster.yaml | 1 - helm_chart/crds/mongodb.com_opsmanagers.yaml | 1 - pkg/util/util_test.go | 5 +---- public/crds.yaml | 3 --- 8 files changed, 1 insertion(+), 13 deletions(-) diff --git a/config/crd/bases/mongodb.com_mongodb.yaml b/config/crd/bases/mongodb.com_mongodb.yaml index 33115441b..bdf8bc3f1 100644 --- a/config/crd/bases/mongodb.com_mongodb.yaml +++ b/config/crd/bases/mongodb.com_mongodb.yaml @@ -1572,7 +1572,6 @@ spec: type: string issuerURI: description: |- - TODO add URI validation Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. type: string diff --git a/config/crd/bases/mongodb.com_mongodbmulticluster.yaml b/config/crd/bases/mongodb.com_mongodbmulticluster.yaml index 28087ec50..f0b64535e 100644 --- a/config/crd/bases/mongodb.com_mongodbmulticluster.yaml +++ b/config/crd/bases/mongodb.com_mongodbmulticluster.yaml @@ -832,7 +832,6 @@ spec: type: string issuerURI: description: |- - TODO add URI validation Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. type: string diff --git a/config/crd/bases/mongodb.com_opsmanagers.yaml b/config/crd/bases/mongodb.com_opsmanagers.yaml index e54059ce5..4206080be 100644 --- a/config/crd/bases/mongodb.com_opsmanagers.yaml +++ b/config/crd/bases/mongodb.com_opsmanagers.yaml @@ -894,7 +894,6 @@ spec: type: string issuerURI: description: |- - TODO add URI validation Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. type: string diff --git a/helm_chart/crds/mongodb.com_mongodb.yaml b/helm_chart/crds/mongodb.com_mongodb.yaml index 33115441b..bdf8bc3f1 100644 --- a/helm_chart/crds/mongodb.com_mongodb.yaml +++ b/helm_chart/crds/mongodb.com_mongodb.yaml @@ -1572,7 +1572,6 @@ spec: type: string issuerURI: description: |- - TODO add URI validation Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. type: string diff --git a/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml b/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml index 28087ec50..f0b64535e 100644 --- a/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml +++ b/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml @@ -832,7 +832,6 @@ spec: type: string issuerURI: description: |- - TODO add URI validation Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. type: string diff --git a/helm_chart/crds/mongodb.com_opsmanagers.yaml b/helm_chart/crds/mongodb.com_opsmanagers.yaml index e54059ce5..4206080be 100644 --- a/helm_chart/crds/mongodb.com_opsmanagers.yaml +++ b/helm_chart/crds/mongodb.com_opsmanagers.yaml @@ -894,7 +894,6 @@ spec: type: string issuerURI: description: |- - TODO add URI validation Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. type: string diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index 7ffe59f80..514bee8c1 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -255,10 +255,7 @@ func TestIsURL(t *testing.T) { { name: "file scheme", input: "file:///path/to/file", - isValid: true, - checkURL: func(u *url.URL) bool { - return u.Scheme == "file" && u.Path == "/path/to/file" - }, + isValid: false, }, } diff --git a/public/crds.yaml b/public/crds.yaml index ca76be53b..644df1f69 100644 --- a/public/crds.yaml +++ b/public/crds.yaml @@ -1572,7 +1572,6 @@ spec: type: string issuerURI: description: |- - TODO add URI validation Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. type: string @@ -4206,7 +4205,6 @@ spec: type: string issuerURI: description: |- - TODO add URI validation Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. type: string @@ -5595,7 +5593,6 @@ spec: type: string issuerURI: description: |- - TODO add URI validation Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. type: string From 8b342228ce178086aa02bea52768b8e8ecaa07ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kara=C5=9B?= Date: Tue, 29 Apr 2025 09:49:54 +0200 Subject: [PATCH 06/13] Fix kubebuilder validation rules --- api/v1/mdb/mongodb_types.go | 27 ++++++++++++------- config/crd/bases/mongodb.com_mongodb.yaml | 5 +++- .../mongodb.com_mongodbmulticluster.yaml | 5 +++- config/crd/bases/mongodb.com_opsmanagers.yaml | 5 +++- helm_chart/crds/mongodb.com_mongodb.yaml | 5 +++- .../crds/mongodb.com_mongodbmulticluster.yaml | 5 +++- helm_chart/crds/mongodb.com_opsmanagers.yaml | 5 +++- public/crds.yaml | 15 ++++++++--- 8 files changed, 53 insertions(+), 19 deletions(-) diff --git a/api/v1/mdb/mongodb_types.go b/api/v1/mdb/mongodb_types.go index a12933875..fc2b9f54d 100644 --- a/api/v1/mdb/mongodb_types.go +++ b/api/v1/mdb/mongodb_types.go @@ -934,6 +934,8 @@ type Authentication struct { // +optional Ldap *Ldap `json:"ldap,omitempty"` + // Configuration for OIDC providers + // +optional OIDCProviderConfigs []OIDCProviderConfig `json:"oidcProviderConfigs,omitempty"` // Agents contains authentication configuration properties for the agents @@ -1063,54 +1065,59 @@ type Ldap struct { } type OIDCProviderConfig struct { - // TODO add proper validation and test it // Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when // creating users and roles for authorization. It is case-sensitive and can only contain the following characters: // - alphanumeric characters (combination of a to z and 0 to 9) // - hyphens (-) // - underscores (_) - // +kubebuilder:validation:Pattern:"^[a-zA-Z0-9-_]+$" + // +kubebuilder:validation:Pattern="^[a-zA-Z0-9-_]+$" + // +kubebuilder:validation:Required ConfigurationName string `json:"configurationName"` // Issuer value provided by your registered IdP application. Using this URI, MongoDB finds an OpenID Provider // Configuration Document, which should be available in the /.wellknown/open-id-configuration endpoint. + // +kubebuilder:validation:Required IssuerURI string `json:"issuerURI"` // Entity that your external identity provider intends the token for. // Enter the audience value from the app you registered with external Identity Provider. + // +kubebuilder:validation:Required Audience string `json:"audience"` // Select GroupMembership to grant authorization based on IdP user group membership, or select UserID to grant // an individual user authorization. + // +kubebuilder:validation:Required AuthorizationType OIDCAuthorizationType `json:"authorizationType"` // The identifier of the claim that includes the user principal identity. // Accept the default value unless your IdP uses a different claim. - // +default:value:sub + // +kubebuilder:default=sub + // +kubebuilder:validation:Required UserClaim string `json:"userClaim"` // The identifier of the claim that includes the principal's IdP user group membership information. // Accept the default value unless your IdP uses a different claim, or you need a custom claim. // Required when selected GroupMembership as the authorization type, ignored otherwise - // +default:value:groups - // +optional - GroupsClaim string `json:"groupsClaim"` + // +kubebuilder:default=groups + // +kubebuilder:validation:Optional + GroupsClaim string `json:"groupsClaim,omitempty"` // Configure single-sign-on for human user access to Ops Manager deployments with Workforce Identity Federation. // For programmatic, application access to Ops Manager deployments use Workload Identity Federation. // Only one Workforce Identity Federation IdP can be configured per MongoDB resource + // +kubebuilder:validation:Required AuthorizationMethod OIDCAuthorizationMethod `json:"authorizationMethod"` // Unique identifier for your registered application. Enter the clientId value from the app you // registered with an external Identity Provider. // Required when selected Workforce Identity Federation authorization method - // +optional - ClientId string `json:"clientId"` + // +kubebuilder:validation:Optional + ClientId string `json:"clientId,omitempty"` // Tokens that give users permission to request data from the authorization endpoint. // Only used for Workforce Identity Federation authorization method - // +optional - RequestedScopes []string `json:"requestedScopes"` + // +kubebuilder:validation:Optional + RequestedScopes []string `json:"requestedScopes,omitempty"` } // +kubebuilder:validation:Enum=GroupMembership;UserID diff --git a/config/crd/bases/mongodb.com_mongodb.yaml b/config/crd/bases/mongodb.com_mongodb.yaml index bdf8bc3f1..8b5ffc33e 100644 --- a/config/crd/bases/mongodb.com_mongodb.yaml +++ b/config/crd/bases/mongodb.com_mongodb.yaml @@ -1525,6 +1525,7 @@ spec: type: string type: array oidcProviderConfigs: + description: Configuration for OIDC providers items: properties: audience: @@ -1557,14 +1558,15 @@ spec: type: string configurationName: description: |- - TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) - hyphens (-) - underscores (_) + pattern: ^[a-zA-Z0-9-_]+$ type: string groupsClaim: + default: groups description: |- The identifier of the claim that includes the principal's IdP user group membership information. Accept the default value unless your IdP uses a different claim, or you need a custom claim. @@ -1583,6 +1585,7 @@ spec: type: string type: array userClaim: + default: sub description: |- The identifier of the claim that includes the user principal identity. Accept the default value unless your IdP uses a different claim. diff --git a/config/crd/bases/mongodb.com_mongodbmulticluster.yaml b/config/crd/bases/mongodb.com_mongodbmulticluster.yaml index f0b64535e..523238eb6 100644 --- a/config/crd/bases/mongodb.com_mongodbmulticluster.yaml +++ b/config/crd/bases/mongodb.com_mongodbmulticluster.yaml @@ -785,6 +785,7 @@ spec: type: string type: array oidcProviderConfigs: + description: Configuration for OIDC providers items: properties: audience: @@ -817,14 +818,15 @@ spec: type: string configurationName: description: |- - TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) - hyphens (-) - underscores (_) + pattern: ^[a-zA-Z0-9-_]+$ type: string groupsClaim: + default: groups description: |- The identifier of the claim that includes the principal's IdP user group membership information. Accept the default value unless your IdP uses a different claim, or you need a custom claim. @@ -843,6 +845,7 @@ spec: type: string type: array userClaim: + default: sub description: |- The identifier of the claim that includes the user principal identity. Accept the default value unless your IdP uses a different claim. diff --git a/config/crd/bases/mongodb.com_opsmanagers.yaml b/config/crd/bases/mongodb.com_opsmanagers.yaml index 4206080be..a250a4871 100644 --- a/config/crd/bases/mongodb.com_opsmanagers.yaml +++ b/config/crd/bases/mongodb.com_opsmanagers.yaml @@ -847,6 +847,7 @@ spec: type: string type: array oidcProviderConfigs: + description: Configuration for OIDC providers items: properties: audience: @@ -879,14 +880,15 @@ spec: type: string configurationName: description: |- - TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) - hyphens (-) - underscores (_) + pattern: ^[a-zA-Z0-9-_]+$ type: string groupsClaim: + default: groups description: |- The identifier of the claim that includes the principal's IdP user group membership information. Accept the default value unless your IdP uses a different claim, or you need a custom claim. @@ -905,6 +907,7 @@ spec: type: string type: array userClaim: + default: sub description: |- The identifier of the claim that includes the user principal identity. Accept the default value unless your IdP uses a different claim. diff --git a/helm_chart/crds/mongodb.com_mongodb.yaml b/helm_chart/crds/mongodb.com_mongodb.yaml index bdf8bc3f1..8b5ffc33e 100644 --- a/helm_chart/crds/mongodb.com_mongodb.yaml +++ b/helm_chart/crds/mongodb.com_mongodb.yaml @@ -1525,6 +1525,7 @@ spec: type: string type: array oidcProviderConfigs: + description: Configuration for OIDC providers items: properties: audience: @@ -1557,14 +1558,15 @@ spec: type: string configurationName: description: |- - TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) - hyphens (-) - underscores (_) + pattern: ^[a-zA-Z0-9-_]+$ type: string groupsClaim: + default: groups description: |- The identifier of the claim that includes the principal's IdP user group membership information. Accept the default value unless your IdP uses a different claim, or you need a custom claim. @@ -1583,6 +1585,7 @@ spec: type: string type: array userClaim: + default: sub description: |- The identifier of the claim that includes the user principal identity. Accept the default value unless your IdP uses a different claim. diff --git a/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml b/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml index f0b64535e..523238eb6 100644 --- a/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml +++ b/helm_chart/crds/mongodb.com_mongodbmulticluster.yaml @@ -785,6 +785,7 @@ spec: type: string type: array oidcProviderConfigs: + description: Configuration for OIDC providers items: properties: audience: @@ -817,14 +818,15 @@ spec: type: string configurationName: description: |- - TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) - hyphens (-) - underscores (_) + pattern: ^[a-zA-Z0-9-_]+$ type: string groupsClaim: + default: groups description: |- The identifier of the claim that includes the principal's IdP user group membership information. Accept the default value unless your IdP uses a different claim, or you need a custom claim. @@ -843,6 +845,7 @@ spec: type: string type: array userClaim: + default: sub description: |- The identifier of the claim that includes the user principal identity. Accept the default value unless your IdP uses a different claim. diff --git a/helm_chart/crds/mongodb.com_opsmanagers.yaml b/helm_chart/crds/mongodb.com_opsmanagers.yaml index 4206080be..a250a4871 100644 --- a/helm_chart/crds/mongodb.com_opsmanagers.yaml +++ b/helm_chart/crds/mongodb.com_opsmanagers.yaml @@ -847,6 +847,7 @@ spec: type: string type: array oidcProviderConfigs: + description: Configuration for OIDC providers items: properties: audience: @@ -879,14 +880,15 @@ spec: type: string configurationName: description: |- - TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) - hyphens (-) - underscores (_) + pattern: ^[a-zA-Z0-9-_]+$ type: string groupsClaim: + default: groups description: |- The identifier of the claim that includes the principal's IdP user group membership information. Accept the default value unless your IdP uses a different claim, or you need a custom claim. @@ -905,6 +907,7 @@ spec: type: string type: array userClaim: + default: sub description: |- The identifier of the claim that includes the user principal identity. Accept the default value unless your IdP uses a different claim. diff --git a/public/crds.yaml b/public/crds.yaml index 644df1f69..c47fde748 100644 --- a/public/crds.yaml +++ b/public/crds.yaml @@ -1525,6 +1525,7 @@ spec: type: string type: array oidcProviderConfigs: + description: Configuration for OIDC providers items: properties: audience: @@ -1557,14 +1558,15 @@ spec: type: string configurationName: description: |- - TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) - hyphens (-) - underscores (_) + pattern: ^[a-zA-Z0-9-_]+$ type: string groupsClaim: + default: groups description: |- The identifier of the claim that includes the principal's IdP user group membership information. Accept the default value unless your IdP uses a different claim, or you need a custom claim. @@ -1583,6 +1585,7 @@ spec: type: string type: array userClaim: + default: sub description: |- The identifier of the claim that includes the user principal identity. Accept the default value unless your IdP uses a different claim. @@ -4158,6 +4161,7 @@ spec: type: string type: array oidcProviderConfigs: + description: Configuration for OIDC providers items: properties: audience: @@ -4190,14 +4194,15 @@ spec: type: string configurationName: description: |- - TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) - hyphens (-) - underscores (_) + pattern: ^[a-zA-Z0-9-_]+$ type: string groupsClaim: + default: groups description: |- The identifier of the claim that includes the principal's IdP user group membership information. Accept the default value unless your IdP uses a different claim, or you need a custom claim. @@ -4216,6 +4221,7 @@ spec: type: string type: array userClaim: + default: sub description: |- The identifier of the claim that includes the user principal identity. Accept the default value unless your IdP uses a different claim. @@ -5546,6 +5552,7 @@ spec: type: string type: array oidcProviderConfigs: + description: Configuration for OIDC providers items: properties: audience: @@ -5578,14 +5585,15 @@ spec: type: string configurationName: description: |- - TODO add proper validation and test it Unique label that identifies this configuration. This label is visible to your Ops Manager users and is used when creating users and roles for authorization. It is case-sensitive and can only contain the following characters: - alphanumeric characters (combination of a to z and 0 to 9) - hyphens (-) - underscores (_) + pattern: ^[a-zA-Z0-9-_]+$ type: string groupsClaim: + default: groups description: |- The identifier of the claim that includes the principal's IdP user group membership information. Accept the default value unless your IdP uses a different claim, or you need a custom claim. @@ -5604,6 +5612,7 @@ spec: type: string type: array userClaim: + default: sub description: |- The identifier of the claim that includes the user principal identity. Accept the default value unless your IdP uses a different claim. From 1cbe97a4586028ecd2e37b8e23549a41119222fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kara=C5=9B?= Date: Wed, 30 Apr 2025 09:16:43 +0200 Subject: [PATCH 07/13] Fixes for util.ParseURL --- api/v1/mdb/mongodb_validation.go | 8 ++-- pkg/util/util.go | 26 +++++++++-- pkg/util/util_test.go | 79 +++++++++++++------------------- 3 files changed, 60 insertions(+), 53 deletions(-) diff --git a/api/v1/mdb/mongodb_validation.go b/api/v1/mdb/mongodb_validation.go index a91f983bf..171974b79 100644 --- a/api/v1/mdb/mongodb_validation.go +++ b/api/v1/mdb/mongodb_validation.go @@ -189,13 +189,13 @@ func oidcProviderConfigsSingleWorkforceIdentityFederationValidation(configs []OI func oidcProviderConfigIssuerURIValidator(config OIDCProviderConfig) func(DbCommonSpec) v1.ValidationResult { return func(_ DbCommonSpec) v1.ValidationResult { - ok, url := util.IsURL(config.IssuerURI) - if !ok { - return v1.ValidationError("Invalid IssuerURI in OIDC provider config %q", config.ConfigurationName) + url, err := util.ParseURL(config.IssuerURI) + if err != nil { + return v1.ValidationError("Invalid IssuerURI in OIDC provider config %q: %s", config.ConfigurationName, err.Error()) } if url.Scheme != "https" { - return v1.ValidationWarning("IssuerURI in OIDC provider config %q in not secure endpoint", config.ConfigurationName) + return v1.ValidationWarning("IssuerURI %s in OIDC provider config %q in not secure endpoint", url.String(), config.ConfigurationName) } return v1.ValidationSuccess() diff --git a/pkg/util/util.go b/pkg/util/util.go index f941b4bb7..13d6b5ac0 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -186,8 +186,28 @@ func TransformToMap[T any, K comparable, V any](objs []T, f func(obj T, idx int) return result } -// IsURL checks if the given string is a valid URL and returns the parsed URL if valid. -func IsURL(str string) (bool, *url.URL) { +// ParseURL checks if the given string is a valid URL and returns the parsed URL if valid. +func ParseURL(str string) (*url.URL, error) { + if strings.TrimSpace(str) == "" { + return nil, fmt.Errorf("empty URL") + } + u, err := url.Parse(str) - return err == nil && u.Scheme != "" && u.Host != "", u + if err != nil { + return nil, fmt.Errorf("invalid URL: %w", err) + } + + if u.Scheme == "" { + return nil, fmt.Errorf("missing URL scheme: %s", str) + } + + if u.Scheme != "http" && u.Scheme != "https" { + return nil, fmt.Errorf("invalid URL scheme (http or https): %s", str) + } + + if u.Host == "" { + return nil, fmt.Errorf("missing URL host: %s", str) + } + + return u, nil } diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index 514bee8c1..cd639d41c 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -2,10 +2,10 @@ package util import ( "fmt" - "net/url" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/mongodb/mongodb-kubernetes/pkg/util/identifiable" ) @@ -198,77 +198,64 @@ func TestTransformToMap(t *testing.T) { })) } -// TestIsURL tests the IsURL function with various inputs. +// TestIsURL tests the ParseURL function with various inputs. // //goland:noinspection HttpUrlsUsage func TestIsURL(t *testing.T) { tests := []struct { - name string - input string - isValid bool - checkURL func(*url.URL) bool + name string + input string + expectedErrorString string }{ { - name: "valid http URL", - input: "http://example.com", - isValid: true, - checkURL: func(u *url.URL) bool { - return u.Scheme == "http" && u.Host == "example.com" - }, + name: "valid http URL", + input: "http://example.com", }, { - name: "valid https URL with path", - input: "https://example.com/path", - isValid: true, - checkURL: func(u *url.URL) bool { - return u.Scheme == "https" && u.Host == "example.com" && u.Path == "/path" - }, + name: "valid https URL with path", + input: "https://example.com/path", }, { - name: "valid URL with port", - input: "http://example.com:8080", - isValid: true, - checkURL: func(u *url.URL) bool { - return u.Host == "example.com:8080" - }, + name: "valid URL with port", + input: "http://example.com:8080", }, { - name: "missing scheme", - input: "example.com", - isValid: false, + name: "missing scheme", + input: "example.com", + expectedErrorString: "missing URL scheme: example.com", }, { - name: "missing host", - input: "http://", - isValid: false, + name: "missing host", + input: "http://", + expectedErrorString: "missing URL host: http://", }, { - name: "empty string", - input: "", - isValid: false, + name: "empty string", + input: "", + expectedErrorString: "empty URL", }, { - name: "invalid URL", - input: ":invalid-url", - isValid: false, + name: "invalid URL", + input: ":invalid-url", + expectedErrorString: "invalid URL: parse \":invalid-url\": missing protocol scheme", }, { - name: "file scheme", - input: "file:///path/to/file", - isValid: false, + name: "file scheme", + input: "file://path/to/file", + expectedErrorString: "invalid URL scheme (http or https): file://path/to/file", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - valid, u := IsURL(tt.input) - assert.Equal(t, tt.isValid, valid) - - if tt.isValid { + u, err := ParseURL(tt.input) + if tt.expectedErrorString != "" { + require.Error(t, err) + assert.Equal(t, tt.expectedErrorString, err.Error()) + assert.Nil(t, u) + } else { + assert.NoError(t, err) assert.NotNil(t, u) - if tt.checkURL != nil { - assert.True(t, tt.checkURL(u)) - } } }) } From e4cfb11b677ce88cc4cd635e59990df8bbc2d641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kara=C5=9B?= Date: Wed, 30 Apr 2025 09:51:53 +0200 Subject: [PATCH 08/13] Unit test fixes --- api/v1/mdb/mongodb_validation_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/api/v1/mdb/mongodb_validation_test.go b/api/v1/mdb/mongodb_validation_test.go index 4a3db9da4..4529ef2c4 100644 --- a/api/v1/mdb/mongodb_validation_test.go +++ b/api/v1/mdb/mongodb_validation_test.go @@ -306,9 +306,8 @@ func TestOIDCAuthValidation(t *testing.T) { }, }, }, - expectedErrorMessage: "Invalid IssuerURI in OIDC provider config \"test-provider\"", + expectedErrorMessage: "Invalid IssuerURI in OIDC provider config \"test-provider\": missing URL scheme: invalid-uri", }, - // TODO fix validation, we should not return warnings immediately, only add them to the result { name: "Non-HTTPS issuer URI - warning", auth: &Authentication{ @@ -322,7 +321,7 @@ func TestOIDCAuthValidation(t *testing.T) { }, }, }, - expectedWarning: "IssuerURI in OIDC provider config \"test-provider\" in not secure endpoint", + expectedWarning: "IssuerURI http://example.com in OIDC provider config \"test-provider\" in not secure endpoint", }, { name: "Workforce Identity Federation without ClientId", From e53397691a1ba391f4af835763b1aaac076ebc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kara=C5=9B?= Date: Mon, 5 May 2025 10:26:11 +0200 Subject: [PATCH 09/13] Review fixes --- api/v1/mdb/mongodb_validation.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/api/v1/mdb/mongodb_validation.go b/api/v1/mdb/mongodb_validation.go index 171974b79..5f9da2bab 100644 --- a/api/v1/mdb/mongodb_validation.go +++ b/api/v1/mdb/mongodb_validation.go @@ -2,7 +2,6 @@ package mdb import ( "errors" - "fmt" "strings" "k8s.io/apimachinery/pkg/runtime" @@ -178,9 +177,9 @@ func oidcProviderConfigsSingleWorkforceIdentityFederationValidation(configs []OI } if len(workforceIdentityFederationConfigs) > 1 { - msg := fmt.Sprintf("Only one OIDC provider config can be configured with Workforce Identity Federation. "+ - "The following configs are configured with Workforce Identity Federation: %s", strings.Join(workforceIdentityFederationConfigs, ", ")) - return v1.ValidationError("%s", msg) + configsSeparatedString := strings.Join(workforceIdentityFederationConfigs, ", ") + return v1.ValidationError("Only one OIDC provider config can be configured with Workforce Identity Federation. "+ + "The following configs are configured with Workforce Identity Federation: %s", configsSeparatedString) } return v1.ValidationSuccess() From a8306a7ea7844004f6bea037650b087b2d67fcff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kara=C5=9B?= Date: Mon, 5 May 2025 10:49:58 +0200 Subject: [PATCH 10/13] Add one more validation test --- api/v1/mdb/mongodb_validation_test.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/api/v1/mdb/mongodb_validation_test.go b/api/v1/mdb/mongodb_validation_test.go index 4529ef2c4..6f7fcc0ec 100644 --- a/api/v1/mdb/mongodb_validation_test.go +++ b/api/v1/mdb/mongodb_validation_test.go @@ -293,6 +293,32 @@ func TestOIDCAuthValidation(t *testing.T) { }, expectedErrorMessage: "Only one OIDC provider config can be configured with Workforce Identity Federation. The following configs are configured with Workforce Identity Federation: test-provider1, test-provider2", }, + { + name: "Multiple Workload Identity Federation configs", + auth: &Authentication{ + Enabled: true, + Agents: AgentAuthentication{Mode: util.SCRAMSHA256}, + Modes: []AuthMode{util.OIDC, util.SCRAMSHA256}, + OIDCProviderConfigs: []OIDCProviderConfig{ + { + ConfigurationName: "test-provider-workforce1", + IssuerURI: "https://example1.com", + AuthorizationMethod: OIDCAuthorizationMethodWorkforceIdentityFederation, + ClientId: "clientId1", + }, + { + ConfigurationName: "test-provider-workload2", + IssuerURI: "https://example2.com", + AuthorizationMethod: OIDCAuthorizationMethodWorkloadIdentityFederation, + }, + { + ConfigurationName: "test-provider-workload3", + IssuerURI: "https://example3.com", + AuthorizationMethod: OIDCAuthorizationMethodWorkloadIdentityFederation, + }, + }, + }, + }, { name: "Invalid issuer URI", auth: &Authentication{ From 43ac0a48a2520f8dcde1980619680fe807b03626 Mon Sep 17 00:00:00 2001 From: Lucian Tosa <49226451+lucian-tosa@users.noreply.github.com> Date: Thu, 22 May 2025 10:28:55 +0200 Subject: [PATCH 11/13] Update api/v1/mdb/mongodb_types.go Co-authored-by: Anand <13899132+anandsyncs@users.noreply.github.com> --- api/v1/mdb/mongodb_types.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api/v1/mdb/mongodb_types.go b/api/v1/mdb/mongodb_types.go index 27e9fadba..5fc66b6db 100644 --- a/api/v1/mdb/mongodb_types.go +++ b/api/v1/mdb/mongodb_types.go @@ -808,6 +808,11 @@ func (s *Security) IsTLSEnabled() bool { } func (s *Security) IsOIDCEnabled() bool { + if s == nil || s.Authentication == nil || !s.Authentication.Enabled { + return false + } + return s.Authentication.IsOIDCEnabled() +} if s == nil { return false } From 01a93589390578f5513ba649532768ba643dc046 Mon Sep 17 00:00:00 2001 From: Lucian Tosa Date: Thu, 22 May 2025 11:41:26 +0200 Subject: [PATCH 12/13] Add enterprise build validation --- api/v1/mdb/mongodb_types.go | 14 -------------- api/v1/mdb/mongodb_validation.go | 9 +++++++++ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/api/v1/mdb/mongodb_types.go b/api/v1/mdb/mongodb_types.go index 5fc66b6db..58ea251fe 100644 --- a/api/v1/mdb/mongodb_types.go +++ b/api/v1/mdb/mongodb_types.go @@ -813,20 +813,6 @@ func (s *Security) IsOIDCEnabled() bool { } return s.Authentication.IsOIDCEnabled() } - if s == nil { - return false - } - - if s.Authentication == nil { - return false - } - - if !s.Authentication.Enabled { - return false - } - - return s.Authentication.IsOIDCEnabled() -} // GetAgentMechanism returns the authentication mechanism that the agents will be using. // The agents will use X509 if it is the only mechanism specified, otherwise they will use SCRAM if specified diff --git a/api/v1/mdb/mongodb_validation.go b/api/v1/mdb/mongodb_validation.go index 5f9da2bab..a9f07e7b6 100644 --- a/api/v1/mdb/mongodb_validation.go +++ b/api/v1/mdb/mongodb_validation.go @@ -130,6 +130,7 @@ func oidcAuthValidators(db DbCommonSpec) []func(DbCommonSpec) v1.ValidationResul oidcProviderConfigClientIdValidator(config), oidcProviderConfigRequestedScopesValidator(config), oidcProviderConfigAuthorizationTypeValidator(config), + oidcAuthRequiresEnterprise, ) } @@ -245,6 +246,14 @@ func oidcProviderConfigAuthorizationTypeValidator(config OIDCProviderConfig) fun } } +func oidcAuthRequiresEnterprise(d DbCommonSpec) v1.ValidationResult { + authSpec := d.Security.Authentication + if authSpec != nil && authSpec.IsOIDCEnabled() && !strings.HasSuffix(d.Version, "-ent") { + return v1.ValidationError("Cannot enable OIDC authentication with MongoDB Community Builds") + } + return v1.ValidationSuccess() +} + func ldapAuthRequiresEnterprise(d DbCommonSpec) v1.ValidationResult { authSpec := d.Security.Authentication if authSpec != nil && authSpec.IsLDAPEnabled() && !strings.HasSuffix(d.Version, "-ent") { From f90559ecb6c8d35c589932bde7806548130109a4 Mon Sep 17 00:00:00 2001 From: Lucian Tosa Date: Thu, 22 May 2025 11:58:55 +0200 Subject: [PATCH 13/13] Fix unit tests --- api/v1/mdb/mongodb_validation_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/api/v1/mdb/mongodb_validation_test.go b/api/v1/mdb/mongodb_validation_test.go index 6f7fcc0ec..075edada6 100644 --- a/api/v1/mdb/mongodb_validation_test.go +++ b/api/v1/mdb/mongodb_validation_test.go @@ -473,6 +473,7 @@ func TestOIDCAuthValidation(t *testing.T) { t.Run(tt.name, func(t *testing.T) { rs := NewReplicaSetBuilder(). SetSecurityTLSEnabled(). + SetVersion("8.0.5-ent"). Build() rs.Spec.CloudManagerConfig = &PrivateCloudConfig{