Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita511812

Browse files
committed
feat: add best effort attempt to revoke oauth access token in provider
1 parente6b04d1 commita511812

File tree

15 files changed

+148
-38
lines changed

15 files changed

+148
-38
lines changed

‎cli/server.go‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2692,6 +2692,8 @@ func parseExternalAuthProvidersFromEnv(prefix string, environ []string) ([]coder
26922692
provider.AuthURL=v.Value
26932693
case"TOKEN_URL":
26942694
provider.TokenURL=v.Value
2695+
case"REVOKE_URL":
2696+
provider.RevokeURL=v.Value
26952697
case"VALIDATE_URL":
26962698
provider.ValidateURL=v.Value
26972699
case"REGEX":

‎cli/server_test.go‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ func TestReadExternalAuthProvidersFromEnv(t *testing.T) {
7676
"CODER_EXTERNAL_AUTH_1_CLIENT_SECRET=hunter12",
7777
"CODER_EXTERNAL_AUTH_1_TOKEN_URL=google.com",
7878
"CODER_EXTERNAL_AUTH_1_VALIDATE_URL=bing.com",
79+
"CODER_EXTERNAL_AUTH_1_REVOKE_URL=revoke.url",
7980
"CODER_EXTERNAL_AUTH_1_SCOPES=repo:read repo:write",
8081
"CODER_EXTERNAL_AUTH_1_NO_REFRESH=true",
8182
"CODER_EXTERNAL_AUTH_1_DISPLAY_NAME=Google",
@@ -87,13 +88,15 @@ func TestReadExternalAuthProvidersFromEnv(t *testing.T) {
8788
// Validate the first provider.
8889
assert.Equal(t,"1",providers[0].ID)
8990
assert.Equal(t,"gitlab",providers[0].Type)
91+
assert.Equal(t,"",providers[0].RevokeURL)
9092

9193
// Validate the second provider.
9294
assert.Equal(t,"2",providers[1].ID)
9395
assert.Equal(t,"sid",providers[1].ClientID)
9496
assert.Equal(t,"hunter12",providers[1].ClientSecret)
9597
assert.Equal(t,"google.com",providers[1].TokenURL)
9698
assert.Equal(t,"bing.com",providers[1].ValidateURL)
99+
assert.Equal(t,"revoke.url",providers[1].RevokeURL)
97100
assert.Equal(t, []string{"repo:read","repo:write"},providers[1].Scopes)
98101
assert.Equal(t,true,providers[1].NoRefresh)
99102
assert.Equal(t,"Google",providers[1].DisplayName)

‎coderd/apidoc/docs.go‎

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/apidoc/swagger.json‎

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/externalauth.go‎

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,29 @@ func (api *API) deleteExternalAuthByID(w http.ResponseWriter, r *http.Request) {
9393
apiKey:=httpmw.APIKey(r)
9494
ctx:=r.Context()
9595

96-
err:=api.Database.DeleteExternalAuthLink(ctx, database.DeleteExternalAuthLinkParams{
96+
link,err:=api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{
9797
ProviderID:config.ID,
9898
UserID:apiKey.UserID,
9999
})
100+
100101
iferr!=nil {
101-
if!errors.Is(err,sql.ErrNoRows) {
102+
iferrors.Is(err,sql.ErrNoRows) {
103+
httpapi.ResourceNotFound(w)
104+
return
105+
}
106+
httpapi.Write(ctx,w,http.StatusInternalServerError, codersdk.Response{
107+
Message:"Failed to get external auth link during deletion.",
108+
Detail:err.Error(),
109+
})
110+
return
111+
}
112+
113+
err=api.Database.DeleteExternalAuthLink(ctx, database.DeleteExternalAuthLinkParams{
114+
ProviderID:config.ID,
115+
UserID:apiKey.UserID,
116+
})
117+
iferr!=nil {
118+
iferrors.Is(err,sql.ErrNoRows) {
102119
httpapi.ResourceNotFound(w)
103120
return
104121
}
@@ -109,7 +126,13 @@ func (api *API) deleteExternalAuthByID(w http.ResponseWriter, r *http.Request) {
109126
return
110127
}
111128

112-
httpapi.Write(ctx,w,http.StatusOK,"OK")
129+
ok,err:=config.RevokeToken(ctx,link)
130+
iferr!=nil||!ok {
131+
httpapi.Write(ctx,w,http.StatusOK,"Successfully deleted external auth link, access token has NOT been revoked from the oauth2 provider.")
132+
return
133+
}
134+
135+
httpapi.Write(ctx,w,http.StatusOK,"Successfully deleted external auth link and revoked token from the oauth2 provider")
113136
}
114137

115138
// @Summary Post external auth device by ID
@@ -394,13 +417,14 @@ func ExternalAuthConfigs(auths []*externalauth.Config) []codersdk.ExternalAuthLi
394417

395418
funcExternalAuthConfig(cfg*externalauth.Config) codersdk.ExternalAuthLinkProvider {
396419
return codersdk.ExternalAuthLinkProvider{
397-
ID:cfg.ID,
398-
Type:cfg.Type,
399-
Device:cfg.DeviceAuth!=nil,
400-
DisplayName:cfg.DisplayName,
401-
DisplayIcon:cfg.DisplayIcon,
402-
AllowRefresh:!cfg.NoRefresh,
403-
AllowValidate:cfg.ValidateURL!="",
420+
ID:cfg.ID,
421+
Type:cfg.Type,
422+
Device:cfg.DeviceAuth!=nil,
423+
DisplayName:cfg.DisplayName,
424+
DisplayIcon:cfg.DisplayIcon,
425+
AllowRefresh:!cfg.NoRefresh,
426+
AllowValidate:cfg.ValidateURL!="",
427+
SupportsRevocation:cfg.RevokeURL!="",
404428
}
405429
}
406430

‎coderd/externalauth/externalauth.go‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ type Config struct {
4343
IDstring
4444
// Type is the type of provider.
4545
Typestring
46+
47+
ClientIdstring
48+
ClientSecretstring
4649
// DeviceAuth is set if the provider uses the device flow.
4750
DeviceAuth*DeviceAuth
4851
// DisplayName is the name of the provider to display to the user.
@@ -69,6 +72,8 @@ type Config struct {
6972
// not be validated before being returned.
7073
ValidateURLstring
7174

75+
RevokeURLstring
76+
7277
// Regex is a Regexp matched against URLs for
7378
// a Git clone. e.g. "Username for 'https://github.com':"
7479
// The regex would be `github\.com`..
@@ -385,6 +390,55 @@ func (c *Config) AppInstallations(ctx context.Context, token string) ([]codersdk
385390
returninstalls,true,nil
386391
}
387392

393+
func (c*Config)RevokeToken(ctx context.Context,link database.ExternalAuthLink) (bool,error) {
394+
ifc.RevokeURL=="" {
395+
returnfalse,nil
396+
}
397+
398+
varerrerror
399+
varreq*http.Request
400+
ifc.Type==codersdk.EnhancedExternalAuthProviderGitHub.String() {
401+
req,err=c.tokenRevocationRequestGitHub(ctx,link)
402+
}else {
403+
req,err=c.tokenRevocationRequestRFC7009(ctx,link)
404+
}
405+
iferr!=nil {
406+
returnfalse,err
407+
}
408+
409+
res,err:=c.InstrumentedOAuth2Config.Do(ctx,promoauth.SourceRevoke,req)
410+
iferr!=nil {
411+
returnfalse,err
412+
}
413+
deferres.Body.Close()
414+
415+
returnres.StatusCode==http.StatusOK,nil
416+
}
417+
418+
func (c*Config)tokenRevocationRequestRFC7009(ctx context.Context,link database.ExternalAuthLink) (*http.Request,error) {
419+
p:= url.Values{}
420+
p.Add("client_id",c.ClientId)
421+
p.Add("client_secret",c.ClientSecret)
422+
p.Add("token_type_hint","refresh_token")
423+
p.Add("token",link.OAuthRefreshToken)
424+
body:=p.Encode()
425+
returnhttp.NewRequestWithContext(ctx,http.MethodPost,c.RevokeURL,strings.NewReader(body))
426+
}
427+
428+
func (c*Config)tokenRevocationRequestGitHub(ctx context.Context,link database.ExternalAuthLink) (*http.Request,error) {
429+
// GitHub doesn't follow RFC spec, GitHub specific request is needed
430+
// https://docs.github.com/en/rest/apps/oauth-applications?apiVersion=2022-11-28#delete-an-app-authorization
431+
body:=fmt.Sprintf("{\"access_token\":\"%s\"}",link.OAuthAccessToken)
432+
req,err:=http.NewRequestWithContext(ctx,http.MethodDelete,c.RevokeURL,strings.NewReader(body))
433+
iferr!=nil {
434+
returnnil,err
435+
}
436+
req.Header.Add("Accept","application/vnd.github+json")
437+
req.Header.Add("X-GitHub-Api-Version","2022-11-28")
438+
req.SetBasicAuth(c.ClientId,c.ClientSecret)
439+
returnreq,nil
440+
}
441+
388442
typeDeviceAuthstruct {
389443
// Config is provided for the http client method.
390444
Config promoauth.InstrumentedOAuth2Config
@@ -611,10 +665,13 @@ func ConvertConfig(instrument *promoauth.Factory, entries []codersdk.ExternalAut
611665
cfg:=&Config{
612666
InstrumentedOAuth2Config:instrumented,
613667
ID:entry.ID,
668+
ClientId:entry.ClientID,
669+
ClientSecret:entry.ClientSecret,
614670
Regex:regex,
615671
Type:entry.Type,
616672
NoRefresh:entry.NoRefresh,
617673
ValidateURL:entry.ValidateURL,
674+
RevokeURL:entry.RevokeURL,
618675
AppInstallationsURL:entry.AppInstallationsURL,
619676
AppInstallURL:entry.AppInstallURL,
620677
DisplayName:entry.DisplayName,
@@ -776,6 +833,7 @@ func gitlabDefaults(config *codersdk.ExternalAuthConfig) codersdk.ExternalAuthCo
776833
AuthURL:"https://gitlab.com/oauth/authorize",
777834
TokenURL:"https://gitlab.com/oauth/token",
778835
ValidateURL:"https://gitlab.com/oauth/token/info",
836+
RevokeURL:"https://gitlab.com/oauth/revoke",
779837
DisplayName:"GitLab",
780838
DisplayIcon:"/icon/gitlab.svg",
781839
Regex:`^(https?://)?gitlab\.com(/.*)?$`,
@@ -801,6 +859,7 @@ func gitlabDefaults(config *codersdk.ExternalAuthConfig) codersdk.ExternalAuthCo
801859
AuthURL:au.ResolveReference(&url.URL{Path:"/oauth/authorize"}).String(),
802860
TokenURL:au.ResolveReference(&url.URL{Path:"/oauth/token"}).String(),
803861
ValidateURL:au.ResolveReference(&url.URL{Path:"/oauth/token/info"}).String(),
862+
RevokeURL:au.ResolveReference(&url.URL{Path:"/oauth/revoke"}).String(),
804863
Regex:fmt.Sprintf(`^(https?://)?%s(/.*)?$`,strings.ReplaceAll(au.Host,".",`\.`)),
805864
}
806865
}
@@ -942,6 +1001,7 @@ var staticDefaults = map[codersdk.EnhancedExternalAuthProvider]codersdk.External
9421001
codersdk.EnhancedExternalAuthProviderSlack: {
9431002
AuthURL:"https://slack.com/oauth/v2/authorize",
9441003
TokenURL:"https://slack.com/api/oauth.v2.access",
1004+
RevokeURL:"https://slack.com/api/auth.revoke",
9451005
DisplayName:"Slack",
9461006
DisplayIcon:"/icon/slack.svg",
9471007
// See: https://api.slack.com/authentication/oauth-v2#exchanging

‎coderd/promoauth/oauth2.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const (
1919
SourceTokenSourceOauth2Source="TokenSource"
2020
SourceAppInstallationsOauth2Source="AppInstallations"
2121
SourceAuthorizeDeviceOauth2Source="AuthorizeDevice"
22+
SourceRevokeOauth2Source="Revoke"
2223

2324
SourceGitAPIAuthUserOauth2Source="GitAPIAuthUser"
2425
SourceGitAPIListEmailsOauth2Source="GitAPIListEmails"

‎codersdk/deployment.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,7 @@ type ExternalAuthConfig struct {
735735
AuthURLstring`json:"auth_url" yaml:"auth_url"`
736736
TokenURLstring`json:"token_url" yaml:"token_url"`
737737
ValidateURLstring`json:"validate_url" yaml:"validate_url"`
738+
RevokeURLstring`json:"-" yaml:"revoke_url"`
738739
AppInstallURLstring`json:"app_install_url" yaml:"app_install_url"`
739740
AppInstallationsURLstring`json:"app_installations_url" yaml:"app_installations_url"`
740741
NoRefreshbool`json:"no_refresh" yaml:"no_refresh"`

‎codersdk/externalauth.go‎

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ const (
4949
)
5050

5151
typeExternalAuthstruct {
52-
Authenticatedbool`json:"authenticated"`
53-
Devicebool`json:"device"`
54-
DisplayNamestring`json:"display_name"`
52+
Authenticatedbool`json:"authenticated"`
53+
Devicebool`json:"device"`
54+
DisplayNamestring`json:"display_name"`
55+
SupportsRevocationbool`json:"supports_revocation"`
5556

5657
// User is the user that authenticated with the provider.
5758
User*ExternalAuthUser`json:"user"`
@@ -87,13 +88,14 @@ type ExternalAuthLink struct {
8788

8889
// ExternalAuthLinkProvider are the static details of a provider.
8990
typeExternalAuthLinkProviderstruct {
90-
IDstring`json:"id"`
91-
Typestring`json:"type"`
92-
Devicebool`json:"device"`
93-
DisplayNamestring`json:"display_name"`
94-
DisplayIconstring`json:"display_icon"`
95-
AllowRefreshbool`json:"allow_refresh"`
96-
AllowValidatebool`json:"allow_validate"`
91+
IDstring`json:"id"`
92+
Typestring`json:"type"`
93+
Devicebool`json:"device"`
94+
DisplayNamestring`json:"display_name"`
95+
DisplayIconstring`json:"display_icon"`
96+
AllowRefreshbool`json:"allow_refresh"`
97+
AllowValidatebool`json:"allow_validate"`
98+
SupportsRevocationbool`json:"supports_revocation"`
9799
}
98100

99101
typeExternalAuthAppInstallationstruct {

‎docs/reference/api/git.md‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp