Skip to content

Commit 3fd91d9

Browse files
zmotsoSergK
authored andcommitted
fix: Client creation fails due to admin fine grained permissions (#180)
- Added a new method to check if the ADMIN_FINE_GRAINED_AUTHZ feature flag is enabled in Keycloak. - Added condition to not process admin fine grained permissions if ADMIN_FINE_GRAINED_AUTHZ is not enabled. - Prevents client creation failures when the feature flag is disabled in Keycloak server.
1 parent 798d8fa commit 3fd91d9

16 files changed

+798
-38
lines changed

.mockery.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ mockname: "Mock{{.InterfaceName}}"
55
outpkg: "mocks"
66
filename: "{{.InterfaceName | lower}}_mock.go"
77
issue-845-fix: True
8+
resolve-type-alias: False
9+
disable-version-string: True
810
packages:
911
github.com/epam/edp-keycloak-operator/pkg/client/keycloak:
1012
interfaces:

api/v1/keycloakclient_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ type KeycloakClientSpec struct {
132132
AuthorizationServicesEnabled bool `json:"authorizationServicesEnabled,omitempty"`
133133

134134
// AdminFineGrainedPermissionsEnabled enable/disable fine-grained admin permissions for a client.
135+
// Feature flag ADMIN_FINE_GRAINED_AUTHZ should be enabled in Keycloak server.
135136
// +optional
136137
AdminFineGrainedPermissionsEnabled bool `json:"adminFineGrainedPermissionsEnabled,omitempty"`
137138

config/crd/bases/v1.edp.epam.com_keycloakclients.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ spec:
4545
description: KeycloakClientSpec defines the desired state of KeycloakClient.
4646
properties:
4747
adminFineGrainedPermissionsEnabled:
48-
description: AdminFineGrainedPermissionsEnabled enable/disable fine-grained
49-
admin permissions for a client.
48+
description: |-
49+
AdminFineGrainedPermissionsEnabled enable/disable fine-grained admin permissions for a client.
50+
Feature flag ADMIN_FINE_GRAINED_AUTHZ should be enabled in Keycloak server.
5051
type: boolean
5152
adminUrl:
5253
description: |-

deploy-templates/crds/v1.edp.epam.com_keycloakclients.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ spec:
4545
description: KeycloakClientSpec defines the desired state of KeycloakClient.
4646
properties:
4747
adminFineGrainedPermissionsEnabled:
48-
description: AdminFineGrainedPermissionsEnabled enable/disable fine-grained
49-
admin permissions for a client.
48+
description: |-
49+
AdminFineGrainedPermissionsEnabled enable/disable fine-grained admin permissions for a client.
50+
Feature flag ADMIN_FINE_GRAINED_AUTHZ should be enabled in Keycloak server.
5051
type: boolean
5152
adminUrl:
5253
description: |-

docs/api.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1966,7 +1966,8 @@ KeycloakClientSpec defines the desired state of KeycloakClient.
19661966
<td><b>adminFineGrainedPermissionsEnabled</b></td>
19671967
<td>boolean</td>
19681968
<td>
1969-
AdminFineGrainedPermissionsEnabled enable/disable fine-grained admin permissions for a client.<br/>
1969+
AdminFineGrainedPermissionsEnabled enable/disable fine-grained admin permissions for a client.
1970+
Feature flag ADMIN_FINE_GRAINED_AUTHZ should be enabled in Keycloak server.<br/>
19701971
</td>
19711972
<td>false</td>
19721973
</tr><tr>

internal/controller/keycloakclient/chain/put_client_admin_fine_grained_perms.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ func NewPutAdminFineGrainedPermissions(keycloakApiClient keycloak.Client) *PutAd
2626
}
2727

2828
func (el *PutAdminFineGrainedPermissions) Serve(ctx context.Context, keycloakClient *keycloakApi.KeycloakClient, realmName string) error {
29+
featureFlagEnabled, err := el.keycloakApiClient.FeatureFlagEnabled(ctx, adapter.FeatureFlagAdminFineGrainedAuthz)
30+
if err != nil {
31+
return fmt.Errorf("failed to check feature flag ADMIN_FINE_GRAINED_AUTHZ: %w", err)
32+
}
33+
34+
if !featureFlagEnabled {
35+
log := ctrl.LoggerFrom(ctx)
36+
log.Info("Feature flag is not enabled, skipping admin fine grained permissions", "featureFlag", adapter.FeatureFlagAdminFineGrainedAuthz)
37+
38+
return nil
39+
}
40+
2941
clientID, err := el.keycloakApiClient.GetClientID(keycloakClient.Spec.ClientId, realmName)
3042
if err != nil {
3143
return fmt.Errorf("failed to get client id: %w", err)

internal/controller/keycloakclient/chain/put_client_admin_fine_grained_perms_test.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package chain
22

33
import (
44
"context"
5+
"fmt"
56
"testing"
67

78
"github.com/Nerzal/gocloak/v12"
@@ -67,6 +68,10 @@ func TestPutAdminFineGrainedPermissions_Serve(t *testing.T) {
6768
"map-role": "321",
6869
}
6970

71+
m.On("FeatureFlagEnabled", ctrl.LoggerInto(context.Background(), logr.Discard()), "ADMIN_FINE_GRAINED_AUTHZ").
72+
Return(true, nil).
73+
Once()
74+
7075
m.On("GetClientID", "test-client-id", "realm").
7176
Return("123", nil).
7277
Once()
@@ -102,6 +107,90 @@ func TestPutAdminFineGrainedPermissions_Serve(t *testing.T) {
102107
},
103108
wantErr: require.NoError,
104109
},
110+
{
111+
name: "with feature flag disabled",
112+
client: func(t *testing.T) client.Client {
113+
s := runtime.NewScheme()
114+
require.NoError(t, keycloakApi.AddToScheme(s))
115+
require.NoError(t, corev1.AddToScheme(s))
116+
117+
return fake.NewClientBuilder().WithScheme(s).WithObjects(
118+
&keycloakApi.KeycloakClient{
119+
ObjectMeta: metav1.ObjectMeta{
120+
Name: "test-client",
121+
Namespace: "default",
122+
},
123+
Spec: keycloakApi.KeycloakClientSpec{
124+
ClientId: "test-client-id",
125+
AdminFineGrainedPermissionsEnabled: true,
126+
Permission: &keycloakApi.AdminFineGrainedPermission{
127+
ScopePermissions: []keycloakApi.ScopePermissions{
128+
{
129+
Name: "map-role",
130+
Policies: []string{"scope permission"},
131+
},
132+
},
133+
},
134+
},
135+
}).Build()
136+
},
137+
keycloakClient: client.ObjectKey{
138+
Name: "test-client",
139+
Namespace: "default",
140+
},
141+
keycloakApiClient: func(t *testing.T) *mocks.MockClient {
142+
m := mocks.NewMockClient(t)
143+
144+
m.On("FeatureFlagEnabled", ctrl.LoggerInto(context.Background(), logr.Discard()), "ADMIN_FINE_GRAINED_AUTHZ").
145+
Return(false, nil).
146+
Once()
147+
148+
return m
149+
},
150+
wantErr: require.NoError,
151+
},
152+
{
153+
name: "with feature flag check error",
154+
client: func(t *testing.T) client.Client {
155+
s := runtime.NewScheme()
156+
require.NoError(t, keycloakApi.AddToScheme(s))
157+
require.NoError(t, corev1.AddToScheme(s))
158+
159+
return fake.NewClientBuilder().WithScheme(s).WithObjects(
160+
&keycloakApi.KeycloakClient{
161+
ObjectMeta: metav1.ObjectMeta{
162+
Name: "test-client",
163+
Namespace: "default",
164+
},
165+
Spec: keycloakApi.KeycloakClientSpec{
166+
ClientId: "test-client-id",
167+
AdminFineGrainedPermissionsEnabled: true,
168+
Permission: &keycloakApi.AdminFineGrainedPermission{
169+
ScopePermissions: []keycloakApi.ScopePermissions{
170+
{
171+
Name: "map-role",
172+
Policies: []string{"scope permission"},
173+
},
174+
},
175+
},
176+
},
177+
}).Build()
178+
},
179+
keycloakClient: client.ObjectKey{
180+
Name: "test-client",
181+
Namespace: "default",
182+
},
183+
keycloakApiClient: func(t *testing.T) *mocks.MockClient {
184+
m := mocks.NewMockClient(t)
185+
186+
m.On("FeatureFlagEnabled", ctrl.LoggerInto(context.Background(), logr.Discard()), "ADMIN_FINE_GRAINED_AUTHZ").
187+
Return(false, fmt.Errorf("feature flag check failed")).
188+
Once()
189+
190+
return m
191+
},
192+
wantErr: require.Error,
193+
},
105194
}
106195

107196
for _, tt := range tests {

internal/controller/keycloakclient/keycloakclient_controller_integration_test.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,29 @@ import (
2222

2323
var _ = Describe("KeycloakClient controller", Ordered, func() {
2424
It("Should create KeycloakClient with secret reference", func() {
25+
By("Checking feature flag ADMIN_FINE_GRAINED_AUTHZ")
26+
By("Creating a KeycloakClient to check feature flag")
27+
keycloakApiClient, err := controllerHelper.CreateKeycloakClientFromRealmRef(
28+
ctx,
29+
&keycloakApi.KeycloakClient{
30+
ObjectMeta: metav1.ObjectMeta{
31+
Name: "test-keycloak-client-to-check-feature-flag",
32+
Namespace: ns,
33+
},
34+
Spec: keycloakApi.KeycloakClientSpec{
35+
RealmRef: common.RealmRef{
36+
Name: KeycloakRealmCR,
37+
Kind: keycloakApi.KeycloakRealmKind,
38+
},
39+
},
40+
},
41+
)
42+
Expect(err).ShouldNot(HaveOccurred())
43+
44+
featureFlagEnabled, err := keycloakApiClient.FeatureFlagEnabled(ctx, "ADMIN_FINE_GRAINED_AUTHZ")
45+
Expect(err).ShouldNot(HaveOccurred())
46+
Expect(featureFlagEnabled).Should(BeTrue(), "Feature flag ADMIN_FINE_GRAINED_AUTHZ should be enabled")
47+
2548
By("Creating a client secret")
2649
clientSecret := &corev1.Secret{
2750
ObjectMeta: metav1.ObjectMeta{
@@ -66,7 +89,7 @@ var _ = Describe("KeycloakClient controller", Ordered, func() {
6689
Browser: "browser",
6790
DirectGrant: "direct grant",
6891
},
69-
//AdminFineGrainedPermissionsEnabled: true,
92+
AdminFineGrainedPermissionsEnabled: true,
7093
},
7194
}
7295

internal/controller/keycloakclient/suite_test.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,13 @@ import (
3232
)
3333

3434
var (
35-
cfg *rest.Config
36-
k8sClient client.Client
37-
testEnv *envtest.Environment
38-
ctx context.Context
39-
cancel context.CancelFunc
40-
keycloakURL string
35+
cfg *rest.Config
36+
k8sClient client.Client
37+
testEnv *envtest.Environment
38+
ctx context.Context
39+
cancel context.CancelFunc
40+
keycloakURL string
41+
controllerHelper *helper.Helper
4142
)
4243

4344
const (
@@ -94,17 +95,17 @@ var _ = BeforeSuite(func() {
9495
})
9596
Expect(err).ToNot(HaveOccurred())
9697

97-
h := helper.MakeHelper(k8sManager.GetClient(), k8sManager.GetScheme(), "default")
98+
controllerHelper = helper.MakeHelper(k8sManager.GetClient(), k8sManager.GetScheme(), "default")
9899

99-
err = keycloak.NewReconcileKeycloak(k8sManager.GetClient(), k8sManager.GetScheme(), h).
100+
err = keycloak.NewReconcileKeycloak(k8sManager.GetClient(), k8sManager.GetScheme(), controllerHelper).
100101
SetupWithManager(k8sManager, 0)
101102
Expect(err).ToNot(HaveOccurred())
102103

103-
err = keycloakrealm.NewReconcileKeycloakRealm(k8sManager.GetClient(), k8sManager.GetScheme(), h).
104+
err = keycloakrealm.NewReconcileKeycloakRealm(k8sManager.GetClient(), k8sManager.GetScheme(), controllerHelper).
104105
SetupWithManager(k8sManager, 0)
105106
Expect(err).ToNot(HaveOccurred())
106107

107-
err = NewReconcileKeycloakClient(k8sManager.GetClient(), h).
108+
err = NewReconcileKeycloakClient(k8sManager.GetClient(), controllerHelper).
108109
SetupWithManager(k8sManager, 0)
109110
Expect(err).ToNot(HaveOccurred())
110111

pkg/client/keycloak/adapter/gocloak_adapter.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ const (
6969
getChildGroups = "/admin/realms/{realm}/groups/{groupID}/children"
7070
getGroup = "/admin/realms/{realm}/groups/{groupID}"
7171
clientManagementPermissions = "/admin/realms/{realm}/clients/{id}/management/permissions"
72+
serverInfo = "/admin/serverinfo"
7273
logClientDTO = "client dto"
7374
)
7475

0 commit comments

Comments
 (0)