@@ -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
1718type 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
6265type 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
150160func (c * AzureDevopsClient ) SupportsPatAuthentication () bool {
151- return c .accessToken != nil
161+ return c .accessToken != nil && len ( * c . accessToken ) > 0
152162}
153163
154164func (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
158170func (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
165177func (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
198228func (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
0 commit comments