@@ -13,9 +13,10 @@ import (
1313)
1414
1515const (
16− gitlabProviderName = "GitLab"
17− gitlabDefaultScope = "openid email"
18− gitlabUserClaim = "nickname"
16+ gitlabProviderName = "GitLab"
17+ gitlabDefaultScope = "openid email"
18+ gitlabUserClaim = "nickname"
19+ gitlabProjectPrefix = "project:"
1920)
2021
2122// GitLabProvider represents a GitLab based Identity Provider
@@ -23,6 +24,8 @@ type GitLabProvider struct {
2324 *OIDCProvider
2425
2526 allowedProjects []*gitlabProject
27+ // Expose this for unit testing
28+ oidcRefreshFunc func(context.Context, *sessions.SessionState) (bool, error)
2629}
2730
2831var _ Provider = (*GitLabProvider)(nil)
@@ -35,11 +38,14 @@ func NewGitLabProvider(p *ProviderData) *GitLabProvider {
3538 p.Scope = gitlabDefaultScope
3639 }
3740
41+ oidcProvider := &OIDCProvider{
42+ ProviderData: p,
43+ SkipNonce: false,
44+ }
45+
3846 return &GitLabProvider{
39− OIDCProvider: &OIDCProvider{
40− ProviderData: p,
41− SkipNonce: false,
42− },
47+ OIDCProvider: oidcProvider,
48+ oidcRefreshFunc: oidcProvider.RefreshSession,
4349 }
4450}
4551
@@ -245,5 +251,41 @@ func (p *GitLabProvider) getProjectInfo(ctx context.Context, s *sessions.Session
245251}
246252
247253func formatProject(project *gitlabProject) string {
248− return fmt.Sprintf("project:%s", project.Name)
254+ return gitlabProjectPrefix + project.Name
255+}
256+
257+// RefreshSession refreshes the session with the OIDCProvider implementation
258+// but preserves the custom GitLab projects added in the `EnrichSession` stage.
259+func (p *GitLabProvider) RefreshSession(ctx context.Context, s *sessions.SessionState) (bool, error) {
260+ projects := getSessionProjects(s)
261+ // This will overwrite s.Groups with the new IDToken's `groups` claims
262+ refreshed, err := p.oidcRefreshFunc(ctx, s)
263+ if refreshed && err == nil {
264+ s.Groups = append(s.Groups, projects...)
265+ s.Groups = deduplicateGroups(s.Groups)
266+ }
267+ return refreshed, err
268+}
269+
270+func getSessionProjects(s *sessions.SessionState) []string {
271+ var projects []string
272+ for _, group := range s.Groups {
273+ if strings.HasPrefix(group, gitlabProjectPrefix) {
274+ projects = append(projects, group)
275+ }
276+ }
277+ return projects
278+}
279+
280+func deduplicateGroups(groups []string) []string {
281+ groupSet := make(map[string]struct{})
282+ for _, group := range groups {
283+ groupSet[group] = struct{}{}
284+ }
285+
286+ uniqueGroups := make([]string, 0, len(groupSet))
287+ for group := range groupSet {
288+ uniqueGroups = append(uniqueGroups, group)
289+ }
290+ return uniqueGroups
249291}