Skip to content

Commit 6fca850

Browse files
committed
fix a few bugs in the json serialization and the token resolution
1 parent 185f44d commit 6fca850

File tree

2 files changed

+46
-16
lines changed

2 files changed

+46
-16
lines changed

azure-devops-client/main.go

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ import (
1212

1313
resty "github.com/go-resty/resty/v2"
1414
"github.com/prometheus/client_golang/prometheus"
15+
"go.uber.org/zap"
1516
)
1617

1718
type AzureDevopsClient struct {
19+
logger *zap.SugaredLogger
20+
1821
// RequestCount has to be the first words
1922
// in order to be 64-aligned on 32-bit architectures.
2023
RequestCount uint64
@@ -60,14 +63,21 @@ type AzureDevopsClient struct {
6063
}
6164

6265
type EntraIdToken struct {
63-
token_type *string
64-
expires_in *int64
65-
ext_expires_in *int64
66-
access_token *string
66+
TokenType *string `json:"token_type"`
67+
ExpiresIn *int64 `json:"expires_in"`
68+
ExtExpiresIn *int64 `json:"ext_expires_in"`
69+
AccessToken *string `json:"access_token"`
70+
}
71+
72+
type EntraIdErrorResponse struct {
73+
Error *string `json:"error"`
74+
ErrorDescription *string `json:"error_description"`
6775
}
6876

69-
func NewAzureDevopsClient() *AzureDevopsClient {
70-
c := AzureDevopsClient{}
77+
func NewAzureDevopsClient(logger *zap.SugaredLogger) *AzureDevopsClient {
78+
c := AzureDevopsClient{
79+
logger: logger,
80+
}
7181
c.Init()
7282

7383
return &c
@@ -148,18 +158,20 @@ func (c *AzureDevopsClient) SetClientSecret(clientSecret string) {
148158
}
149159

150160
func (c *AzureDevopsClient) SupportsPatAuthentication() bool {
151-
return c.accessToken != nil
161+
return c.accessToken != nil && len(*c.accessToken) > 0
152162
}
153163

154164
func (c *AzureDevopsClient) SupportsServicePrincipalAuthentication() bool {
155-
return c.tenantId != nil && c.clientId != nil && c.clientSecret != nil
165+
return c.tenantId != nil && len(*c.tenantId) > 0 &&
166+
c.clientId != nil && len(*c.clientId) > 0 &&
167+
c.clientSecret != nil && len(*c.clientSecret) > 0
156168
}
157169

158170
func (c *AzureDevopsClient) HasExpiredEntraIdAccessToken() bool {
159171
var currentUnix = time.Now().Unix()
160172

161173
// subtract 60 seconds of offset (should be enough time to use fire all requests)
162-
return (c.entraIdToken == nil || currentUnix >= c.entraIdTokenLastRefreshed+*c.entraIdToken.expires_in-60)
174+
return (c.entraIdToken == nil || currentUnix >= c.entraIdTokenLastRefreshed+*c.entraIdToken.ExpiresIn-60)
163175
}
164176

165177
func (c *AzureDevopsClient) RefreshEntraIdAccessToken() (string, error) {
@@ -171,7 +183,7 @@ func (c *AzureDevopsClient) RefreshEntraIdAccessToken() (string, error) {
171183
"client_id": *c.clientId,
172184
"client_secret": *c.clientSecret,
173185
"grant_type": "client_credentials",
174-
"scope": "499b84ac-1321-427f-aa17-267ca6975798", // the scope is always the same for Azure DevOps
186+
"scope": "499b84ac-1321-427f-aa17-267ca6975798/.default", // the scope is always the same for Azure DevOps
175187
})
176188

177189
restClient.SetHeader("Content-Type", "application/x-www-form-urlencoded")
@@ -184,22 +196,40 @@ func (c *AzureDevopsClient) RefreshEntraIdAccessToken() (string, error) {
184196
return "", err
185197
}
186198

187-
err = json.Unmarshal(response.Body(), &c.entraIdToken)
199+
var responseBody = response.Body()
200+
201+
var errorResponse *EntraIdErrorResponse
202+
203+
err = json.Unmarshal(responseBody, &errorResponse)
188204

189205
if err != nil {
190206
return "", err
191207
}
192208

209+
if errorResponse.Error != nil && len(*errorResponse.Error) > 0 {
210+
return "", fmt.Errorf("could not request a token, error: %v %v", *errorResponse.Error, *errorResponse.ErrorDescription)
211+
}
212+
213+
err = json.Unmarshal(responseBody, &c.entraIdToken)
214+
215+
if err != nil {
216+
return "", err
217+
}
218+
219+
if c.entraIdToken == nil || c.entraIdToken.AccessToken == nil {
220+
return "", errors.New("could not request an access token")
221+
}
222+
193223
c.entraIdTokenLastRefreshed = time.Now().Unix()
194224

195-
return *c.entraIdToken.access_token, nil
225+
return *c.entraIdToken.AccessToken, nil
196226
}
197227

198228
func (c *AzureDevopsClient) rest() *resty.Client {
199229
var client, err = c.restWithAuthentication("dev.azure.com")
200230

201231
if err != nil {
202-
// TODO handle error!
232+
c.logger.Fatalf("could not create a rest client: %v", err)
203233
}
204234

205235
return client
@@ -209,7 +239,7 @@ func (c *AzureDevopsClient) restVsrm() *resty.Client {
209239
var client, err = c.restWithAuthentication("vsrm.dev.azure.com")
210240

211241
if err != nil {
212-
// TODO handle error!
242+
c.logger.Fatalf("could not create a rest client: %v", err)
213243
}
214244

215245
return client

main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func initArgparser() {
8282
}
8383
}
8484

85-
if len(opts.AzureDevops.AccessToken) == 0 || (len(opts.AzureDevops.TenantId) == 0 && len(opts.AzureDevops.ClientId) == 0 && len(opts.AzureDevops.ClientSecret) == 0) {
85+
if len(opts.AzureDevops.AccessToken) == 0 && (len(opts.AzureDevops.TenantId) == 0 || len(opts.AzureDevops.ClientId) == 0 || len(opts.AzureDevops.ClientSecret) == 0) {
8686
logger.Fatalf("neither an Azure DevOps PAT token nor client credentials (tenant ID, client ID, client secret) for service principal authentication have been provided")
8787
}
8888

@@ -148,7 +148,7 @@ func initArgparser() {
148148

149149
// Init and build Azure authorzier
150150
func initAzureDevOpsConnection() {
151-
AzureDevopsClient = AzureDevops.NewAzureDevopsClient()
151+
AzureDevopsClient = AzureDevops.NewAzureDevopsClient(logger)
152152
if opts.AzureDevops.Url != nil {
153153
AzureDevopsClient.HostUrl = opts.AzureDevops.Url
154154
}

0 commit comments

Comments
 (0)