Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
125fb34
feat(dex): add option to modify user id claim, skip email_verified vi…
kengou Oct 27, 2025
4874534
fix(api): fix default values
kengou Oct 27, 2025
f7b847a
update org sample
kengou Oct 28, 2025
d2320e3
fix org sample
kengou Oct 28, 2025
a7ae42c
Merge branch 'main' into feat/dex-orgconfig
kengou Oct 28, 2025
7a52ae1
introduce ExtraConfig
kengou Nov 16, 2025
da900f0
Automatic generation of CRD API Docs
cloud-operator-bot[bot] Nov 16, 2025
1e7cec3
Merge branch 'main' into feat/dex-orgconfig
kengou Jan 29, 2026
2290e27
Automatic generation of CRD API Docs
cloud-operator-bot[bot] Jan 29, 2026
969c4cf
Merge branch 'main' into feat/dex-orgconfig
kengou Feb 11, 2026
52ce0df
Update config/samples/organization/demo.yaml
kengou Feb 26, 2026
2d63648
Merge branch 'main' into feat/dex-orgconfig
kengou Mar 6, 2026
74fe8c2
Merge branch 'main' into feat/dex-orgconfig
kengou Mar 27, 2026
9480ff5
fix issues, add test and run generate
kengou Mar 27, 2026
68337c2
Merge branch 'main' into feat/dex-orgconfig
kengou Mar 31, 2026
e816e77
Merge branch 'main' into feat/dex-orgconfig
kengou Apr 2, 2026
2351fc3
Merge branch 'main' into feat/dex-orgconfig
kengou Apr 7, 2026
a714e74
Merge branch 'main' into feat/dex-orgconfig
kengou Apr 16, 2026
061166d
Merge branch 'main' into feat/dex-orgconfig
kengou Apr 19, 2026
a8200c7
Merge branch 'main' into feat/dex-orgconfig
kengou Apr 27, 2026
340f3f5
Merge branch 'main' into feat/dex-orgconfig
kengou May 5, 2026
acb80d3
Automatic generation of CRD API Docs
cloud-operator-bot[bot] May 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions api/v1alpha1/organization_types.go
100644 β†’ 100755
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@ type OIDCConfig struct {
// OAuth2ClientRedirectURIs are a registered set of redirect URIs. When redirecting from the idproxy to
// the client application, the URI requested to redirect to must be contained in this list.
OAuth2ClientRedirectURIs []string `json:"oauth2ClientRedirectURIs,omitempty"`
// ExtraConfig contains additional OIDC configuration for claim mapping and token validation behavior.
ExtraConfig *OIDCExtraConfig `json:"extraConfig,omitempty"`
}

type OIDCExtraConfig struct {
// InsecureSkipEmailVerified if set to true, treats email_verified as true when the claim is absent from the ID token.
// This does not override an explicit email_verified=false. Only enable for providers that omit the claim entirely (e.g. some Okta, EntraID or CloudFoundry configurations).
// +kubebuilder:default:=false
InsecureSkipEmailVerified bool `json:"insecureSkipEmailVerified,omitempty"`
Comment thread
abhijith-darshan marked this conversation as resolved.
// UserIDClaim is the claim to be used as both user ID and username.
// When set, it overrides both UserIDKey and UserNameKey in the dex OIDC connector config.
// +kubebuilder:default:="login_name"
UserIDClaim string `json:"userIDClaim,omitempty"`
}

