Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to authorize using a Service Account #562

Merged
merged 17 commits into from
Apr 19, 2023
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func main() {

## Authentication

You can authenticate to the vCD in four ways:
You can authenticate to the vCD in five ways:

* With a System Administration user and password (`administrator@system`)
* With an Organization user and password (`tenant-admin@org-name`)
Expand All @@ -133,6 +133,11 @@ For the above two methods, you use:
The file `scripts/get_token.sh` provides a handy method of extracting the token
(`x-vcloud-authorization` value) for future use.

* With a service account token
```go
err := vcdClient.SetServiceAccountApiToken(Org, "tokenfile.json")
```

* SAML user and password (works with ADFS as IdP using WS-TRUST endpoint
"/adfs/services/trust/13/usernamemixed"). One must pass `govcd.WithSamlAdfs(true,customAdfsRptId)`
and username must be formatted so that ADFS understands it ('user@contoso.com' or
Expand Down
44 changes: 44 additions & 0 deletions govcd/api_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"io"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"

"github.com/vmware/go-vcloud-director/v2/types/v56"
Expand All @@ -31,6 +33,48 @@ func (vcdClient *VCDClient) SetApiToken(org, apiToken string) (*types.ApiTokenRe
return tokenRefresh, nil
}

func (vcdClient *VCDClient) SetServiceAccountApiToken(org, apiTokenFile string) error {
if vcdClient.Client.APIVCDMaxVersionIs("< 37.0") {
version, err := vcdClient.Client.GetVcdFullVersion()
if err == nil {
return fmt.Errorf("minimum version for Service Account authentication is 10.4 - Version detected: %s", version.Version)
}
// If we can't get the VCD version, we return API version info
return fmt.Errorf("minimum API version for Service Account authentication is 37.0 - Version detected: %s", vcdClient.Client.APIVersion)
}

apiTokenFile = filepath.Clean(apiTokenFile)
data, err := os.ReadFile(apiTokenFile)
if err != nil {
return err
}

saApiToken := &types.ApiTokenRefresh{}
err = json.Unmarshal(data, &saApiToken)
if err != nil {
return err
}

saApiToken, err = vcdClient.SetApiToken(org, saApiToken.RefreshToken)
if err != nil {
return err
}

data, err = json.Marshal(&types.ApiTokenRefresh{
RefreshToken: saApiToken.RefreshToken,
})
if err != nil {
return err
}

err = os.WriteFile(apiTokenFile, data, 0600)
if err != nil {
return err
}

return nil
}

// GetBearerTokenFromApiToken uses an API token to retrieve a bearer token
// using the refresh token operation.
func (vcdClient *VCDClient) GetBearerTokenFromApiToken(org, token string) (*types.ApiTokenRefresh, error) {
Expand Down
8 changes: 4 additions & 4 deletions types/v56/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3257,10 +3257,10 @@ type UpdateVdcStorageProfiles struct {

// ApiTokenRefresh contains the access token resulting from a refresh_token operation
type ApiTokenRefresh struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
RefreshToken interface{} `json:"refresh_token"`
AccessToken string `json:"access_token,omitempty"`
TokenType string `json:"token_type,omitempty"`
ExpiresIn int `json:"expires_in,omitempty"`
RefreshToken string `json:"refresh_token,omitempty"`
}

/**/
Expand Down