Skip to content

Commit 53f7e9e

Browse files
authored
chore: dynamically determine gitlab external auth defaults (#13102)
* chore: dynamically determine gitlab external auth defaults Static defaults work for github cloud, but not self hosted. Self hosted setups will now have sane defaults if omitted.
1 parent 47993e3 commit 53f7e9e

File tree

2 files changed

+147
-9
lines changed

2 files changed

+147
-9
lines changed

coderd/externalauth/externalauth.go

+41-9
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,9 @@ func applyDefaultsToConfig(config *codersdk.ExternalAuthConfig) {
563563

564564
// Dynamic defaults
565565
switch codersdk.EnhancedExternalAuthProvider(config.Type) {
566+
case codersdk.EnhancedExternalAuthProviderGitLab:
567+
copyDefaultSettings(config, gitlabDefaults(config))
568+
return
566569
case codersdk.EnhancedExternalAuthProviderBitBucketServer:
567570
copyDefaultSettings(config, bitbucketServerDefaults(config))
568571
return
@@ -667,6 +670,44 @@ func bitbucketServerDefaults(config *codersdk.ExternalAuthConfig) codersdk.Exter
667670
return defaults
668671
}
669672

673+
// gitlabDefaults returns a static config if using the gitlab cloud offering.
674+
// The values are dynamic if using a self-hosted gitlab.
675+
// When the decision is not obvious, just defer to the cloud defaults.
676+
// Any user specific fields will override this if provided.
677+
func gitlabDefaults(config *codersdk.ExternalAuthConfig) codersdk.ExternalAuthConfig {
678+
cloud := codersdk.ExternalAuthConfig{
679+
AuthURL: "https://gitlab.com/oauth/authorize",
680+
TokenURL: "https://gitlab.com/oauth/token",
681+
ValidateURL: "https://gitlab.com/oauth/token/info",
682+
DisplayName: "GitLab",
683+
DisplayIcon: "/icon/gitlab.svg",
684+
Regex: `^(https?://)?gitlab\.com(/.*)?$`,
685+
Scopes: []string{"write_repository"},
686+
}
687+
688+
if config.AuthURL == "" || config.AuthURL == cloud.AuthURL {
689+
return cloud
690+
}
691+
692+
au, err := url.Parse(config.AuthURL)
693+
if err != nil || au.Host == "gitlab.com" {
694+
// If the AuthURL is not a valid URL or is using the cloud,
695+
// use the cloud static defaults.
696+
return cloud
697+
}
698+
699+
// At this point, assume it is self-hosted and use the AuthURL
700+
return codersdk.ExternalAuthConfig{
701+
DisplayName: cloud.DisplayName,
702+
Scopes: cloud.Scopes,
703+
DisplayIcon: cloud.DisplayIcon,
704+
AuthURL: au.ResolveReference(&url.URL{Path: "/oauth/authorize"}).String(),
705+
TokenURL: au.ResolveReference(&url.URL{Path: "/oauth/token"}).String(),
706+
ValidateURL: au.ResolveReference(&url.URL{Path: "/oauth/token/info"}).String(),
707+
Regex: fmt.Sprintf(`^(https?://)?%s(/.*)?$`, strings.ReplaceAll(au.Host, ".", `\.`)),
708+
}
709+
}
710+
670711
func jfrogArtifactoryDefaults(config *codersdk.ExternalAuthConfig) codersdk.ExternalAuthConfig {
671712
defaults := codersdk.ExternalAuthConfig{
672713
DisplayName: "JFrog Artifactory",
@@ -789,15 +830,6 @@ var staticDefaults = map[codersdk.EnhancedExternalAuthProvider]codersdk.External
789830
Regex: `^(https?://)?bitbucket\.org(/.*)?$`,
790831
Scopes: []string{"account", "repository:write"},
791832
},
792-
codersdk.EnhancedExternalAuthProviderGitLab: {
793-
AuthURL: "https://gitlab.com/oauth/authorize",
794-
TokenURL: "https://gitlab.com/oauth/token",
795-
ValidateURL: "https://gitlab.com/oauth/token/info",
796-
DisplayName: "GitLab",
797-
DisplayIcon: "/icon/gitlab.svg",
798-
Regex: `^(https?://)?gitlab\.com(/.*)?$`,
799-
Scopes: []string{"write_repository"},
800-
},
801833
codersdk.EnhancedExternalAuthProviderGitHub: {
802834
AuthURL: xgithub.Endpoint.AuthURL,
803835
TokenURL: xgithub.Endpoint.TokenURL,

coderd/externalauth/externalauth_internal_test.go

+106
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,112 @@ import (
88
"github.com/coder/coder/v2/codersdk"
99
)
1010

11+
func TestGitlabDefaults(t *testing.T) {
12+
t.Parallel()
13+
14+
// The default cloud setup. Copying this here as hard coded
15+
// values.
16+
cloud := codersdk.ExternalAuthConfig{
17+
Type: string(codersdk.EnhancedExternalAuthProviderGitLab),
18+
ID: string(codersdk.EnhancedExternalAuthProviderGitLab),
19+
AuthURL: "https://gitlab.com/oauth/authorize",
20+
TokenURL: "https://gitlab.com/oauth/token",
21+
ValidateURL: "https://gitlab.com/oauth/token/info",
22+
DisplayName: "GitLab",
23+
DisplayIcon: "/icon/gitlab.svg",
24+
Regex: `^(https?://)?gitlab\.com(/.*)?$`,
25+
Scopes: []string{"write_repository"},
26+
}
27+
28+
tests := []struct {
29+
name string
30+
input codersdk.ExternalAuthConfig
31+
expected codersdk.ExternalAuthConfig
32+
mutateExpected func(*codersdk.ExternalAuthConfig)
33+
}{
34+
// Cloud
35+
{
36+
name: "OnlyType",
37+
input: codersdk.ExternalAuthConfig{
38+
Type: string(codersdk.EnhancedExternalAuthProviderGitLab),
39+
},
40+
expected: cloud,
41+
},
42+
{
43+
// If someone was to manually configure the gitlab cli.
44+
name: "CloudByConfig",
45+
input: codersdk.ExternalAuthConfig{
46+
Type: string(codersdk.EnhancedExternalAuthProviderGitLab),
47+
AuthURL: "https://gitlab.com/oauth/authorize",
48+
},
49+
expected: cloud,
50+
},
51+
{
52+
// Changing some of the defaults of the cloud option
53+
name: "CloudWithChanges",
54+
input: codersdk.ExternalAuthConfig{
55+
Type: string(codersdk.EnhancedExternalAuthProviderGitLab),
56+
// Adding an extra query param intentionally to break simple
57+
// string comparisons.
58+
AuthURL: "https://gitlab.com/oauth/authorize?foo=bar",
59+
DisplayName: "custom",
60+
Regex: ".*",
61+
},
62+
expected: cloud,
63+
mutateExpected: func(config *codersdk.ExternalAuthConfig) {
64+
config.AuthURL = "https://gitlab.com/oauth/authorize?foo=bar"
65+
config.DisplayName = "custom"
66+
config.Regex = ".*"
67+
},
68+
},
69+
// Self-hosted
70+
{
71+
// Dynamically figures out the Validate, Token, and Regex fields.
72+
name: "SelfHostedOnlyAuthURL",
73+
input: codersdk.ExternalAuthConfig{
74+
Type: string(codersdk.EnhancedExternalAuthProviderGitLab),
75+
AuthURL: "https://gitlab.company.org/oauth/authorize?foo=bar",
76+
},
77+
expected: cloud,
78+
mutateExpected: func(config *codersdk.ExternalAuthConfig) {
79+
config.AuthURL = "https://gitlab.company.org/oauth/authorize?foo=bar"
80+
config.ValidateURL = "https://gitlab.company.org/oauth/token/info"
81+
config.TokenURL = "https://gitlab.company.org/oauth/token"
82+
config.Regex = `^(https?://)?gitlab\.company\.org(/.*)?$`
83+
},
84+
},
85+
{
86+
// Strange values
87+
name: "RandomValues",
88+
input: codersdk.ExternalAuthConfig{
89+
Type: string(codersdk.EnhancedExternalAuthProviderGitLab),
90+
AuthURL: "https://auth.com/auth",
91+
ValidateURL: "https://validate.com/validate",
92+
TokenURL: "https://token.com/token",
93+
Regex: "random",
94+
},
95+
expected: cloud,
96+
mutateExpected: func(config *codersdk.ExternalAuthConfig) {
97+
config.AuthURL = "https://auth.com/auth"
98+
config.ValidateURL = "https://validate.com/validate"
99+
config.TokenURL = "https://token.com/token"
100+
config.Regex = `random`
101+
},
102+
},
103+
}
104+
for _, c := range tests {
105+
c := c
106+
t.Run(c.name, func(t *testing.T) {
107+
t.Parallel()
108+
applyDefaultsToConfig(&c.input)
109+
if c.mutateExpected != nil {
110+
c.mutateExpected(&c.expected)
111+
}
112+
require.Equal(t, c.input, c.expected)
113+
})
114+
}
115+
}
116+
11117
func Test_bitbucketServerConfigDefaults(t *testing.T) {
12118
t.Parallel()
13119

0 commit comments

Comments
 (0)