type SCIMConfig struct {
Expand Down
20 changes: 20 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion charts/manager/crds/greenhouse.sap_catalogs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.0
controller-gen.kubebuilder.io/version: v0.20.1
name: catalogs.greenhouse.sap
spec:
group: greenhouse.sap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.0
controller-gen.kubebuilder.io/version: v0.20.1
name: clusterkubeconfigs.greenhouse.sap
spec:
group: greenhouse.sap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.0
controller-gen.kubebuilder.io/version: v0.20.1
name: clusterplugindefinitions.greenhouse.sap
spec:
group: greenhouse.sap
Expand Down
2 changes: 1 addition & 1 deletion charts/manager/crds/greenhouse.sap_clusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.0
controller-gen.kubebuilder.io/version: v0.20.1
name: clusters.greenhouse.sap
spec:
group: greenhouse.sap
Expand Down
19 changes: 18 additions & 1 deletion charts/manager/crds/greenhouse.sap_organizations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.0
controller-gen.kubebuilder.io/version: v0.20.1
name: organizations.greenhouse.sap
spec:
group: greenhouse.sap
Expand Down Expand Up @@ -92,6 +92,23 @@ spec:
- key
- name
type: object
extraConfig:
description: ExtraConfig contains additional OIDC configuration
for claim mapping and token validation behavior.
properties:
insecureSkipEmailVerified:
default: false
description: |-
InsecureSkipEmailVerified if set to true, treats email_verified as true when the claim is absent from the ID token.
This does not override an explicit email_verified=false. Only enable for providers that omit the claim entirely (e.g. some Okta, EntraID or CloudFoundry configurations).
type: boolean
userIDClaim:
default: login_name
description: |-
UserIDClaim is the claim to be used as both user ID and username.
When set, it overrides both UserIDKey and UserNameKey in the dex OIDC connector config.
type: string
type: object
issuer:
description: Issuer is the URL of the identity service.
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.0
controller-gen.kubebuilder.io/version: v0.20.1
name: plugindefinitions.greenhouse.sap
spec:
group: greenhouse.sap
Expand Down
2 changes: 1 addition & 1 deletion charts/manager/crds/greenhouse.sap_pluginpresets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.0
controller-gen.kubebuilder.io/version: v0.20.1
name: pluginpresets.greenhouse.sap
spec:
group: greenhouse.sap
Expand Down
2 changes: 1 addition & 1 deletion charts/manager/crds/greenhouse.sap_plugins.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.0
controller-gen.kubebuilder.io/version: v0.20.1
name: plugins.greenhouse.sap
spec:
group: greenhouse.sap
Expand Down
2 changes: 1 addition & 1 deletion charts/manager/crds/greenhouse.sap_teamrolebindings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.0
controller-gen.kubebuilder.io/version: v0.20.1
name: teamrolebindings.greenhouse.sap
spec:
group: greenhouse.sap
Expand Down
2 changes: 1 addition & 1 deletion charts/manager/crds/greenhouse.sap_teamroles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.0
controller-gen.kubebuilder.io/version: v0.20.1
name: teamroles.greenhouse.sap
spec:
group: greenhouse.sap
Expand Down
2 changes: 1 addition & 1 deletion charts/manager/crds/greenhouse.sap_teams.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.0
controller-gen.kubebuilder.io/version: v0.20.1
name: teams.greenhouse.sap
spec:
group: greenhouse.sap
Expand Down
2 changes: 2 additions & 0 deletions config/samples/organization/demo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,5 @@ spec:
# name: demo-oidc
# issuer: https://global.accounts.dev
# redirectURI: https://bogus.accounts.foo
# extraConfig:
# userIDClaim: email
57 changes: 57 additions & 0 deletions docs/reference/api/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2083,6 +2083,63 @@ <h3 id="greenhouse.sap/v1alpha1.OIDCConfig">OIDCConfig
the client application, the URI requested to redirect to must be contained in this list.</p>
</td>
</tr>
<tr>
<td>
<code>extraConfig</code><br>
<em>
<a href="#greenhouse.sap/v1alpha1.OIDCExtraConfig">
OIDCExtraConfig
</a>
</em>
</td>
<td>
<p>ExtraConfig contains additional OIDC configuration for claim mapping and token validation behavior.</p>
</td>
Comment thread
kengou marked this conversation as resolved.
</tr>
</tbody>
</table>
</div>
</div>
<h3 id="greenhouse.sap/v1alpha1.OIDCExtraConfig">OIDCExtraConfig
</h3>
<p>
(<em>Appears on:</em>
<a href="#greenhouse.sap/v1alpha1.OIDCConfig">OIDCConfig</a>)
</p>
<div class="md-typeset__scrollwrap">
<div class="md-typeset__table">
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>insecureSkipEmailVerified</code><br>
<em>
bool
</em>
</td>
<td>
<p>InsecureSkipEmailVerified if set to true, treats email_verified as true when the claim is absent from the ID token.
This does not override an explicit email_verified=false. Only enable for providers that omit the claim entirely (e.g. some Okta, EntraID or CloudFoundry configurations).</p>
</td>
</tr>
<tr>
<td>
<code>userIDClaim</code><br>
<em>
string
</em>
</td>
<td>
<p>UserIDClaim is the claim to be used as both user ID and username.
When set, it overrides both UserIDKey and UserNameKey in the dex OIDC connector config.</p>
</td>
Comment thread
kengou marked this conversation as resolved.
</tr>
</tbody>
</table>
</div>
Expand Down
16 changes: 16 additions & 0 deletions docs/reference/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,22 @@ components:
- key
- name
type: object
extraConfig:
description: ExtraConfig contains additional OIDC configuration for claim mapping and token validation behavior.
properties:
insecureSkipEmailVerified:
default: false
description: |-
InsecureSkipEmailVerified if set to true, treats email_verified as true when the claim is absent from the ID token.
This does not override an explicit email_verified=false. Only enable for providers that omit the claim entirely (e.g. some Okta, EntraID or CloudFoundry configurations).
type: boolean
userIDClaim:
default: login_name
description: |-
UserIDClaim is the claim to be used as both user ID and username.
When set, it overrides both UserIDKey and UserNameKey in the dex OIDC connector config.
type: string
type: object
issuer:
description: Issuer is the URL of the identity service.
type: string
Expand Down
25 changes: 17 additions & 8 deletions internal/controller/organization/dex.go
100644 β†’ 100755
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,24 @@ func (r *OrganizationReconciler) reconcileDexConnector(ctx context.Context, org
if err != nil {
return err
}
var userNameKey = "login_name"
var skipEmailVerified = false
if org.Spec.Authentication.OIDCConfig.ExtraConfig != nil {
if org.Spec.Authentication.OIDCConfig.ExtraConfig.UserIDClaim != "" {
userNameKey = org.Spec.Authentication.OIDCConfig.ExtraConfig.UserIDClaim
}
skipEmailVerified = org.Spec.Authentication.OIDCConfig.ExtraConfig.InsecureSkipEmailVerified
}
oidcConfig := &oidc.Config{
Issuer: org.Spec.Authentication.OIDCConfig.Issuer,
ClientID: clientID,
ClientSecret: clientSecret,
RedirectURI: redirectURL,
UserNameKey: "login_name",
UserIDKey: "login_name",
InsecureSkipVerify: true,
InsecureEnableGroups: true,
Issuer: org.Spec.Authentication.OIDCConfig.Issuer,
ClientID: clientID,
ClientSecret: clientSecret,
RedirectURI: redirectURL,
UserNameKey: userNameKey,
UserIDKey: userNameKey,
InsecureSkipEmailVerified: skipEmailVerified,
InsecureSkipVerify: true,
InsecureEnableGroups: true,
}
configByte, err := json.Marshal(oidcConfig)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
package organization_test

import (
"encoding/json"
"fmt"

"slices"

dexoidc "github.com/dexidp/dex/connector/oidc"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gstruct"
Expand Down Expand Up @@ -390,6 +392,61 @@ var _ = Describe("Test Organization reconciliation", Ordered, func() {
}
test.EventuallyDeleted(test.Ctx, test.K8sClient, team)
})

It("should propagate ExtraConfig to dex connector", func() {
team := setup.CreateTeam(test.Ctx, "test-team-extra", test.WithTeamLabel(greenhouseapis.LabelKeySupportGroup, "true"))

defaultOrg := setup.CreateDefaultOrgWithOIDCSecret(test.Ctx, team.Name)
test.EventuallyCreated(test.Ctx, test.K8sClient, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: defaultOrg.Name}})
Eventually(func(g Gomega) {
err := test.K8sClient.Get(test.Ctx, types.NamespacedName{Name: defaultOrg.Name}, defaultOrg)
g.Expect(err).ToNot(HaveOccurred())
oidcCondition := defaultOrg.Status.GetConditionByType(greenhousev1alpha1.OrganizationOICDConfigured)
g.Expect(oidcCondition).ToNot(BeNil())
g.Expect(oidcCondition.IsTrue()).To(BeTrue())
}).Should(Succeed())

By("creating a test organization with ExtraConfig")
extraConfigOrg := setup.CreateOrganization(test.Ctx, "test-extraconfig-org", test.WithMappedAdminIDPGroup("EXTRA_CONFIG_GROUP"))
test.EventuallyCreated(test.Ctx, test.K8sClient, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: extraConfigOrg.Name}})

