From 2b20b13fad0d7e81078189bc17dab243e671be1d Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Fri, 3 Dec 2021 16:19:00 +0100 Subject: [PATCH] mythicbeasts: fix token expiration (#1539) --- providers/dns/mythicbeasts/client.go | 29 +++++++++++++--------- providers/dns/mythicbeasts/mythicbeasts.go | 6 ++++- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/providers/dns/mythicbeasts/client.go b/providers/dns/mythicbeasts/client.go index c7940637..69d05535 100644 --- a/providers/dns/mythicbeasts/client.go +++ b/providers/dns/mythicbeasts/client.go @@ -9,6 +9,7 @@ import ( "net/http" "path" "strings" + "time" ) const ( @@ -25,6 +26,8 @@ type authResponse struct { // The token type (must be 'bearer') TokenType string `json:"token_type"` + + Deadline time.Time `json:"-"` } type authResponseError struct { @@ -61,14 +64,15 @@ type deleteTXTResponse struct { // Logs into mythic beasts and acquires a bearer token for use in future API calls. // https://www.mythic-beasts.com/support/api/auth#sec-obtaining-a-token func (d *DNSProvider) login() error { - if d.token != "" { + d.muToken.Lock() + defer d.muToken.Unlock() + + if d.token != nil && time.Now().Before(d.token.Deadline) { // Already authenticated, stop now return nil } - reqBody := strings.NewReader("grant_type=client_credentials") - - req, err := http.NewRequest(http.MethodPost, d.config.AuthAPIEndpoint.String(), reqBody) + req, err := http.NewRequest(http.MethodPost, d.config.AuthAPIEndpoint.String(), strings.NewReader("grant_type=client_credentials")) if err != nil { return err } @@ -88,7 +92,7 @@ func (d *DNSProvider) login() error { return fmt.Errorf("login: %w", err) } - if resp.StatusCode != 200 { + if resp.StatusCode != http.StatusOK { if resp.StatusCode < 400 || resp.StatusCode > 499 { return fmt.Errorf("login: unknown error in auth API: %d", resp.StatusCode) } @@ -113,7 +117,8 @@ func (d *DNSProvider) login() error { return fmt.Errorf("login: received unexpected token type: %s", authResp.TokenType) } - d.token = authResp.Token + authResp.Deadline = time.Now().Add(time.Duration(authResp.Lifetime) * time.Second) + d.token = &authResp // Success return nil @@ -121,7 +126,7 @@ func (d *DNSProvider) login() error { // https://www.mythic-beasts.com/support/api/dnsv2#ep-get-zoneszonerecords func (d *DNSProvider) createTXTRecord(zone, leaf, value string) error { - if d.token == "" { + if d.token == nil { return fmt.Errorf("createTXTRecord: not logged in") } @@ -149,7 +154,7 @@ func (d *DNSProvider) createTXTRecord(zone, leaf, value string) error { return fmt.Errorf("createTXTRecord: %w", err) } - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", d.token)) + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", d.token.Token)) req.Header.Set("Content-Type", "application/json") resp, err := d.config.HTTPClient.Do(req) @@ -184,13 +189,13 @@ func (d *DNSProvider) createTXTRecord(zone, leaf, value string) error { // https://www.mythic-beasts.com/support/api/dnsv2#ep-delete-zoneszonerecords func (d *DNSProvider) removeTXTRecord(zone, leaf, value string) error { - if d.token == "" { + if d.token == nil { return fmt.Errorf("removeTXTRecord: not logged in") } endpoint, err := d.config.APIEndpoint.Parse(path.Join(d.config.APIEndpoint.Path, "zones", zone, "records", leaf, "TXT")) if err != nil { - return fmt.Errorf("createTXTRecord: failed to parse URL: %w", err) + return fmt.Errorf("removeTXTRecord: failed to parse URL: %w", err) } query := endpoint.Query() @@ -202,7 +207,7 @@ func (d *DNSProvider) removeTXTRecord(zone, leaf, value string) error { return fmt.Errorf("removeTXTRecord: %w", err) } - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", d.token)) + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", d.token.Token)) resp, err := d.config.HTTPClient.Do(req) if err != nil { @@ -227,7 +232,7 @@ func (d *DNSProvider) removeTXTRecord(zone, leaf, value string) error { } if deleteResp.Removed != 1 { - return errors.New("deleteTXTRecord: did not add TXT record for some reason") + return errors.New("removeTXTRecord: did not add TXT record for some reason") } // Success diff --git a/providers/dns/mythicbeasts/mythicbeasts.go b/providers/dns/mythicbeasts/mythicbeasts.go index be35e736..40760f57 100644 --- a/providers/dns/mythicbeasts/mythicbeasts.go +++ b/providers/dns/mythicbeasts/mythicbeasts.go @@ -6,6 +6,7 @@ import ( "fmt" "net/http" "net/url" + "sync" "time" "github.com/go-acme/lego/v4/challenge/dns01" @@ -66,7 +67,10 @@ func NewDefaultConfig() (*Config, error) { // DNSProvider implements the challenge.Provider interface. type DNSProvider struct { config *Config - token string + + // token string + token *authResponse + muToken sync.Mutex } // NewDNSProvider returns a DNSProvider instance configured for mythicbeasts DNSv2 API.