Skip to content

Commit 4524c19

Browse files
authored
[OIDC] IDP: use workspace.context.normalizedContextUrl to fill the "sub" and "context" claims of the IDToken (#20111)
The motivation is to have more uniform URL shapes to match against e.g. across different IDEs.
1 parent 2d67254 commit 4524c19

File tree

2 files changed

+70
-24
lines changed

2 files changed

+70
-24
lines changed

components/public-api-server/pkg/apiv1/identityprovider.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func (srv *IdentityProviderService) GetIDToken(ctx context.Context, req *connect
9393
userInfo.SetName(user.Name)
9494
userInfo.AppendClaims("user_id", user.ID)
9595
userInfo.AppendClaims("org_id", workspace.Workspace.OrganizationId)
96-
userInfo.AppendClaims("context", workspace.Workspace.ContextURL)
96+
userInfo.AppendClaims("context", getContext(workspace))
9797
userInfo.AppendClaims("workspace_id", workspaceID)
9898

9999
if req.Msg.GetScope() != "" {
@@ -127,7 +127,7 @@ func (srv *IdentityProviderService) getOIDCSubject(ctx context.Context, userInfo
127127
UserID: user.ID,
128128
TeamID: workspace.Workspace.OrganizationId,
129129
})
130-
subject := workspace.Workspace.ContextURL
130+
subject := getContext(workspace)
131131
if len(claimKeys) != 0 {
132132
subArr := []string{}
133133
for _, key := range claimKeys {
@@ -141,3 +141,12 @@ func (srv *IdentityProviderService) getOIDCSubject(ctx context.Context, userInfo
141141
}
142142
return subject
143143
}
144+
145+
func getContext(workspace *protocol.WorkspaceInfo) string {
146+
context := "no-context"
147+
if workspace.Workspace.Context != nil && workspace.Workspace.Context.NormalizedContextURL != "" {
148+
// using Workspace.Context.NormalizedContextURL to not include prefixes (like "referrer:jetbrains-gateway", or other prefix contexts)
149+
context = workspace.Workspace.Context.NormalizedContextURL
150+
}
151+
return context
152+
}

components/public-api-server/pkg/apiv1/identityprovider_test.go

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ func TestGetIDToken(t *testing.T) {
6464
Repository: &protocol.Repository{
6565
CloneURL: "https://github.com/gitpod-io/gitpod.git",
6666
},
67+
NormalizedContextURL: "https://github.com/gitpod-io/gitpod",
6768
},
6869
},
6970
},
@@ -112,6 +113,7 @@ func TestGetIDToken(t *testing.T) {
112113
Repository: &protocol.Repository{
113114
CloneURL: "https://github.com/gitpod-io/gitpod.git",
114115
},
116+
NormalizedContextURL: "https://github.com/gitpod-io/gitpod",
115117
},
116118
},
117119
},
@@ -174,6 +176,9 @@ func TestGetIDToken(t *testing.T) {
174176
&protocol.WorkspaceInfo{
175177
Workspace: &protocol.Workspace{
176178
ContextURL: "https://github.com/gitpod-io/gitpod",
179+
Context: &protocol.WorkspaceContext{
180+
NormalizedContextURL: "https://github.com/gitpod-io/gitpod",
181+
},
177182
},
178183
},
179184
nil,
@@ -226,6 +231,7 @@ func TestGetIDToken(t *testing.T) {
226231
Repository: &protocol.Repository{
227232
CloneURL: "https://github.com/gitpod-io/gitpod.git",
228233
},
234+
NormalizedContextURL: "https://github.com/gitpod-io/gitpod",
229235
},
230236
},
231237
},
@@ -268,6 +274,9 @@ func TestGetIDToken(t *testing.T) {
268274
&protocol.WorkspaceInfo{
269275
Workspace: &protocol.Workspace{
270276
ContextURL: "https://github.com/gitpod-io/gitpod",
277+
Context: &protocol.WorkspaceContext{
278+
NormalizedContextURL: "https://github.com/gitpod-io/gitpod",
279+
},
271280
},
272281
},
273282
nil,
@@ -344,36 +353,64 @@ func (f functionIDTokenSource) IDToken(ctx context.Context, org string, audience
344353
}
345354

346355
func TestGetOIDCSubject(t *testing.T) {
347-
contextUrl := "https://github.com/gitpod-io/gitpod"
356+
normalizedContextUrl := "https://github.com/gitpod-io/gitpod"
357+
defaultWorkspace := &protocol.Workspace{
358+
ContextURL: "SOME_ENV=test/" + normalizedContextUrl,
359+
Context: &protocol.WorkspaceContext{
360+
NormalizedContextURL: normalizedContextUrl,
361+
}}
348362
tests := []struct {
349-
Name string
350-
Keys string
351-
Claims map[string]interface{}
352-
Subject string
363+
Name string
364+
Keys string
365+
Claims map[string]interface{}
366+
Subject string
367+
Workspace *protocol.Workspace
353368
}{
354369
{
355-
Name: "happy path",
356-
Keys: "",
357-
Claims: map[string]interface{}{},
358-
Subject: contextUrl,
370+
Name: "happy path",
371+
Keys: "",
372+
Claims: map[string]interface{}{},
373+
Subject: normalizedContextUrl,
374+
Workspace: defaultWorkspace,
359375
},
360376
{
361-
Name: "happy path 2",
362-
Keys: "undefined",
363-
Claims: map[string]interface{}{},
364-
Subject: contextUrl,
377+
Name: "happy path 2",
378+
Keys: "undefined",
379+
Claims: map[string]interface{}{},
380+
Subject: normalizedContextUrl,
381+
Workspace: defaultWorkspace,
365382
},
366383
{
367-
Name: "with custom keys",
368-
Keys: "key1,key3,key2",
369-
Claims: map[string]interface{}{"key1": 1, "key2": "hello"},
370-
Subject: "key1:1:key3::key2:hello",
384+
Name: "with custom keys",
385+
Keys: "key1,key3,key2",
386+
Claims: map[string]interface{}{"key1": 1, "key2": "hello"},
387+
Subject: "key1:1:key3::key2:hello",
388+
Workspace: defaultWorkspace,
371389
},
372390
{
373-
Name: "with custom keys",
374-
Keys: "key1,key3,key2",
375-
Claims: map[string]interface{}{"key1": 1, "key3": errors.New("test")},
376-
Subject: "key1:1:key3:test:key2:",
391+
Name: "with custom keys",
392+
Keys: "key1,key3,key2",
393+
Claims: map[string]interface{}{"key1": 1, "key3": errors.New("test")},
394+
Subject: "key1:1:key3:test:key2:",
395+
Workspace: defaultWorkspace,
396+
},
397+
{
398+
Name: "happy path with strange prefix",
399+
Keys: "",
400+
Claims: map[string]interface{}{},
401+
Subject: normalizedContextUrl,
402+
Workspace: &protocol.Workspace{ContextURL: "referrer:jetbrains-gateway:intellij/" + normalizedContextUrl, Context: &protocol.WorkspaceContext{
403+
NormalizedContextURL: normalizedContextUrl,
404+
}},
405+
},
406+
{
407+
Name: "happy path without NormalizedContextURL",
408+
Keys: "",
409+
Claims: map[string]interface{}{},
410+
Subject: "no-context",
411+
Workspace: &protocol.Workspace{ContextURL: "referrer:jetbrains-gateway:intellij/" + normalizedContextUrl, Context: &protocol.WorkspaceContext{
412+
NormalizedContextURL: "",
413+
}},
377414
},
378415
}
379416

@@ -389,7 +426,7 @@ func TestGetOIDCSubject(t *testing.T) {
389426
userinfo.AppendClaims(k, v)
390427
}
391428
act := svc.getOIDCSubject(context.Background(), userinfo, &protocol.User{}, &protocol.WorkspaceInfo{
392-
Workspace: &protocol.Workspace{ContextURL: contextUrl},
429+
Workspace: test.Workspace,
393430
})
394431
if diff := cmp.Diff(test.Subject, act); diff != "" {
395432
t.Errorf("getOIDCSubject() mismatch (-want +got):\n%s", diff)

0 commit comments

Comments
 (0)