Skip to content

Commit eb92a26

Browse files
authored
CLOUDP-333260: Delete api key from profile on logout (#4094)
1 parent e41b5d0 commit eb92a26

File tree

3 files changed

+244
-13
lines changed

3 files changed

+244
-13
lines changed

internal/cli/auth/logout.go

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ type ConfigDeleter interface {
3636
Delete() error
3737
SetAccessToken(string)
3838
SetRefreshToken(string)
39+
SetPublicAPIKey(string)
40+
SetPrivateAPIKey(string)
3941
SetProjectID(string)
4042
SetOrgID(string)
43+
AuthType() config.AuthMechanism
4144
Save() error
4245
}
4346

@@ -62,16 +65,30 @@ func (opts *logoutOpts) initFlow() error {
6265
}
6366

6467
func (opts *logoutOpts) Run(ctx context.Context) error {
65-
// revoking a refresh token revokes the access token
66-
if _, err := opts.flow.RevokeToken(ctx, config.RefreshToken(), "refresh_token"); err != nil {
67-
return err
68+
authType := opts.config.AuthType()
69+
70+
// Handle OAuth authentication - revoke tokens
71+
if authType == config.OAuth {
72+
if _, err := opts.flow.RevokeToken(ctx, config.RefreshToken(), "refresh_token"); err != nil {
73+
return err
74+
}
6875
}
6976

7077
if !opts.keepConfig {
7178
return opts.Delete(opts.config.Delete)
7279
}
73-
opts.config.SetAccessToken("")
74-
opts.config.SetRefreshToken("")
80+
81+
// Clear credentials based on auth type
82+
switch authType {
83+
case config.OAuth:
84+
opts.config.SetAccessToken("")
85+
opts.config.SetRefreshToken("")
86+
case config.APIKeys:
87+
opts.config.SetPublicAPIKey("")
88+
opts.config.SetPrivateAPIKey("")
89+
case config.NotLoggedIn:
90+
}
91+
7592
opts.config.SetProjectID("")
7693
opts.config.SetOrgID("")
7794
return opts.config.Save()
@@ -94,14 +111,23 @@ func LogoutBuilder() *cobra.Command {
94111
return opts.initFlow()
95112
},
96113
RunE: func(cmd *cobra.Command, _ []string) error {
97-
if config.RefreshToken() == "" {
114+
authType := config.AuthType()
115+
var accountIdentifier string
116+
var err error
117+
118+
switch authType {
119+
case config.OAuth:
120+
accountIdentifier, err = config.AccessTokenSubject()
121+
if err != nil {
122+
return err
123+
}
124+
case config.APIKeys:
125+
accountIdentifier = config.PublicAPIKey()
126+
case config.NotLoggedIn:
98127
return ErrUnauthenticated
99128
}
100-
s, err := config.AccessTokenSubject()
101-
if err != nil {
102-
return err
103-
}
104-
opts.Entry = s
129+
130+
opts.Entry = accountIdentifier
105131
if err := opts.PromptWithMessage("Are you sure you want to log out of account %s?"); err != nil || !opts.Confirm {
106132
return err
107133
}

internal/cli/auth/logout_mock_test.go

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

internal/cli/auth/logout_test.go

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ import (
1919
"testing"
2020

2121
"github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli"
22+
"github.com/mongodb/mongodb-atlas-cli/atlascli/internal/config"
2223
"github.com/stretchr/testify/require"
2324
"go.uber.org/mock/gomock"
2425
)
2526

26-
func Test_logoutOpts_Run(t *testing.T) {
27+
func Test_logoutOpts_Run_OAuth(t *testing.T) {
2728
ctrl := gomock.NewController(t)
2829
mockFlow := NewMockRevoker(ctrl)
2930
mockConfig := NewMockConfigDeleter(ctrl)
@@ -39,6 +40,12 @@ func Test_logoutOpts_Run(t *testing.T) {
3940
},
4041
}
4142
ctx := t.Context()
43+
44+
mockConfig.
45+
EXPECT().
46+
AuthType().
47+
Return(config.OAuth).
48+
Times(1)
4249
mockFlow.
4350
EXPECT().
4451
RevokeToken(ctx, gomock.Any(), gomock.Any()).
@@ -52,7 +59,38 @@ func Test_logoutOpts_Run(t *testing.T) {
5259
require.NoError(t, opts.Run(ctx))
5360
}
5461

55-
func Test_logoutOpts_Run_Keep(t *testing.T) {
62+
func Test_logoutOpts_Run_APIKeys(t *testing.T) {
63+
ctrl := gomock.NewController(t)
64+
mockFlow := NewMockRevoker(ctrl)
65+
mockConfig := NewMockConfigDeleter(ctrl)
66+
67+
buf := new(bytes.Buffer)
68+
69+
opts := logoutOpts{
70+
OutWriter: buf,
71+
config: mockConfig,
72+
flow: mockFlow,
73+
DeleteOpts: &cli.DeleteOpts{
74+
Confirm: true,
75+
},
76+
}
77+
ctx := t.Context()
78+
79+
mockConfig.
80+
EXPECT().
81+
AuthType().
82+
Return(config.APIKeys).
83+
Times(1)
84+
// No token revocation expected for API keys
85+
mockConfig.
86+
EXPECT().
87+
Delete().
88+
Return(nil).
89+
Times(1)
90+
require.NoError(t, opts.Run(ctx))
91+
}
92+
93+
func Test_logoutOpts_Run_Keep_OAuth(t *testing.T) {
5694
ctrl := gomock.NewController(t)
5795
mockFlow := NewMockRevoker(ctrl)
5896
mockConfig := NewMockConfigDeleter(ctrl)
@@ -69,6 +107,12 @@ func Test_logoutOpts_Run_Keep(t *testing.T) {
69107
keepConfig: true,
70108
}
71109
ctx := t.Context()
110+
111+
mockConfig.
112+
EXPECT().
113+
AuthType().
114+
Return(config.OAuth).
115+
Times(1)
72116
mockFlow.
73117
EXPECT().
74118
RevokeToken(ctx, gomock.Any(), gomock.Any()).
@@ -99,3 +143,53 @@ func Test_logoutOpts_Run_Keep(t *testing.T) {
99143

100144
require.NoError(t, opts.Run(ctx))
101145
}
146+
147+
func Test_logoutOpts_Run_Keep_APIKeys(t *testing.T) {
148+
ctrl := gomock.NewController(t)
149+
mockFlow := NewMockRevoker(ctrl)
150+
mockConfig := NewMockConfigDeleter(ctrl)
151+
152+
buf := new(bytes.Buffer)
153+
154+
opts := logoutOpts{
155+
OutWriter: buf,
156+
config: mockConfig,
157+
flow: mockFlow,
158+
DeleteOpts: &cli.DeleteOpts{
159+
Confirm: true,
160+
},
161+
keepConfig: true,
162+
}
163+
ctx := t.Context()
164+
165+
mockConfig.
166+
EXPECT().
167+
AuthType().
168+
Return(config.APIKeys).
169+
Times(1)
170+
// No token revocation for API keys
171+
172+
mockConfig.
173+
EXPECT().
174+
SetPublicAPIKey("").
175+
Times(1)
176+
mockConfig.
177+
EXPECT().
178+
SetPrivateAPIKey("").
179+
Times(1)
180+
mockConfig.
181+
EXPECT().
182+
SetProjectID("").
183+
Times(1)
184+
mockConfig.
185+
EXPECT().
186+
SetOrgID("").
187+
Times(1)
188+
mockConfig.
189+
EXPECT().
190+
Save().
191+
Return(nil).
192+
Times(1)
193+
194+
require.NoError(t, opts.Run(ctx))
195+
}

0 commit comments

Comments
 (0)