-
-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathtask_agent.go
More file actions
111 lines (99 loc) · 3.02 KB
/
task_agent.go
File metadata and controls
111 lines (99 loc) · 3.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package protocol
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"time"
"github.com/golang-jwt/jwt"
"github.com/google/uuid"
)
const (
// JWT token expiration time
jwtExpiration = 5 * time.Minute
// Error message prefix for authorization failures
authFailurePrefix = "Failed to Authorize: "
)
type TaskAgentPublicKey struct {
Exponent string
Modulus string
}
type TaskAgentAuthorization struct {
AuthorizationURL string `json:",omitempty"`
ClientID string `json:",omitempty"`
PublicKey TaskAgentPublicKey
}
type AgentLabel struct {
ID int
Name string
Type string
}
type TaskAgent struct {
Authorization TaskAgentAuthorization
Labels []AgentLabel
MaxParallelism int
ID int64
Name string
Version string
OSDescription string
Enabled *bool `json:",omitempty"`
ProvisioningState string
AccessPoint string `json:",omitempty"`
CreatedOn string
Ephemeral bool `json:",omitempty"`
DisableUpdate bool `json:",omitempty"`
// Just a convenient way to store the URL, not part of the spec
ServerV2URL string `json:",omitempty"`
}
type TaskAgents struct {
Count int64
Value []TaskAgent
}
func (taskAgent *TaskAgent) Authorize(c *http.Client, key interface{}) (*VssOAuthTokenResponse, error) {
tokenresp := &VssOAuthTokenResponse{}
now := time.Now().UTC().Add(-30 * time.Second)
token2 := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.StandardClaims{
Subject: taskAgent.Authorization.ClientID,
Issuer: taskAgent.Authorization.ClientID,
Id: uuid.New().String(),
Audience: taskAgent.Authorization.AuthorizationURL,
NotBefore: now.Unix(),
IssuedAt: now.Unix(),
ExpiresAt: now.Add(jwtExpiration).Unix(),
})
stkn, err := token2.SignedString(key)
if err != nil {
return nil, err
}
data := url.Values{}
data.Set("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
data.Set("client_assertion", stkn)
data.Set("grant_type", "client_credentials")
//nolint:noctx // Legacy function without context - would break API compatibility
poolsreq, err := http.NewRequest(http.MethodPost, taskAgent.Authorization.AuthorizationURL, bytes.NewBufferString(data.Encode()))
if err != nil {
return nil, errors.New(authFailurePrefix + err.Error())
}
poolsreq.Header["Content-Type"] = []string{"application/x-www-form-urlencoded; charset=utf-8"}
poolsreq.Header["Accept"] = []string{"application/json"}
poolsresp, err := c.Do(poolsreq)
if err != nil {
return nil, errors.New(authFailurePrefix + err.Error())
}
defer func() {
_ = poolsresp.Body.Close() // Ignore close error
}()
if poolsresp.StatusCode != http.StatusOK {
responseBytes, _ := io.ReadAll(poolsresp.Body)
return nil, errors.New("Failed to Authorize, service responded with code " + fmt.Sprint(poolsresp.StatusCode) +
": " + string(responseBytes))
}
dec := json.NewDecoder(poolsresp.Body)
if err := dec.Decode(tokenresp); err != nil {
return nil, err
}
return tokenresp, nil
}