identity.go raw
1 package internal
2
3 import (
4 "bytes"
5 "context"
6 "encoding/json"
7 "fmt"
8 "net/http"
9 "strings"
10 "time"
11
12 "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
13 )
14
15 // authEndpoint represents the Identity API endpoint to call.
16 const authEndpoint = "https://kasapi.kasserver.com/soap/KasAuth.php"
17
18 type token string
19
20 const tokenKey token = "token"
21
22 // Identifier generates credential tokens.
23 type Identifier struct {
24 login string
25 password string
26
27 authEndpoint string
28 HTTPClient *http.Client
29 }
30
31 // NewIdentifier creates a new Identifier.
32 func NewIdentifier(login, password string) *Identifier {
33 return &Identifier{
34 login: login,
35 password: password,
36 authEndpoint: authEndpoint,
37 HTTPClient: &http.Client{Timeout: 10 * time.Second},
38 }
39 }
40
41 // Authentication Creates a credential token.
42 // - sessionLifetime: Validity of the token in seconds.
43 // - sessionUpdateLifetime: with `true` the session is extended with every request.
44 func (c *Identifier) Authentication(ctx context.Context, sessionLifetime int, sessionUpdateLifetime bool) (string, error) {
45 sul := "N"
46 if sessionUpdateLifetime {
47 sul = "Y"
48 }
49
50 ar := AuthRequest{
51 Login: c.login,
52 AuthData: c.password,
53 AuthType: "plain",
54 SessionLifetime: sessionLifetime,
55 SessionUpdateLifetime: sul,
56 }
57
58 body, err := json.Marshal(ar)
59 if err != nil {
60 return "", fmt.Errorf("failed to create request JSON body: %w", err)
61 }
62
63 payload := []byte(strings.TrimSpace(fmt.Sprintf(kasAuthEnvelope, body)))
64
65 req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.authEndpoint, bytes.NewReader(payload))
66 if err != nil {
67 return "", fmt.Errorf("unable to create request: %w", err)
68 }
69
70 resp, err := c.HTTPClient.Do(req)
71 if err != nil {
72 return "", errutils.NewHTTPDoError(req, err)
73 }
74
75 defer func() { _ = resp.Body.Close() }()
76
77 if resp.StatusCode != http.StatusOK {
78 return "", errutils.NewUnexpectedResponseStatusCodeError(req, resp)
79 }
80
81 envlp, err := decodeXML[KasAuthEnvelope](resp.Body)
82 if err != nil {
83 return "", err
84 }
85
86 if envlp.Body.Fault != nil {
87 return "", envlp.Body.Fault
88 }
89
90 return envlp.Body.KasAuthResponse.Return.Text, nil
91 }
92
93 func WithContext(ctx context.Context, credential string) context.Context {
94 return context.WithValue(ctx, tokenKey, credential)
95 }
96
97 func getToken(ctx context.Context) string {
98 credential, ok := ctx.Value(tokenKey).(string)
99 if !ok {
100 return ""
101 }
102
103 return credential
104 }
105