Skip to content

Commit ac974e4

Browse files
committed
ApplicationAuth: support OIDC authentication mode
1 parent 1b56fd7 commit ac974e4

File tree

2 files changed

+117
-1
lines changed

2 files changed

+117
-1
lines changed

controllers/capabilities/applicationauth_controller.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,14 @@ type AuthSecret struct {
4747
UserKey string
4848
ApplicationKey string
4949
ApplicationID string
50+
ClientSecret string
5051
}
5152

5253
const (
5354
UserKey = "UserKey"
5455
ApplicationKey = "ApplicationKey"
5556
ApplicationID = "ApplicationID"
57+
ClientSecret = "ClientSecret"
5658
)
5759

5860
// +kubebuilder:rbac:groups=capabilities.3scale.net,resources=applicationauths,verbs=get;list;watch;create;update;patch;delete
@@ -248,6 +250,29 @@ func syncApplicationAuth(
248250
return fmt.Errorf("error sync applicationAuth for developerAccountID: %d, applicationID: %d, error: %w", developerAccountID, applicationID, err)
249251
}
250252
}
253+
case "oidc":
254+
// get the existing value from the portal
255+
applicationKeys, err := threescaleClient.ApplicationKeys(developerAccountID, applicationID)
256+
if err != nil {
257+
return err
258+
}
259+
260+
// pre-existing keys
261+
if len(applicationKeys) > 0 {
262+
// Nothing to do, return early
263+
if applicationKeys[0].Value == authSecret.ClientSecret {
264+
return nil
265+
}
266+
267+
// if the key is not match, delete it
268+
if err := threescaleClient.DeleteApplicationKey(developerAccountID, applicationID, applicationKeys[0].Value); err != nil {
269+
return err
270+
}
271+
}
272+
273+
if _, err = threescaleClient.CreateApplicationKey(developerAccountID, applicationID, authSecret.ClientSecret); err != nil {
274+
return err
275+
}
251276
}
252277

253278
return nil
@@ -304,6 +329,25 @@ func authSecretReferenceSource(cl client.Client, ns string, authSectretRef *core
304329
}
305330
}
306331
return &AuthSecret{ApplicationKey: applicationKeyStr}, nil
332+
case "oidc":
333+
clientSecretStr, err := secretSource.RequiredFieldValueFromRequiredSecret(authSectretRef.Name, ClientSecret)
334+
if err != nil {
335+
return nil, err
336+
}
337+
338+
if clientSecretStr == "" {
339+
if generateSecret {
340+
clientSecretStr = rand.String(16)
341+
}
342+
newValues := map[string][]byte{
343+
ClientSecret: []byte(clientSecretStr),
344+
}
345+
346+
if err := updateSecret(context.Background(), cl, authSectretRef.Name, ns, newValues); err != nil {
347+
return nil, err
348+
}
349+
}
350+
return &AuthSecret{ClientSecret: clientSecretStr}, nil
307351
default:
308352
return nil, fmt.Errorf("unknown authentication mode")
309353
}

controllers/capabilities/applicationauth_controller_test.go

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,51 @@ func TestApplicationAuthReconciler_syncApplicationAuth(t *testing.T) {
151151
expectedKey: "testkey1,testkey2,testkey3",
152152
wantErr: false,
153153
},
154+
{
155+
name: "returns error with empty client_secret with empty secret",
156+
mockServer: &mockApplicationAuthServer{
157+
authMode: "oidc",
158+
keys: []string{},
159+
userAccountID: appID,
160+
appID: userAccountID,
161+
},
162+
authMode: "oidc",
163+
authSecret: getEmptyAuthSecret(),
164+
expectedKey: "",
165+
wantErr: true,
166+
},
167+
{
168+
name: "update existing client_secret with value from secret",
169+
mockServer: &mockApplicationAuthServer{
170+
authMode: "oidc",
171+
keys: []string{"initalkey"},
172+
userAccountID: appID,
173+
appID: userAccountID,
174+
},
175+
authMode: "oidc",
176+
authSecret: getAuthSecret(),
177+
expectedKey: "testkey",
178+
wantErr: false,
179+
},
180+
{
181+
name: "update existing client_secret with the same value should not return error",
182+
mockServer: &mockApplicationAuthServer{
183+
authMode: "oidc",
184+
keys: []string{"testkey"},
185+
userAccountID: appID,
186+
appID: userAccountID,
187+
},
188+
authMode: "oidc",
189+
authSecret: getAuthSecret(),
190+
expectedKey: "testkey",
191+
wantErr: false,
192+
},
154193
}
155194
for _, tt := range tests {
156195
t.Run(tt.name, func(t *testing.T) {
157196
srv := tt.mockServer.GetServer()
197+
defer srv.Close()
198+
158199
ap, _ := threescaleapi.NewAdminPortalFromStr(srv.URL)
159200
threescaleClient := threescaleapi.NewThreeScale(ap, "test", srv.Client())
160201

@@ -236,6 +277,30 @@ func TestApplicationAuthReconciler_authSecretReferenceSource(t *testing.T) {
236277
wantErr: false,
237278
err: "",
238279
},
280+
{
281+
name: "return error when secret is empty",
282+
authMode: "oidc",
283+
generateSecret: true,
284+
secretData: map[string][]byte{},
285+
wantErr: true,
286+
err: "secret field 'ClientSecret' is required in secret 'test'",
287+
},
288+
{
289+
name: "generate client_secret when secret is empty",
290+
authMode: "oidc",
291+
generateSecret: true,
292+
secretData: map[string][]byte{"ClientSecret": []byte("")},
293+
wantErr: false,
294+
err: "",
295+
},
296+
{
297+
name: "use client_secret value in secret",
298+
authMode: "oidc",
299+
generateSecret: true,
300+
secretData: map[string][]byte{"ClientSecret": []byte("testkey")},
301+
wantErr: false,
302+
err: "",
303+
},
239304
{
240305
name: "return error with unknown authMode",
241306
authMode: "unknown",
@@ -293,6 +358,10 @@ func TestApplicationAuthReconciler_authSecretReferenceSource(t *testing.T) {
293358
if authSecret.ApplicationKey != string(newSecret.Data["ApplicationKey"]) {
294359
t.Fatalf("mismatch user_key expected = '%s', got '%s'", authSecret.ApplicationKey, newSecret.Data["ApplicationKey"])
295360
}
361+
case "oidc":
362+
if authSecret.ClientSecret != string(newSecret.Data[ClientSecret]) {
363+
t.Fatalf("mismatch user_key expected = '%s', got '%s'", authSecret.ClientSecret, newSecret.Data[ClientSecret])
364+
}
296365
}
297366
}
298367
})
@@ -349,6 +418,7 @@ func getAuthSecret() AuthSecret {
349418
UserKey: "testkey",
350419
ApplicationKey: "testkey",
351420
ApplicationID: "",
421+
ClientSecret: "testkey",
352422
}
353423
return authSecret
354424
}
@@ -376,7 +446,7 @@ func (m *mockApplicationAuthServer) GetKey(mode string) string {
376446
switch mode {
377447
case "1":
378448
return m.userKey
379-
case "2":
449+
case "2", "oidc":
380450
return strings.Join(m.keys, ",")
381451
default:
382452
return ""
@@ -437,6 +507,8 @@ func (m *mockApplicationAuthServer) applicationKeysHandler(w http.ResponseWriter
437507

438508
if m.authMode == "2" {
439509
keyLimit = 5
510+
} else if m.authMode == "oidc" {
511+
keyLimit = 1
440512
}
441513

442514
// Check if the current lenght does not exceed 5 keys limit

0 commit comments

Comments
 (0)