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