Skip to content

Commit 0748918

Browse files
authored
fix: remove deprecated refresh token usage (#1255)
relates to STACKITCLI-316
1 parent 2b34f71 commit 0748918

File tree

4 files changed

+73
-92
lines changed

4 files changed

+73
-92
lines changed

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.24.0
55
require (
66
github.com/fatih/color v1.18.0
77
github.com/goccy/go-yaml v1.19.2
8-
github.com/golang-jwt/jwt/v5 v5.3.0
8+
github.com/golang-jwt/jwt/v5 v5.3.1
99
github.com/google/go-cmp v0.7.0
1010
github.com/google/uuid v1.6.0
1111
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
@@ -15,7 +15,7 @@ require (
1515
github.com/spf13/cobra v1.10.2
1616
github.com/spf13/pflag v1.0.10
1717
github.com/spf13/viper v1.21.0
18-
github.com/stackitcloud/stackit-sdk-go/core v0.20.1
18+
github.com/stackitcloud/stackit-sdk-go/core v0.21.1
1919
github.com/stackitcloud/stackit-sdk-go/services/alb v0.9.0
2020
github.com/stackitcloud/stackit-sdk-go/services/authorization v0.11.0
2121
github.com/stackitcloud/stackit-sdk-go/services/cdn v1.9.1

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,8 @@ github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8
252252
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
253253
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
254254
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
255-
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
256-
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
255+
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
256+
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
257257
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
258258
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
259259
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -600,8 +600,8 @@ github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
600600
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
601601
github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
602602
github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
603-
github.com/stackitcloud/stackit-sdk-go/core v0.20.1 h1:odiuhhRXmxvEvnVTeZSN9u98edvw2Cd3DcnkepncP3M=
604-
github.com/stackitcloud/stackit-sdk-go/core v0.20.1/go.mod h1:fqto7M82ynGhEnpZU6VkQKYWYoFG5goC076JWXTUPRQ=
603+
github.com/stackitcloud/stackit-sdk-go/core v0.21.1 h1:Y/PcAgM7DPYMNqum0MLv4n1mF9ieuevzcCIZYQfm3Ts=
604+
github.com/stackitcloud/stackit-sdk-go/core v0.21.1/go.mod h1:osMglDby4csGZ5sIfhNyYq1bS1TxIdPY88+skE/kkmI=
605605
github.com/stackitcloud/stackit-sdk-go/services/alb v0.9.0 h1:P24WoKPt14dfUiUJ4czIv+IiVmdCFQGrKgVtw23fxNg=
606606
github.com/stackitcloud/stackit-sdk-go/services/alb v0.9.0/go.mod h1:63XvbCslxdfWEp+0Q4OSzQrpbY4kvVODOiIEAEEVH8M=
607607
github.com/stackitcloud/stackit-sdk-go/services/authorization v0.11.0 h1:4YFY5PG4vP/NiEP1uxCwh+kQHEU7iHG6syuFD7NPqcw=

internal/pkg/auth/auth_test.go

Lines changed: 54 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import (
44
"crypto/rand"
55
"crypto/rsa"
66
"crypto/x509"
7+
"encoding/json"
78
"encoding/pem"
89
"fmt"
910
"io"
11+
"net/http"
12+
"net/http/httptest"
1013
"strconv"
1114
"testing"
1215
"time"
@@ -235,58 +238,28 @@ func TestAuthenticationConfig(t *testing.T) {
235238

236239
func TestInitKeyFlow(t *testing.T) {
237240
tests := []struct {
238-
description string
239-
accessTokenSet bool
240-
refreshToken string
241-
saKey string
242-
privateKeySet bool
243-
tokenEndpoint string
244-
isValid bool
241+
description string
242+
saKey string
243+
privateKeySet bool
244+
isValid bool
245245
}{
246246
{
247-
description: "base",
248-
accessTokenSet: true,
249-
refreshToken: "refresh_token",
250-
saKey: testServiceAccountKey,
251-
privateKeySet: true,
252-
tokenEndpoint: "token_url",
253-
isValid: true,
247+
description: "base",
248+
saKey: testServiceAccountKey,
249+
privateKeySet: true,
250+
isValid: true,
254251
},
255252
{
256-
description: "invalid_service_account_key",
257-
accessTokenSet: true,
258-
refreshToken: "refresh_token",
259-
saKey: "",
260-
privateKeySet: true,
261-
tokenEndpoint: "token_url",
262-
isValid: false,
263-
},
264-
{
265-
description: "invalid_private_key",
266-
accessTokenSet: true,
267-
refreshToken: "refresh_token",
268-
saKey: testServiceAccountKey,
269-
privateKeySet: false,
270-
tokenEndpoint: "token_url",
271-
isValid: false,
272-
},
273-
{
274-
description: "invalid_access_token",
275-
accessTokenSet: false,
276-
refreshToken: "refresh_token",
277-
saKey: testServiceAccountKey,
278-
privateKeySet: true,
279-
tokenEndpoint: "token_url",
280-
isValid: false,
253+
description: "invalid_service_account_key",
254+
saKey: "",
255+
privateKeySet: true,
256+
isValid: false,
281257
},
282258
{
283-
description: "empty_refresh_token",
284-
accessTokenSet: false,
285-
refreshToken: "",
286-
saKey: testServiceAccountKey,
287-
privateKeySet: true,
288-
tokenEndpoint: "token_url",
289-
isValid: false,
259+
description: "no_private_key_set",
260+
saKey: testServiceAccountKey,
261+
privateKeySet: false,
262+
isValid: false,
290263
},
291264
}
292265

@@ -297,13 +270,11 @@ func TestInitKeyFlow(t *testing.T) {
297270
authFields := make(map[authFieldKey]string)
298271
var accessToken string
299272
var err error
300-
if tt.accessTokenSet {
301-
accessTokenJWT := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{
302-
ExpiresAt: jwt.NewNumericDate(timestamp)})
303-
accessToken, err = accessTokenJWT.SignedString(testSigningKey)
304-
if err != nil {
305-
t.Fatalf("Get test access token as string: %s", err)
306-
}
273+
accessTokenJWT := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{
274+
ExpiresAt: jwt.NewNumericDate(timestamp)})
275+
accessToken, err = accessTokenJWT.SignedString(testSigningKey)
276+
if err != nil {
277+
t.Fatalf("Get test access token as string: %s", err)
307278
}
308279
if tt.privateKeySet {
309280
privateKey, err := generatePrivateKey()
@@ -313,16 +284,42 @@ func TestInitKeyFlow(t *testing.T) {
313284
authFields[PRIVATE_KEY] = string(privateKey)
314285
}
315286
authFields[ACCESS_TOKEN] = accessToken
316-
authFields[REFRESH_TOKEN] = tt.refreshToken
317287
authFields[SERVICE_ACCOUNT_KEY] = tt.saKey
318-
authFields[TOKEN_CUSTOM_ENDPOINT] = tt.tokenEndpoint
288+
289+
// Mock server to avoid HTTP calls
290+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
291+
w.WriteHeader(http.StatusOK)
292+
resp := clients.TokenResponseBody{
293+
AccessToken: accessToken,
294+
ExpiresIn: 3600,
295+
TokenType: "Bearer",
296+
}
297+
jsonResp, err := json.Marshal(resp)
298+
if err != nil {
299+
t.Fatalf("Failed to marshal json: %v", err)
300+
}
301+
_, err = w.Write(jsonResp)
302+
if err != nil {
303+
t.Fatalf("Failed to write response: %v", err)
304+
}
305+
}))
306+
defer server.Close()
307+
authFields[TOKEN_CUSTOM_ENDPOINT] = server.URL
308+
319309
err = SetAuthFieldMap(authFields)
320310
if err != nil {
321311
t.Fatalf("Failed to set in auth storage: %v", err)
322312
}
323313

324314
keyFlowWithStorage, err := initKeyFlowWithStorage()
315+
if err != nil {
316+
if !tt.isValid {
317+
return
318+
}
319+
t.Fatalf("Expected no error but error was returned: %v", err)
320+
}
325321

322+
getAccessToken, err := keyFlowWithStorage.keyFlow.GetAccessToken()
326323
if !tt.isValid {
327324
if err == nil {
328325
t.Fatalf("Expected error but no error was returned")
@@ -331,15 +328,8 @@ func TestInitKeyFlow(t *testing.T) {
331328
if err != nil {
332329
t.Fatalf("Expected no error but error was returned: %v", err)
333330
}
334-
expectedToken := &clients.TokenResponseBody{
335-
AccessToken: accessToken,
336-
ExpiresIn: int(timestamp.Unix()),
337-
RefreshToken: tt.refreshToken,
338-
Scope: "",
339-
TokenType: "Bearer",
340-
}
341-
if !cmp.Equal(*expectedToken, keyFlowWithStorage.keyFlow.GetToken()) {
342-
t.Errorf("The returned result is wrong. Expected %+v, got %+v", expectedToken, keyFlowWithStorage.keyFlow.GetToken())
331+
if !cmp.Equal(accessToken, getAccessToken) {
332+
t.Errorf("The returned result is wrong. Expected %+v, got %+v", accessToken, getAccessToken)
343333
}
344334
}
345335
})

internal/pkg/auth/service_account.go

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
type keyFlowInterface interface {
1515
GetAccessToken() (string, error)
1616
GetConfig() clients.KeyFlowConfig
17-
GetToken() clients.TokenResponseBody
1817
RoundTrip(*http.Request) (*http.Response, error)
1918
}
2019

@@ -32,7 +31,7 @@ var _ http.RoundTripper = &keyFlowWithStorage{}
3231

3332
// AuthenticateServiceAccount checks the type of the provided roundtripper,
3433
// authenticates the CLI accordingly and store the credentials.
35-
// For the key flow, it fetches an access and refresh token from the Service Account API.
34+
// For the key flow, it fetches an access token from the Service Account API.
3635
// For the token flow, it just stores the provided token and doesn't check if it is valid.
3736
// It returns the email associated with the service account
3837
// If disableWriting is set to true the credentials are not stored on disk (keyring, file).
@@ -56,7 +55,6 @@ func AuthenticateServiceAccount(p *print.Printer, rt http.RoundTripper, disableW
5655
}
5756

5857
authFields[ACCESS_TOKEN] = accessToken
59-
authFields[REFRESH_TOKEN] = flow.GetToken().RefreshToken
6058
authFields[SERVICE_ACCOUNT_KEY] = string(saKeyBytes)
6159
authFields[PRIVATE_KEY] = flow.GetConfig().PrivateKey
6260
case tokenFlowInterface:
@@ -100,8 +98,6 @@ func AuthenticateServiceAccount(p *print.Printer, rt http.RoundTripper, disableW
10098
// initKeyFlowWithStorage initializes the keyFlow from the SDK and creates a keyFlowWithStorage struct that uses that keyFlow
10199
func initKeyFlowWithStorage() (*keyFlowWithStorage, error) {
102100
authFields := map[authFieldKey]string{
103-
ACCESS_TOKEN: "",
104-
REFRESH_TOKEN: "",
105101
SERVICE_ACCOUNT_KEY: "",
106102
PRIVATE_KEY: "",
107103
TOKEN_CUSTOM_ENDPOINT: "",
@@ -110,12 +106,6 @@ func initKeyFlowWithStorage() (*keyFlowWithStorage, error) {
110106
if err != nil {
111107
return nil, fmt.Errorf("get from auth storage: %w", err)
112108
}
113-
if authFields[ACCESS_TOKEN] == "" {
114-
return nil, fmt.Errorf("access token not set")
115-
}
116-
if authFields[REFRESH_TOKEN] == "" {
117-
return nil, fmt.Errorf("refresh token not set")
118-
}
119109

120110
var serviceAccountKey = &clients.ServiceAccountKeyResponse{}
121111
err = json.Unmarshal([]byte(authFields[SERVICE_ACCOUNT_KEY]), serviceAccountKey)
@@ -134,10 +124,6 @@ func initKeyFlowWithStorage() (*keyFlowWithStorage, error) {
134124
if err != nil {
135125
return nil, fmt.Errorf("initialize key flow: %w", err)
136126
}
137-
err = keyFlow.SetToken(authFields[ACCESS_TOKEN], authFields[REFRESH_TOKEN])
138-
if err != nil {
139-
return nil, fmt.Errorf("set access and refresh token: %w", err)
140-
}
141127

142128
// create keyFlowWithStorage roundtripper that stores the credentials after executing a request
143129
keyFlowWithStorage := &keyFlowWithStorage{
@@ -146,21 +132,26 @@ func initKeyFlowWithStorage() (*keyFlowWithStorage, error) {
146132
return keyFlowWithStorage, nil
147133
}
148134

149-
// The keyFlowWithStorage Roundtrip executes the keyFlow roundtrip and then stores the access and refresh tokens
135+
// The keyFlowWithStorage Roundtrip executes the keyFlow roundtrip and then stores the access token
150136
func (kf *keyFlowWithStorage) RoundTrip(req *http.Request) (*http.Response, error) {
151137
resp, err := kf.keyFlow.RoundTrip(req)
152138

153-
token := kf.keyFlow.GetToken()
154-
accessToken := token.AccessToken
155-
refreshToken := token.RefreshToken
139+
accessToken, getTokenErr := kf.keyFlow.GetAccessToken()
140+
if getTokenErr != nil {
141+
return nil, fmt.Errorf("get access token: %w", getTokenErr)
142+
}
143+
156144
tokenValues := map[authFieldKey]string{
157-
ACCESS_TOKEN: accessToken,
158-
REFRESH_TOKEN: refreshToken,
145+
ACCESS_TOKEN: accessToken,
159146
}
160147

161148
storageErr := SetAuthFieldMap(tokenValues)
162149
if storageErr != nil {
163-
return nil, fmt.Errorf("set access and refresh token in the storage: %w", err)
150+
// If the request was successful, but storing the token failed we still return the response and a nil error
151+
if err == nil {
152+
return resp, nil
153+
}
154+
return nil, fmt.Errorf("set access token in the storage: %w", err)
164155
}
165156

166157
return resp, err

0 commit comments

Comments
 (0)