Skip to content

Commit b34a67e

Browse files
authored
fix: Allow custom Git OAuth URLs (#4758)
Fixes an issue reported in Discord where custom endpoints weren't working.
1 parent 3e15ee3 commit b34a67e

File tree

8 files changed

+63
-13
lines changed

8 files changed

+63
-13
lines changed

agent/agent.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,11 @@ func (a *agent) createTailnet(ctx context.Context, derpMap *tailcfg.DERPMap) (*t
242242
if err != nil {
243243
return nil, xerrors.Errorf("listen on the ssh port: %w", err)
244244
}
245+
a.closeMutex.Lock()
246+
a.connCloseWait.Add(1)
247+
a.closeMutex.Unlock()
245248
go func() {
249+
defer a.connCloseWait.Done()
246250
for {
247251
conn, err := sshListener.Accept()
248252
if err != nil {
@@ -256,7 +260,11 @@ func (a *agent) createTailnet(ctx context.Context, derpMap *tailcfg.DERPMap) (*t
256260
if err != nil {
257261
return nil, xerrors.Errorf("listen for reconnecting pty: %w", err)
258262
}
263+
a.closeMutex.Lock()
264+
a.connCloseWait.Add(1)
265+
a.closeMutex.Unlock()
259266
go func() {
267+
defer a.connCloseWait.Done()
260268
for {
261269
conn, err := reconnectingPTYListener.Accept()
262270
if err != nil {
@@ -290,7 +298,11 @@ func (a *agent) createTailnet(ctx context.Context, derpMap *tailcfg.DERPMap) (*t
290298
if err != nil {
291299
return nil, xerrors.Errorf("listen for speedtest: %w", err)
292300
}
301+
a.closeMutex.Lock()
302+
a.connCloseWait.Add(1)
303+
a.closeMutex.Unlock()
293304
go func() {
305+
defer a.connCloseWait.Done()
294306
for {
295307
conn, err := speedtestListener.Accept()
296308
if err != nil {
@@ -311,7 +323,11 @@ func (a *agent) createTailnet(ctx context.Context, derpMap *tailcfg.DERPMap) (*t
311323
if err != nil {
312324
return nil, xerrors.Errorf("listen for statistics: %w", err)
313325
}
326+
a.closeMutex.Lock()
327+
a.connCloseWait.Add(1)
328+
a.closeMutex.Unlock()
314329
go func() {
330+
defer a.connCloseWait.Done()
315331
defer statisticsListener.Close()
316332
server := &http.Server{
317333
Handler: a.statisticsHandler(),

cli/deployment/config.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,14 +462,20 @@ func readSliceFromViper[T any](vip *viper.Viper, key string, value any) []T {
462462
if prop == "-" {
463463
prop = fve.Tag.Get("yaml")
464464
}
465-
value := vip.Get(fmt.Sprintf("%s.%d.%s", key, entry, prop))
465+
configKey := fmt.Sprintf("%s.%d.%s", key, entry, prop)
466+
value := vip.Get(configKey)
466467
if value == nil {
467468
continue
468469
}
469470
if instance == nil {
470471
newType := reflect.Indirect(reflect.New(elementType))
471472
instance = &newType
472473
}
474+
switch instance.Field(i).Type().String() {
475+
case "[]string":
476+
value = vip.GetStringSlice(configKey)
477+
default:
478+
}
473479
instance.Field(i).Set(reflect.ValueOf(value))
474480
}
475481
if instance == nil {

cli/deployment/config_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ func TestConfig(t *testing.T) {
158158
"CODER_GITAUTH_0_AUTH_URL": "https://auth.com",
159159
"CODER_GITAUTH_0_TOKEN_URL": "https://token.com",
160160
"CODER_GITAUTH_0_REGEX": "github.com",
161+
"CODER_GITAUTH_0_SCOPES": "read write",
161162

162163
"CODER_GITAUTH_1_ID": "another",
163164
"CODER_GITAUTH_1_TYPE": "gitlab",
@@ -177,6 +178,7 @@ func TestConfig(t *testing.T) {
177178
AuthURL: "https://auth.com",
178179
TokenURL: "https://token.com",
179180
Regex: "github.com",
181+
Scopes: []string{"read", "write"},
180182
}, {
181183
ID: "another",
182184
Type: "gitlab",

coderd/gitauth/config.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,16 @@ func ConvertConfig(entries []codersdk.GitAuthConfig, accessURL *url.URL) ([]*Con
8686
Scopes: scope[typ],
8787
}
8888

89+
if entry.AuthURL != "" {
90+
oauth2Config.Endpoint.AuthURL = entry.AuthURL
91+
}
92+
if entry.TokenURL != "" {
93+
oauth2Config.Endpoint.TokenURL = entry.TokenURL
94+
}
95+
if entry.Scopes != nil && len(entry.Scopes) > 0 {
96+
oauth2Config.Scopes = entry.Scopes
97+
}
98+
8999
var oauthConfig httpmw.OAuth2Config = oauth2Config
90100
// Azure DevOps uses JWT token authentication!
91101
if typ == codersdk.GitProviderAzureDevops {

coderd/gitauth/config_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,18 @@ func TestConvertYAML(t *testing.T) {
7575
require.Equal(t, tc.Output, output)
7676
})
7777
}
78+
79+
t.Run("CustomScopesAndEndpoint", func(t *testing.T) {
80+
t.Parallel()
81+
config, err := gitauth.ConvertConfig([]codersdk.GitAuthConfig{{
82+
Type: codersdk.GitProviderGitLab,
83+
ClientID: "id",
84+
ClientSecret: "secret",
85+
AuthURL: "https://auth.com",
86+
TokenURL: "https://token.com",
87+
Scopes: []string{"read"},
88+
}}, &url.URL{})
89+
require.NoError(t, err)
90+
require.Equal(t, "https://auth.com?client_id=id&redirect_uri=%2Fgitauth%2Fgitlab%2Fcallback&response_type=code&scope=read", config[0].AuthCodeURL(""))
91+
})
7892
}

codersdk/client_internal_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func Test_readBodyAsError(t *testing.T) {
3434
longResponse += "a"
3535
}
3636

37-
unexpectedJSON := marshalJSON(map[string]any{
37+
unexpectedJSON := marshal(map[string]any{
3838
"hello": "world",
3939
"foo": "bar",
4040
})
@@ -49,7 +49,7 @@ func Test_readBodyAsError(t *testing.T) {
4949
{
5050
name: "JSONWithRequest",
5151
req: httptest.NewRequest(http.MethodGet, exampleURL, nil),
52-
res: newResponse(http.StatusNotFound, jsonCT, marshalJSON(simpleResponse)),
52+
res: newResponse(http.StatusNotFound, jsonCT, marshal(simpleResponse)),
5353
assert: func(t *testing.T, err error) {
5454
sdkErr := assertSDKError(t, err)
5555

@@ -72,7 +72,7 @@ func Test_readBodyAsError(t *testing.T) {
7272
{
7373
name: "JSONWithoutRequest",
7474
req: nil,
75-
res: newResponse(http.StatusNotFound, jsonCT, marshalJSON(simpleResponse)),
75+
res: newResponse(http.StatusNotFound, jsonCT, marshal(simpleResponse)),
7676
assert: func(t *testing.T, err error) {
7777
sdkErr := assertSDKError(t, err)
7878

@@ -86,7 +86,7 @@ func Test_readBodyAsError(t *testing.T) {
8686
{
8787
name: "UnauthorizedHelper",
8888
req: nil,
89-
res: newResponse(http.StatusUnauthorized, jsonCT, marshalJSON(simpleResponse)),
89+
res: newResponse(http.StatusUnauthorized, jsonCT, marshal(simpleResponse)),
9090
assert: func(t *testing.T, err error) {
9191
sdkErr := assertSDKError(t, err)
9292

@@ -190,7 +190,7 @@ func newResponse(status int, contentType string, body interface{}) *http.Respons
190190
}
191191
}
192192

193-
func marshalJSON(res any) string {
193+
func marshal(res any) string {
194194
b, err := json.Marshal(res)
195195
if err != nil {
196196
panic(err)

codersdk/deploymentconfig.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,14 @@ type TLSConfig struct {
108108
}
109109

110110
type GitAuthConfig struct {
111-
ID string `json:"id"`
112-
Type string `json:"type"`
113-
ClientID string `json:"client_id"`
114-
ClientSecret string `json:"-" yaml:"client_secret"`
115-
AuthURL string `json:"auth_url"`
116-
TokenURL string `json:"token_url"`
117-
Regex string `json:"regex"`
111+
ID string `json:"id"`
112+
Type string `json:"type"`
113+
ClientID string `json:"client_id"`
114+
ClientSecret string `json:"-" yaml:"client_secret"`
115+
AuthURL string `json:"auth_url"`
116+
TokenURL string `json:"token_url"`
117+
Regex string `json:"regex"`
118+
Scopes []string `json:"scopes"`
118119
}
119120

120121
type Flaggable interface {

site/src/api/typesGenerated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ export interface GitAuthConfig {
354354
readonly auth_url: string
355355
readonly token_url: string
356356
readonly regex: string
357+
readonly scopes: string[]
357358
}
358359

359360
// From codersdk/gitsshkey.go

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy