lego/providers/dns/otc/internal/identity.go
2023-05-05 09:49:38 +02:00

125 lines
2.7 KiB
Go

package internal
import (
"context"
"encoding/json"
"errors"
"io"
"net/http"
"net/url"
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
)
// DefaultIdentityEndpoint the default API identity endpoint.
const DefaultIdentityEndpoint = "https://iam.eu-de.otc.t-systems.com:443/v3/auth/tokens"
// Login Starts a new OTC API Session. Authenticates using userName, password
// and receives a token to be used in for subsequent requests.
func (c *Client) Login(ctx context.Context) error {
payload := LoginRequest{
Auth: Auth{
Identity: Identity{
Methods: []string{"password"},
Password: Password{
User: User{
Name: c.username,
Password: c.password,
Domain: Domain{
Name: c.domainName,
},
},
},
},
Scope: Scope{
Project: Project{
Name: c.projectName,
},
},
},
}
tokenResp, token, err := c.obtainUserToken(ctx, payload)
if err != nil {
return err
}
c.muToken.Lock()
defer c.muToken.Unlock()
c.token = token
if c.token == "" {
return errors.New("unable to get auth token")
}
baseURL, err := getBaseURL(tokenResp)
if err != nil {
return err
}
c.muBaseURL.Lock()
c.baseURL = baseURL
c.muBaseURL.Unlock()
return nil
}
// https://docs.otc.t-systems.com/identity-access-management/api-ref/apis/token_management/obtaining_a_user_token.html
func (c *Client) obtainUserToken(ctx context.Context, payload LoginRequest) (*TokenResponse, string, error) {
req, err := newJSONRequest(ctx, http.MethodPost, c.IdentityEndpoint, payload)
if err != nil {
return nil, "", err
}
client := &http.Client{Timeout: c.HTTPClient.Timeout}
resp, err := client.Do(req)
if err != nil {
return nil, "", err
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode/100 != 2 {
return nil, "", errutils.NewUnexpectedResponseStatusCodeError(req, resp)
}
token := resp.Header.Get("X-Subject-Token")
if token == "" {
return nil, "", errors.New("unable to get auth token")
}
raw, err := io.ReadAll(resp.Body)
if err != nil {
return nil, "", errutils.NewReadResponseError(req, resp.StatusCode, err)
}
var newToken TokenResponse
err = json.Unmarshal(raw, &newToken)
if err != nil {
return nil, "", errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
}
return &newToken, token, nil
}
func getBaseURL(tokenResp *TokenResponse) (*url.URL, error) {
var endpoints []Endpoint
for _, v := range tokenResp.Token.Catalog {
if v.Type == "dns" {
endpoints = append(endpoints, v.Endpoints...)
}
}
if len(endpoints) == 0 {
return nil, errors.New("unable to get dns endpoint")
}
baseURL, err := url.JoinPath(endpoints[0].URL, "v2")
if err != nil {
return nil, err
}
return url.Parse(baseURL)
}