@@ -9,9 +9,13 @@ import (
9
9
"encoding/json"
10
10
"fmt"
11
11
"io"
12
+ "io/fs"
12
13
"net/http"
13
14
"net/url"
15
+ "os"
16
+ "path"
14
17
"strings"
18
+ "time"
15
19
16
20
"github.com/vmware/go-vcloud-director/v2/types/v56"
17
21
"github.com/vmware/go-vcloud-director/v2/util"
@@ -31,6 +35,47 @@ func (vcdClient *VCDClient) SetApiToken(org, apiToken string) (*types.ApiTokenRe
31
35
return tokenRefresh , nil
32
36
}
33
37
38
+ // SetServiceAccountApiToken reads the current Service Account API token,
39
+ // sets the client's bearer token and fetches a new API token for next
40
+ // authentication request using SetApiToken and overwrites the old file.
41
+ func (vcdClient * VCDClient ) SetServiceAccountApiToken (org , apiTokenFile string ) error {
42
+ if vcdClient .Client .APIVCDMaxVersionIs ("< 37.0" ) {
43
+ version , err := vcdClient .Client .GetVcdFullVersion ()
44
+ if err == nil {
45
+ return fmt .Errorf ("minimum version for Service Account authentication is 10.4 - Version detected: %s" , version .Version )
46
+ }
47
+ // If we can't get the VCD version, we return API version info
48
+ return fmt .Errorf ("minimum API version for Service Account authentication is 37.0 - Version detected: %s" , vcdClient .Client .APIVersion )
49
+ }
50
+
51
+ saApiToken := & types.ApiTokenRefresh {}
52
+ // Read file contents and unmarshal them to saApiToken
53
+ err := readFileAndUnmarshalJSON (apiTokenFile , saApiToken )
54
+ if err != nil {
55
+ return err
56
+ }
57
+
58
+ // Get bearer token and update the refresh token for the next authentication request
59
+ saApiToken , err = vcdClient .SetApiToken (org , saApiToken .RefreshToken )
60
+ if err != nil {
61
+ return err
62
+ }
63
+
64
+ // leave only the refresh token to not leave any sensitive information
65
+ saApiToken = & types.ApiTokenRefresh {
66
+ RefreshToken : saApiToken .RefreshToken ,
67
+ TokenType : "Service Account" ,
68
+ UpdatedBy : vcdClient .Client .UserAgent ,
69
+ UpdatedOn : time .Now ().Format (time .RFC3339 ),
70
+ }
71
+ err = marshalJSONAndWriteToFile (apiTokenFile , saApiToken , 0600 )
72
+ if err != nil {
73
+ return err
74
+ }
75
+
76
+ return nil
77
+ }
78
+
34
79
// GetBearerTokenFromApiToken uses an API token to retrieve a bearer token
35
80
// using the refresh token operation.
36
81
func (vcdClient * VCDClient ) GetBearerTokenFromApiToken (org , token string ) (* types.ApiTokenRefresh , error ) {
@@ -112,3 +157,34 @@ func (vcdClient *VCDClient) GetBearerTokenFromApiToken(org, token string) (*type
112
157
}
113
158
return & tokenDef , nil
114
159
}
160
+
161
+ // readFileAndUnmarshalJSON reads a file and unmarshals it to the given variable
162
+ func readFileAndUnmarshalJSON (filename string , object any ) error {
163
+ data , err := os .ReadFile (path .Clean (filename ))
164
+ if err != nil {
165
+ return fmt .Errorf ("failed to read from file: %s" , err )
166
+ }
167
+
168
+ err = json .Unmarshal (data , object )
169
+ if err != nil {
170
+ return fmt .Errorf ("failed to unmarshal file contents to the object: %s" , err )
171
+ }
172
+
173
+ return nil
174
+ }
175
+
176
+ // marshalJSONAndWriteToFile marshalls the given object into JSON and writes
177
+ // to a file with the given permissions in octal format (e.g 0600)
178
+ func marshalJSONAndWriteToFile (filename string , object any , permissions int ) error {
179
+ data , err := json .MarshalIndent (object , " " , " " )
180
+ if err != nil {
181
+ return fmt .Errorf ("error marshalling object to JSON: %s" , err )
182
+ }
183
+
184
+ err = os .WriteFile (filename , data , fs .FileMode (permissions ))
185
+ if err != nil {
186
+ return fmt .Errorf ("error writing to the file: %s" , err )
187
+ }
188
+
189
+ return nil
190
+ }
0 commit comments