Skip to content

Commit a2e66ed

Browse files
authored
CLOUDP-337696: Enable logout from Service Account (#4139)
1 parent 4ff78c2 commit a2e66ed

File tree

4 files changed

+297
-27
lines changed

4 files changed

+297
-27
lines changed

internal/cli/auth/logout.go

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/mongodb/mongodb-atlas-cli/atlascli/internal/transport"
2828
"github.com/mongodb/mongodb-atlas-cli/atlascli/internal/usage"
2929
"github.com/spf13/cobra"
30+
"go.mongodb.org/atlas-sdk/v20250312006/auth/clientcredentials"
3031
atlas "go.mongodb.org/atlas/mongodbatlas"
3132
)
3233

@@ -41,8 +42,14 @@ type ConfigDeleter interface {
4142
SetOrgID(string)
4243
SetPublicAPIKey(string)
4344
SetPrivateAPIKey(string)
45+
SetClientID(string)
46+
SetClientSecret(string)
4447
AuthType() config.AuthMechanism
4548
PublicAPIKey() string
49+
ClientID() string
50+
ClientSecret() string
51+
AccessTokenSubject() (string, error)
52+
RefreshToken() string
4653
Save() error
4754
}
4855

@@ -53,32 +60,56 @@ type Revoker interface {
5360
type logoutOpts struct {
5461
*cli.DeleteOpts
5562
cli.DefaultSetterOpts
56-
OutWriter io.Writer
57-
config ConfigDeleter
58-
flow Revoker
59-
keepConfig bool
63+
OutWriter io.Writer
64+
config ConfigDeleter
65+
flow Revoker
66+
keepConfig bool
67+
revokeServiceAccountToken func() error
6068
}
6169

62-
func (opts *logoutOpts) initFlow() error {
70+
func (opts *logoutOpts) initFlow(ctx context.Context) error {
6371
var err error
6472
client := http.DefaultClient
6573
client.Transport = transport.Default()
6674
opts.flow, err = oauth.FlowWithConfig(config.Default(), client)
75+
opts.revokeServiceAccountToken = func() error {
76+
return revokeServiceAccountToken(ctx, opts.config.ClientID(), opts.config.ClientSecret())
77+
}
6778
return err
6879
}
6980

81+
func revokeServiceAccountToken(ctx context.Context, clientID, clientSecret string) error {
82+
cfg := clientcredentials.NewConfig(clientID, clientSecret)
83+
if config.OpsManagerURL() != "" {
84+
// TokenURL and RevokeURL points to "https://cloud.mongodb.com/api/oauth/<token/revoke>". Modify TokenURL and RevokeURL if OpsManagerURL does not point to cloud.mongodb.com
85+
cfg.TokenURL = config.OpsManagerURL() + clientcredentials.TokenAPIPath
86+
cfg.RevokeURL = config.OpsManagerURL() + clientcredentials.RevokeAPIPath
87+
}
88+
token, err := cfg.Token(ctx)
89+
if err != nil {
90+
return err
91+
}
92+
return cfg.RevokeToken(ctx, token)
93+
}
94+
7095
func (opts *logoutOpts) Run(ctx context.Context) error {
7196
if !opts.Confirm {
7297
return nil
7398
}
7499

75100
switch opts.config.AuthType() {
76-
case config.ServiceAccount, config.UserAccount:
101+
case config.UserAccount:
77102
if _, err := opts.flow.RevokeToken(ctx, config.RefreshToken(), "refresh_token"); err != nil {
78103
return err
79104
}
80105
opts.config.SetAccessToken("")
81106
opts.config.SetRefreshToken("")
107+
case config.ServiceAccount:
108+
if err := opts.revokeServiceAccountToken(); err != nil {
109+
return err
110+
}
111+
opts.config.SetClientID("")
112+
opts.config.SetClientSecret("")
82113
case config.APIKeys:
83114
opts.config.SetPublicAPIKey("")
84115
opts.config.SetPrivateAPIKey("")
@@ -87,6 +118,8 @@ func (opts *logoutOpts) Run(ctx context.Context) error {
87118
opts.config.SetPrivateAPIKey("")
88119
opts.config.SetAccessToken("")
89120
opts.config.SetRefreshToken("")
121+
opts.config.SetClientID("")
122+
opts.config.SetClientSecret("")
90123
}
91124

92125
opts.config.SetProjectID("")
@@ -122,7 +155,7 @@ func LogoutBuilder() *cobra.Command {
122155

123156
// Only initialize OAuth flow if we have OAuth-based auth
124157
if opts.config.AuthType() == config.UserAccount || opts.config.AuthType() == config.ServiceAccount {
125-
return opts.initFlow()
158+
return opts.initFlow(cmd.Context())
126159
}
127160

128161
return nil
@@ -135,13 +168,16 @@ func LogoutBuilder() *cobra.Command {
135168
case config.APIKeys:
136169
entry = opts.config.PublicAPIKey()
137170
message = "Are you sure you want to log out of account with public API key %s?"
138-
case config.ServiceAccount, config.UserAccount:
139-
entry, err = config.AccessTokenSubject()
171+
case config.ServiceAccount:
172+
entry = opts.config.ClientID()
173+
message = "Are you sure you want to log out of service account %s?"
174+
case config.UserAccount:
175+
entry, err = opts.config.AccessTokenSubject()
140176
if err != nil {
141177
return err
142178
}
143179

144-
if config.RefreshToken() == "" {
180+
if opts.config.RefreshToken() == "" {
145181
return ErrUnauthenticated
146182
}
147183

internal/cli/auth/logout_mock_test.go

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

0 commit comments

Comments
 (0)