oidcSecret := setup.CreateOrgOIDCSecret(test.Ctx, extraConfigOrg.Name, team.Name)
extraConfigOrg = setup.UpdateOrganization(test.Ctx,
extraConfigOrg.Name,
test.WithOIDCConfig(test.OIDCIssuer, oidcSecret.Name, test.OIDCClientIDKey, test.OIDCClientSecretKey),
test.WithOIDCExtraConfig("email", true),
)

By("checking Organization OIDC status is ready")
Eventually(func(g Gomega) {
err := test.K8sClient.Get(test.Ctx, types.NamespacedName{Name: extraConfigOrg.Name}, extraConfigOrg)
g.Expect(err).ToNot(HaveOccurred())
oidcCondition := extraConfigOrg.Status.GetConditionByType(greenhousev1alpha1.OrganizationOICDConfigured)
g.Expect(oidcCondition).ToNot(BeNil(), "OrganizationOICDConfigured should be set")
g.Expect(oidcCondition.IsTrue()).To(BeTrue(), "OrganizationOICDConfigured should be True")
}).Should(Succeed())

if DexStorageType == dex.K8s {
By("verifying the dex connector config contains ExtraConfig values")
connectors := &dexapi.ConnectorList{}
err := setup.List(test.Ctx, connectors)
Expect(err).ToNot(HaveOccurred())

filteredConnectors := slices.DeleteFunc(connectors.Items, func(c dexapi.Connector) bool {
return c.ID != extraConfigOrg.Name
})
Expect(filteredConnectors).To(HaveLen(1), "there should be exactly one connector for the org")

var connectorConfig dexoidc.Config
Expect(json.Unmarshal(filteredConnectors[0].Config, &connectorConfig)).To(Succeed(), "connector config should be valid JSON")
Expect(connectorConfig.UserNameKey).To(Equal("email"), "UserNameKey should be set to the custom claim")
Expect(connectorConfig.UserIDKey).To(Equal("email"), "UserIDKey should be set to the custom claim")
Expect(connectorConfig.InsecureSkipEmailVerified).To(BeTrue(), "InsecureSkipEmailVerified should be true")
}

test.EventuallyDeleted(test.Ctx, test.K8sClient, &greenhousev1alpha1.Organization{ObjectMeta: metav1.ObjectMeta{Name: extraConfigOrg.Name}})
test.EventuallyDeleted(test.Ctx, test.K8sClient, team)
})
})

When("reconciling PluginDefinitionCatalog ServiceAccount for regular organization", Ordered, func() {
Expand Down
Loading
Loading