aboutsummaryrefslogtreecommitdiffstats
path: root/client/go/internal/cli/auth/zts
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2023-02-03 15:20:23 +0100
committerMartin Polden <mpolden@mpolden.no>2023-02-03 15:35:25 +0100
commite1e94812425a487069bf33f781bec987e9e49874 (patch)
tree4a892c3b5c0a7dee2cb76f9971e538cb4aba8a16 /client/go/internal/cli/auth/zts
parenta08ae588d6035b69f0961dff596fc871fd1c4e58 (diff)
Re-organize Go code
Diffstat (limited to 'client/go/internal/cli/auth/zts')
-rw-r--r--client/go/internal/cli/auth/zts/zts.go58
-rw-r--r--client/go/internal/cli/auth/zts/zts_test.go30
2 files changed, 88 insertions, 0 deletions
diff --git a/client/go/internal/cli/auth/zts/zts.go b/client/go/internal/cli/auth/zts/zts.go
new file mode 100644
index 00000000000..9fabe219209
--- /dev/null
+++ b/client/go/internal/cli/auth/zts/zts.go
@@ -0,0 +1,58 @@
+package zts
+
+import (
+ "crypto/tls"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+
+ "github.com/vespa-engine/vespa/client/go/internal/util"
+)
+
+const DefaultURL = "https://zts.athenz.ouroath.com:4443"
+
+// Client is a client for Athenz ZTS, an authentication token service.
+type Client struct {
+ client util.HTTPClient
+ tokenURL *url.URL
+}
+
+// NewClient creates a new client for an Athenz ZTS service located at serviceURL.
+func NewClient(serviceURL string, client util.HTTPClient) (*Client, error) {
+ tokenURL, err := url.Parse(serviceURL)
+ if err != nil {
+ return nil, err
+ }
+ tokenURL.Path = "/zts/v1/oauth2/token"
+ return &Client{tokenURL: tokenURL, client: client}, nil
+}
+
+// AccessToken returns an access token within the given domain, using certificate to authenticate with ZTS.
+func (c *Client) AccessToken(domain string, certificate tls.Certificate) (string, error) {
+ data := fmt.Sprintf("grant_type=client_credentials&scope=%s:domain", domain)
+ req, err := http.NewRequest("POST", c.tokenURL.String(), strings.NewReader(data))
+ if err != nil {
+ return "", err
+ }
+ c.client.UseCertificate([]tls.Certificate{certificate})
+ response, err := c.client.Do(req, 10*time.Second)
+ if err != nil {
+ return "", err
+ }
+ defer response.Body.Close()
+
+ if response.StatusCode != http.StatusOK {
+ return "", fmt.Errorf("got status %d from %s", response.StatusCode, c.tokenURL.String())
+ }
+ var ztsResponse struct {
+ AccessToken string `json:"access_token"`
+ }
+ dec := json.NewDecoder(response.Body)
+ if err := dec.Decode(&ztsResponse); err != nil {
+ return "", err
+ }
+ return ztsResponse.AccessToken, nil
+}
diff --git a/client/go/internal/cli/auth/zts/zts_test.go b/client/go/internal/cli/auth/zts/zts_test.go
new file mode 100644
index 00000000000..6c6ced9bb33
--- /dev/null
+++ b/client/go/internal/cli/auth/zts/zts_test.go
@@ -0,0 +1,30 @@
+package zts
+
+import (
+ "crypto/tls"
+ "testing"
+
+ "github.com/vespa-engine/vespa/client/go/internal/mock"
+)
+
+func TestAccessToken(t *testing.T) {
+ httpClient := mock.HTTPClient{}
+ client, err := NewClient("http://example.com", &httpClient)
+ if err != nil {
+ t.Fatal(err)
+ }
+ httpClient.NextResponseString(400, `{"message": "bad request"}`)
+ _, err = client.AccessToken("vespa.vespa", tls.Certificate{})
+ if err == nil {
+ t.Fatal("want error for non-ok response status")
+ }
+ httpClient.NextResponseString(200, `{"access_token": "foo bar"}`)
+ token, err := client.AccessToken("vespa.vespa", tls.Certificate{})
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := "foo bar"
+ if token != want {
+ t.Errorf("got %q, want %q", token, want)
+ }
+}