identity.go raw
1 // internal/identity.go
2
3 package internal
4
5 import (
6 "context"
7 "errors"
8 "fmt"
9 "io"
10 "net/http"
11 "net/url"
12 "time"
13
14 "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
15 )
16
17 const identityBaseURL = "https://identity.%s.conoha.io"
18
19 type Identifier struct {
20 baseURL *url.URL
21 HTTPClient *http.Client
22 }
23
24 // NewIdentifier creates a new Identifier.
25 func NewIdentifier(region string) (*Identifier, error) {
26 baseURL, err := url.Parse(fmt.Sprintf(identityBaseURL, region))
27 if err != nil {
28 return nil, err
29 }
30
31 return &Identifier{
32 baseURL: baseURL,
33 HTTPClient: &http.Client{Timeout: 5 * time.Second},
34 }, nil
35 }
36
37 // GetToken returns the x-subject-token from Identity API.
38 // https://doc.conoha.jp/reference/api-vps3/api-identity-vps3/identity-post_tokens-v3/?btn_id=reference-api-guideline-v3--sidebar_reference-identity-post_tokens-v3
39 func (c *Identifier) GetToken(ctx context.Context, auth Auth) (string, error) {
40 endpoint := c.baseURL.JoinPath("v3", "auth", "tokens")
41
42 req, err := newJSONRequest(ctx, http.MethodPost, endpoint, &IdentityRequest{Auth: auth})
43 if err != nil {
44 return "", err
45 }
46
47 return c.do(req)
48 }
49
50 // do sends the request and returns the token from x-subject-token header.
51 func (c *Identifier) do(req *http.Request) (string, error) {
52 resp, err := c.HTTPClient.Do(req)
53 if err != nil {
54 return "", errutils.NewHTTPDoError(req, err)
55 }
56
57 defer func() { _ = resp.Body.Close() }()
58
59 if resp.StatusCode != http.StatusCreated {
60 return "", errutils.NewUnexpectedResponseStatusCodeError(req, resp)
61 }
62
63 token := resp.Header.Get("x-subject-token")
64 if token == "" {
65 return "", errors.New("x-subject-token header is missing in response")
66 }
67
68 _, _ = io.Copy(io.Discard, resp.Body)
69
70 return token, nil
71 }
72