DNS challenge Cloudflare auth zone
This commit is contained in:
parent
0335f6fba9
commit
7c2409b5a7
18 changed files with 312 additions and 248 deletions
3
Gopkg.lock
generated
3
Gopkg.lock
generated
|
@ -1366,6 +1366,7 @@
|
|||
"providers/dns/dnsimple",
|
||||
"providers/dns/dnsmadeeasy",
|
||||
"providers/dns/dnspod",
|
||||
"providers/dns/dreamhost",
|
||||
"providers/dns/duckdns",
|
||||
"providers/dns/dyn",
|
||||
"providers/dns/exec",
|
||||
|
@ -1397,7 +1398,7 @@
|
|||
"providers/dns/vegadns",
|
||||
"providers/dns/vultr"
|
||||
]
|
||||
revision = "01c63ec08d1d85e3ad44c16dff95dadee26a81bc"
|
||||
revision = "160d6fe60303699067faad57dc0b1e147ac499ef"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
|
|
@ -263,6 +263,7 @@ Here is a list of supported `provider`s, that can automate the DNS verification,
|
|||
| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | Not tested yet |
|
||||
| [DNS Made Easy](https://dnsmadeeasy.com) | `dnsmadeeasy` | `DNSMADEEASY_API_KEY`, `DNSMADEEASY_API_SECRET`, `DNSMADEEASY_SANDBOX` | Not tested yet |
|
||||
| [DNSPod](http://www.dnspod.net/) | `dnspod` | `DNSPOD_API_KEY` | Not tested yet |
|
||||
| [DreamHost](https://www.dreamhost.com/) | `dreamhost` | `DREAMHOST_API_KEY` | YES |
|
||||
| [Duck DNS](https://www.duckdns.org/) | `duckdns` | `DUCKDNS_TOKEN` | Not tested yet |
|
||||
| [Dyn](https://dyn.com) | `dyn` | `DYN_CUSTOMER_NAME`, `DYN_USER_NAME`, `DYN_PASSWORD` | Not tested yet |
|
||||
| External Program | `exec` | `EXEC_PATH` | Not tested yet |
|
||||
|
|
2
vendor/github.com/xenolf/lego/acme/challenges.go
generated
vendored
2
vendor/github.com/xenolf/lego/acme/challenges.go
generated
vendored
|
@ -7,9 +7,11 @@ const (
|
|||
// HTTP01 is the "http-01" ACME challenge https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md#http
|
||||
// Note: HTTP01ChallengePath returns the URL path to fulfill this challenge
|
||||
HTTP01 = Challenge("http-01")
|
||||
|
||||
// DNS01 is the "dns-01" ACME challenge https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md#dns
|
||||
// Note: DNS01Record returns a DNS record which will fulfill this challenge
|
||||
DNS01 = Challenge("dns-01")
|
||||
|
||||
// TLSALPN01 is the "tls-alpn-01" ACME challenge https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01
|
||||
TLSALPN01 = Challenge("tls-alpn-01")
|
||||
)
|
||||
|
|
2
vendor/github.com/xenolf/lego/acme/client.go
generated
vendored
2
vendor/github.com/xenolf/lego/acme/client.go
generated
vendored
|
@ -412,7 +412,7 @@ DNSNames:
|
|||
// the whole certificate will fail.
|
||||
func (c *Client) ObtainCertificate(domains []string, bundle bool, privKey crypto.PrivateKey, mustStaple bool) (*CertificateResource, error) {
|
||||
if len(domains) == 0 {
|
||||
return nil, errors.New("No domains to obtain a certificate for")
|
||||
return nil, errors.New("no domains to obtain a certificate for")
|
||||
}
|
||||
|
||||
if bundle {
|
||||
|
|
4
vendor/github.com/xenolf/lego/providers/dns/cloudflare/cloudflare.go
generated
vendored
4
vendor/github.com/xenolf/lego/providers/dns/cloudflare/cloudflare.go
generated
vendored
|
@ -114,7 +114,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
return fmt.Errorf("cloudflare: %v", err)
|
||||
}
|
||||
|
||||
zoneID, err := d.client.ZoneIDByName(authZone)
|
||||
zoneID, err := d.client.ZoneIDByName(acme.UnFqdn(authZone))
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: failed to find zone %s: %v", authZone, err)
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
return fmt.Errorf("cloudflare: %v", err)
|
||||
}
|
||||
|
||||
zoneID, err := d.client.ZoneIDByName(authZone)
|
||||
zoneID, err := d.client.ZoneIDByName(acme.UnFqdn(authZone))
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: failed to find zone %s: %v", authZone, err)
|
||||
}
|
||||
|
|
3
vendor/github.com/xenolf/lego/providers/dns/dns_providers.go
generated
vendored
3
vendor/github.com/xenolf/lego/providers/dns/dns_providers.go
generated
vendored
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/xenolf/lego/providers/dns/dnsimple"
|
||||
"github.com/xenolf/lego/providers/dns/dnsmadeeasy"
|
||||
"github.com/xenolf/lego/providers/dns/dnspod"
|
||||
"github.com/xenolf/lego/providers/dns/dreamhost"
|
||||
"github.com/xenolf/lego/providers/dns/duckdns"
|
||||
"github.com/xenolf/lego/providers/dns/dyn"
|
||||
"github.com/xenolf/lego/providers/dns/exec"
|
||||
|
@ -72,6 +73,8 @@ func NewDNSChallengeProviderByName(name string) (acme.ChallengeProvider, error)
|
|||
return dnsmadeeasy.NewDNSProvider()
|
||||
case "dnspod":
|
||||
return dnspod.NewDNSProvider()
|
||||
case "dreamhost":
|
||||
return dreamhost.NewDNSProvider()
|
||||
case "duckdns":
|
||||
return duckdns.NewDNSProvider()
|
||||
case "dyn":
|
||||
|
|
4
vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/client.go
generated
vendored
4
vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/client.go
generated
vendored
|
@ -38,11 +38,11 @@ type Client struct {
|
|||
// NewClient creates a DNSMadeEasy client
|
||||
func NewClient(apiKey string, apiSecret string) (*Client, error) {
|
||||
if apiKey == "" {
|
||||
return nil, fmt.Errorf("DNSMadeEasy: credentials missing: API key")
|
||||
return nil, fmt.Errorf("credentials missing: API key")
|
||||
}
|
||||
|
||||
if apiSecret == "" {
|
||||
return nil, fmt.Errorf("DNSMadeEasy: credentials missing: API secret")
|
||||
return nil, fmt.Errorf("credentials missing: API secret")
|
||||
}
|
||||
|
||||
return &Client{
|
||||
|
|
24
vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/dnsmadeeasy.go
generated
vendored
24
vendor/github.com/xenolf/lego/providers/dns/dnsmadeeasy/dnsmadeeasy.go
generated
vendored
|
@ -5,7 +5,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -18,6 +17,7 @@ type Config struct {
|
|||
BaseURL string
|
||||
APIKey string
|
||||
APISecret string
|
||||
Sandbox bool
|
||||
HTTPClient *http.Client
|
||||
PropagationTimeout time.Duration
|
||||
PollingInterval time.Duration
|
||||
|
@ -55,15 +55,8 @@ func NewDNSProvider() (*DNSProvider, error) {
|
|||
return nil, fmt.Errorf("dnsmadeeasy: %v", err)
|
||||
}
|
||||
|
||||
var baseURL string
|
||||
if sandbox, _ := strconv.ParseBool(env.GetOrFile("DNSMADEEASY_SANDBOX")); sandbox {
|
||||
baseURL = "https://api.sandbox.dnsmadeeasy.com/V2.0"
|
||||
} else {
|
||||
baseURL = "https://api.dnsmadeeasy.com/V2.0"
|
||||
}
|
||||
|
||||
config := NewDefaultConfig()
|
||||
config.BaseURL = baseURL
|
||||
config.Sandbox = env.GetOrDefaultBool("DNSMADEEASY_SANDBOX", false)
|
||||
config.APIKey = values["DNSMADEEASY_API_KEY"]
|
||||
config.APISecret = values["DNSMADEEASY_API_SECRET"]
|
||||
|
||||
|
@ -88,8 +81,15 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, errors.New("dnsmadeeasy: the configuration of the DNS provider is nil")
|
||||
}
|
||||
|
||||
if config.BaseURL == "" {
|
||||
return nil, fmt.Errorf("dnsmadeeasy: base URL missing")
|
||||
var baseURL string
|
||||
if config.Sandbox {
|
||||
baseURL = "https://api.sandbox.dnsmadeeasy.com/V2.0"
|
||||
} else {
|
||||
if len(config.BaseURL) > 0 {
|
||||
baseURL = config.BaseURL
|
||||
} else {
|
||||
baseURL = "https://api.dnsmadeeasy.com/V2.0"
|
||||
}
|
||||
}
|
||||
|
||||
client, err := NewClient(config.APIKey, config.APISecret)
|
||||
|
@ -98,7 +98,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
}
|
||||
|
||||
client.HTTPClient = config.HTTPClient
|
||||
client.BaseURL = config.BaseURL
|
||||
client.BaseURL = baseURL
|
||||
|
||||
return &DNSProvider{
|
||||
client: client,
|
||||
|
|
73
vendor/github.com/xenolf/lego/providers/dns/dreamhost/client.go
generated
vendored
Normal file
73
vendor/github.com/xenolf/lego/providers/dns/dreamhost/client.go
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
package dreamhost
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
|
||||
"github.com/xenolf/lego/log"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultBaseURL = "https://api.dreamhost.com"
|
||||
|
||||
cmdAddRecord = "dns-add_record"
|
||||
cmdRemoveRecord = "dns-remove_record"
|
||||
)
|
||||
|
||||
type apiResponse struct {
|
||||
Data string `json:"data"`
|
||||
Result string `json:"result"`
|
||||
}
|
||||
|
||||
func (d *DNSProvider) buildQuery(action, domain, txt string) (*url.URL, error) {
|
||||
u, err := url.Parse(d.config.BaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := u.Query()
|
||||
query.Set("key", d.config.APIKey)
|
||||
query.Set("cmd", action)
|
||||
query.Set("format", "json")
|
||||
query.Set("record", domain)
|
||||
query.Set("type", "TXT")
|
||||
query.Set("value", txt)
|
||||
query.Set("comment", url.QueryEscape("Managed By lego"))
|
||||
u.RawQuery = query.Encode()
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// updateTxtRecord will either add or remove a TXT record.
|
||||
// action is either cmdAddRecord or cmdRemoveRecord
|
||||
func (d *DNSProvider) updateTxtRecord(u fmt.Stringer) error {
|
||||
resp, err := d.config.HTTPClient.Get(u.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("request failed with HTTP status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
raw, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read body: %v", err)
|
||||
}
|
||||
|
||||
var response apiResponse
|
||||
err = json.Unmarshal(raw, &response)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to decode API server response: %v: %s", err, string(raw))
|
||||
}
|
||||
|
||||
if response.Result == "error" {
|
||||
return fmt.Errorf("add TXT record failed: %s", response.Data)
|
||||
}
|
||||
|
||||
log.Infof("dreamhost: %s", response.Data)
|
||||
return nil
|
||||
}
|
111
vendor/github.com/xenolf/lego/providers/dns/dreamhost/dreamhost.go
generated
vendored
Normal file
111
vendor/github.com/xenolf/lego/providers/dns/dreamhost/dreamhost.go
generated
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
// Package dreamhost Adds lego support for http://dreamhost.com DNS updates
|
||||
// See https://help.dreamhost.com/hc/en-us/articles/217560167-API_overview
|
||||
// and https://help.dreamhost.com/hc/en-us/articles/217555707-DNS-API-commands for the API spec.
|
||||
package dreamhost
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/xenolf/lego/acme"
|
||||
"github.com/xenolf/lego/platform/config/env"
|
||||
)
|
||||
|
||||
// Config is used to configure the creation of the DNSProvider
|
||||
type Config struct {
|
||||
BaseURL string
|
||||
APIKey string
|
||||
PropagationTimeout time.Duration
|
||||
PollingInterval time.Duration
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// NewDefaultConfig returns a default configuration for the DNSProvider
|
||||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
BaseURL: defaultBaseURL,
|
||||
PropagationTimeout: env.GetOrDefaultSecond("DREAMHOST_PROPAGATION_TIMEOUT", 60*time.Minute),
|
||||
PollingInterval: env.GetOrDefaultSecond("DREAMHOST_POLLING_INTERVAL", 1*time.Minute),
|
||||
HTTPClient: &http.Client{
|
||||
Timeout: env.GetOrDefaultSecond("DREAMHOST_HTTP_TIMEOUT", 30*time.Second),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// DNSProvider adds and removes the record for the DNS challenge
|
||||
type DNSProvider struct {
|
||||
config *Config
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a new DNS provider using
|
||||
// environment variable DREAMHOST_TOKEN for adding and removing the DNS record.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
values, err := env.Get("DREAMHOST_API_KEY")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dreamhost: %v", err)
|
||||
}
|
||||
|
||||
config := NewDefaultConfig()
|
||||
config.APIKey = values["DREAMHOST_API_KEY"]
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
}
|
||||
|
||||
// NewDNSProviderConfig return a DNSProvider instance configured for DreamHost.
|
||||
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("dreamhost: the configuration of the DNS provider is nil")
|
||||
}
|
||||
|
||||
if config.APIKey == "" {
|
||||
return nil, errors.New("dreamhost: credentials missing")
|
||||
}
|
||||
|
||||
if config.BaseURL == "" {
|
||||
config.BaseURL = defaultBaseURL
|
||||
}
|
||||
|
||||
return &DNSProvider{config: config}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
record := acme.UnFqdn(fqdn)
|
||||
|
||||
u, err := d.buildQuery(cmdAddRecord, record, value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("dreamhost: %v", err)
|
||||
}
|
||||
|
||||
err = d.updateTxtRecord(u)
|
||||
if err != nil {
|
||||
return fmt.Errorf("dreamhost: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CleanUp clears DreamHost TXT record
|
||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
record := acme.UnFqdn(fqdn)
|
||||
|
||||
u, err := d.buildQuery(cmdRemoveRecord, record, value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("dreamhost: %v", err)
|
||||
}
|
||||
|
||||
err = d.updateTxtRecord(u)
|
||||
if err != nil {
|
||||
return fmt.Errorf("dreamhost: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Timeout returns the timeout and interval to use when checking for DNS propagation.
|
||||
// Adjusting here to cope with spikes in propagation times.
|
||||
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
2
vendor/github.com/xenolf/lego/providers/dns/fastdns/fastdns.go
generated
vendored
2
vendor/github.com/xenolf/lego/providers/dns/fastdns/fastdns.go
generated
vendored
|
@ -77,7 +77,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
}
|
||||
|
||||
if config.ClientToken == "" || config.ClientSecret == "" || config.AccessToken == "" || config.Host == "" {
|
||||
return nil, fmt.Errorf("FastDNS credentials are missing")
|
||||
return nil, fmt.Errorf("fastdns: credentials are missing")
|
||||
}
|
||||
|
||||
return &DNSProvider{config: config}, nil
|
||||
|
|
8
vendor/github.com/xenolf/lego/providers/dns/gandiv5/gandiv5.go
generated
vendored
8
vendor/github.com/xenolf/lego/providers/dns/gandiv5/gandiv5.go
generated
vendored
|
@ -102,6 +102,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
config.BaseURL = defaultBaseURL
|
||||
}
|
||||
|
||||
if config.TTL < minTTL {
|
||||
return nil, fmt.Errorf("gandiv5: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
|
||||
}
|
||||
|
||||
return &DNSProvider{
|
||||
config: config,
|
||||
inProgressFQDNs: make(map[string]inProgressInfo),
|
||||
|
@ -112,10 +116,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
if d.config.TTL < minTTL {
|
||||
d.config.TTL = minTTL // 300 is gandi minimum value for ttl
|
||||
}
|
||||
|
||||
// find authZone
|
||||
authZone, err := findZoneByFqdn(fqdn, acme.RecursiveNameservers)
|
||||
if err != nil {
|
||||
|
|
7
vendor/github.com/xenolf/lego/providers/dns/glesys/glesys.go
generated
vendored
7
vendor/github.com/xenolf/lego/providers/dns/glesys/glesys.go
generated
vendored
|
@ -93,6 +93,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, fmt.Errorf("glesys: incomplete credentials provided")
|
||||
}
|
||||
|
||||
if config.TTL < minTTL {
|
||||
return nil, fmt.Errorf("glesys: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
|
||||
}
|
||||
|
||||
return &DNSProvider{
|
||||
config: config,
|
||||
activeRecords: make(map[string]int),
|
||||
|
@ -103,9 +107,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
if d.config.TTL < minTTL {
|
||||
d.config.TTL = minTTL // 60 is GleSYS minimum value for ttl
|
||||
}
|
||||
// find authZone
|
||||
authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
|
||||
if err != nil {
|
||||
|
|
8
vendor/github.com/xenolf/lego/providers/dns/nifcloud/client.go
generated
vendored
8
vendor/github.com/xenolf/lego/providers/dns/nifcloud/client.go
generated
vendored
|
@ -89,13 +89,17 @@ type ChangeInfo struct {
|
|||
}
|
||||
|
||||
// NewClient Creates a new client of NIFCLOUD DNS
|
||||
func NewClient(accessKey string, secretKey string) *Client {
|
||||
func NewClient(accessKey string, secretKey string) (*Client, error) {
|
||||
if len(accessKey) == 0 || len(secretKey) == 0 {
|
||||
return nil, errors.New("credentials missing")
|
||||
}
|
||||
|
||||
return &Client{
|
||||
accessKey: accessKey,
|
||||
secretKey: secretKey,
|
||||
BaseURL: defaultBaseURL,
|
||||
HTTPClient: &http.Client{},
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Client client of NIFCLOUD DNS
|
||||
|
|
5
vendor/github.com/xenolf/lego/providers/dns/nifcloud/nifcloud.go
generated
vendored
5
vendor/github.com/xenolf/lego/providers/dns/nifcloud/nifcloud.go
generated
vendored
|
@ -77,7 +77,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, errors.New("nifcloud: the configuration of the DNS provider is nil")
|
||||
}
|
||||
|
||||
client := NewClient(config.AccessKey, config.SecretKey)
|
||||
client, err := NewClient(config.AccessKey, config.SecretKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("nifcloud: %v", err)
|
||||
}
|
||||
|
||||
if config.HTTPClient != nil {
|
||||
client.HTTPClient = config.HTTPClient
|
||||
|
|
162
vendor/github.com/xenolf/lego/providers/dns/otc/mock.go
generated
vendored
162
vendor/github.com/xenolf/lego/providers/dns/otc/mock.go
generated
vendored
|
@ -1,162 +0,0 @@
|
|||
package otc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var fakeOTCUserName = "test"
|
||||
var fakeOTCPassword = "test"
|
||||
var fakeOTCDomainName = "test"
|
||||
var fakeOTCProjectName = "test"
|
||||
var fakeOTCToken = "62244bc21da68d03ebac94e6636ff01f"
|
||||
|
||||
// DNSMock mock
|
||||
type DNSMock struct {
|
||||
t *testing.T
|
||||
Server *httptest.Server
|
||||
Mux *http.ServeMux
|
||||
}
|
||||
|
||||
// NewDNSMock create a new DNSMock
|
||||
func NewDNSMock(t *testing.T) *DNSMock {
|
||||
return &DNSMock{
|
||||
t: t,
|
||||
}
|
||||
}
|
||||
|
||||
// Setup creates the mock server
|
||||
func (m *DNSMock) Setup() {
|
||||
m.Mux = http.NewServeMux()
|
||||
m.Server = httptest.NewServer(m.Mux)
|
||||
}
|
||||
|
||||
// ShutdownServer creates the mock server
|
||||
func (m *DNSMock) ShutdownServer() {
|
||||
m.Server.Close()
|
||||
}
|
||||
|
||||
// HandleAuthSuccessfully Handle auth successfully
|
||||
func (m *DNSMock) HandleAuthSuccessfully() {
|
||||
m.Mux.HandleFunc("/v3/auth/token", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Subject-Token", fakeOTCToken)
|
||||
|
||||
fmt.Fprintf(w, `{
|
||||
"token": {
|
||||
"catalog": [
|
||||
{
|
||||
"type": "dns",
|
||||
"id": "56cd81db1f8445d98652479afe07c5ba",
|
||||
"name": "",
|
||||
"endpoints": [
|
||||
{
|
||||
"url": "%s",
|
||||
"region": "eu-de",
|
||||
"region_id": "eu-de",
|
||||
"interface": "public",
|
||||
"id": "0047a06690484d86afe04877074efddf"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}}`, m.Server.URL)
|
||||
})
|
||||
}
|
||||
|
||||
// HandleListZonesSuccessfully Handle list zones successfully
|
||||
func (m *DNSMock) HandleListZonesSuccessfully() {
|
||||
m.Mux.HandleFunc("/v2/zones", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, `{
|
||||
"zones":[{
|
||||
"id":"123123"
|
||||
}]}
|
||||
`)
|
||||
|
||||
assert.Equal(m.t, r.Method, http.MethodGet)
|
||||
assert.Equal(m.t, r.URL.Path, "/v2/zones")
|
||||
assert.Equal(m.t, r.URL.RawQuery, "name=example.com.")
|
||||
assert.Equal(m.t, r.Header.Get("Content-Type"), "application/json")
|
||||
})
|
||||
}
|
||||
|
||||
// HandleListZonesEmpty Handle list zones empty
|
||||
func (m *DNSMock) HandleListZonesEmpty() {
|
||||
m.Mux.HandleFunc("/v2/zones", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, `{
|
||||
"zones":[
|
||||
]}
|
||||
`)
|
||||
|
||||
assert.Equal(m.t, r.Method, http.MethodGet)
|
||||
assert.Equal(m.t, r.URL.Path, "/v2/zones")
|
||||
assert.Equal(m.t, r.URL.RawQuery, "name=example.com.")
|
||||
assert.Equal(m.t, r.Header.Get("Content-Type"), "application/json")
|
||||
})
|
||||
}
|
||||
|
||||
// HandleDeleteRecordsetsSuccessfully Handle delete recordsets successfully
|
||||
func (m *DNSMock) HandleDeleteRecordsetsSuccessfully() {
|
||||
m.Mux.HandleFunc("/v2/zones/123123/recordsets/321321", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, `{
|
||||
"zones":[{
|
||||
"id":"123123"
|
||||
}]}
|
||||
`)
|
||||
|
||||
assert.Equal(m.t, r.Method, http.MethodDelete)
|
||||
assert.Equal(m.t, r.URL.Path, "/v2/zones/123123/recordsets/321321")
|
||||
assert.Equal(m.t, r.Header.Get("Content-Type"), "application/json")
|
||||
})
|
||||
}
|
||||
|
||||
// HandleListRecordsetsEmpty Handle list recordsets empty
|
||||
func (m *DNSMock) HandleListRecordsetsEmpty() {
|
||||
m.Mux.HandleFunc("/v2/zones/123123/recordsets", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, `{
|
||||
"recordsets":[
|
||||
]}
|
||||
`)
|
||||
|
||||
assert.Equal(m.t, r.URL.Path, "/v2/zones/123123/recordsets")
|
||||
assert.Equal(m.t, r.URL.RawQuery, "type=TXT&name=_acme-challenge.example.com.")
|
||||
})
|
||||
}
|
||||
|
||||
// HandleListRecordsetsSuccessfully Handle list recordsets successfully
|
||||
func (m *DNSMock) HandleListRecordsetsSuccessfully() {
|
||||
m.Mux.HandleFunc("/v2/zones/123123/recordsets", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == http.MethodGet {
|
||||
fmt.Fprintf(w, `{
|
||||
"recordsets":[{
|
||||
"id":"321321"
|
||||
}]}
|
||||
`)
|
||||
|
||||
assert.Equal(m.t, r.URL.Path, "/v2/zones/123123/recordsets")
|
||||
assert.Equal(m.t, r.URL.RawQuery, "type=TXT&name=_acme-challenge.example.com.")
|
||||
|
||||
} else if r.Method == http.MethodPost {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
|
||||
assert.Nil(m.t, err)
|
||||
exceptedString := "{\"name\":\"_acme-challenge.example.com.\",\"description\":\"Added TXT record for ACME dns-01 challenge using lego client\",\"type\":\"TXT\",\"ttl\":300,\"records\":[\"\\\"w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI\\\"\"]}"
|
||||
assert.Equal(m.t, string(body), exceptedString)
|
||||
|
||||
fmt.Fprintf(w, `{
|
||||
"recordsets":[{
|
||||
"id":"321321"
|
||||
}]}
|
||||
`)
|
||||
|
||||
} else {
|
||||
m.t.Errorf("Expected method to be 'GET' or 'POST' but got '%s'", r.Method)
|
||||
}
|
||||
|
||||
assert.Equal(m.t, r.Header.Get("Content-Type"), "application/json")
|
||||
})
|
||||
}
|
50
vendor/github.com/xenolf/lego/providers/dns/rackspace/client.go
generated
vendored
50
vendor/github.com/xenolf/lego/providers/dns/rackspace/client.go
generated
vendored
|
@ -16,20 +16,44 @@ type AuthData struct {
|
|||
Auth `json:"auth"`
|
||||
}
|
||||
|
||||
// Identity Identity
|
||||
// Identity Identity
|
||||
type Identity struct {
|
||||
Access struct {
|
||||
ServiceCatalog []struct {
|
||||
Endpoints []struct {
|
||||
PublicURL string `json:"publicURL"`
|
||||
TenantID string `json:"tenantId"`
|
||||
} `json:"endpoints"`
|
||||
Name string `json:"name"`
|
||||
} `json:"serviceCatalog"`
|
||||
Token struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"token"`
|
||||
} `json:"access"`
|
||||
Access Access `json:"access"`
|
||||
}
|
||||
|
||||
// Access Access
|
||||
type Access struct {
|
||||
ServiceCatalog []ServiceCatalog `json:"serviceCatalog"`
|
||||
Token Token `json:"token"`
|
||||
}
|
||||
|
||||
// Token Token
|
||||
type Token struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
// ServiceCatalog ServiceCatalog
|
||||
type ServiceCatalog struct {
|
||||
Endpoints []Endpoint `json:"endpoints"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Endpoint Endpoint
|
||||
type Endpoint struct {
|
||||
PublicURL string `json:"publicURL"`
|
||||
TenantID string `json:"tenantId"`
|
||||
}
|
||||
|
||||
// ZoneSearchResponse represents the response when querying Rackspace DNS zones
|
||||
type ZoneSearchResponse struct {
|
||||
TotalEntries int `json:"totalEntries"`
|
||||
HostedZones []HostedZone `json:"domains"`
|
||||
}
|
||||
|
||||
// HostedZone HostedZone
|
||||
type HostedZone struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Records is the list of records sent/received from the DNS API
|
||||
|
|
91
vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace.go
generated
vendored
91
vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace.go
generated
vendored
|
@ -89,39 +89,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, fmt.Errorf("rackspace: credentials missing")
|
||||
}
|
||||
|
||||
authData := AuthData{
|
||||
Auth: Auth{
|
||||
APIKeyCredentials: APIKeyCredentials{
|
||||
Username: config.APIUser,
|
||||
APIKey: config.APIKey,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
body, err := json.Marshal(authData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, config.BaseURL, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// client := &http.Client{Timeout: 30 * time.Second}
|
||||
resp, err := config.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("rackspace: error querying Identity API: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("rackspace: authentication failed: response code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var identity Identity
|
||||
err = json.NewDecoder(resp.Body).Decode(&identity)
|
||||
identity, err := login(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("rackspace: %v", err)
|
||||
}
|
||||
|
@ -134,6 +102,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
if dnsEndpoint == "" {
|
||||
return nil, fmt.Errorf("rackspace: failed to populate DNS endpoint, check Rackspace API for changes")
|
||||
}
|
||||
|
@ -149,6 +118,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
// Present creates a TXT record to fulfill the dns-01 challenge
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
zoneID, err := d.getHostedZoneID(fqdn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("rackspace: %v", err)
|
||||
|
@ -178,6 +148,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
// CleanUp removes the TXT record matching the specified parameters
|
||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
zoneID, err := d.getHostedZoneID(fqdn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("rackspace: %v", err)
|
||||
|
@ -204,15 +175,6 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
// getHostedZoneID performs a lookup to get the DNS zone which needs
|
||||
// modifying for a given FQDN
|
||||
func (d *DNSProvider) getHostedZoneID(fqdn string) (int, error) {
|
||||
// HostedZones represents the response when querying Rackspace DNS zones
|
||||
type ZoneSearchResponse struct {
|
||||
TotalEntries int `json:"totalEntries"`
|
||||
HostedZones []struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"domains"`
|
||||
}
|
||||
|
||||
authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -250,8 +212,7 @@ func (d *DNSProvider) findTxtRecord(fqdn string, zoneID int) (*Record, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
recordsLength := len(records.Record)
|
||||
switch recordsLength {
|
||||
switch len(records.Record) {
|
||||
case 1:
|
||||
case 0:
|
||||
return nil, fmt.Errorf("no TXT record found for %s", fqdn)
|
||||
|
@ -265,6 +226,7 @@ func (d *DNSProvider) findTxtRecord(fqdn string, zoneID int) (*Record, error) {
|
|||
// makeRequest is a wrapper function used for making DNS API requests
|
||||
func (d *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawMessage, error) {
|
||||
url := d.cloudDNSEndpoint + uri
|
||||
|
||||
req, err := http.NewRequest(method, url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -292,3 +254,44 @@ func (d *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawM
|
|||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func login(config *Config) (*Identity, error) {
|
||||
authData := AuthData{
|
||||
Auth: Auth{
|
||||
APIKeyCredentials: APIKeyCredentials{
|
||||
Username: config.APIUser,
|
||||
APIKey: config.APIKey,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
body, err := json.Marshal(authData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, config.BaseURL, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := config.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error querying Identity API: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("authentication failed: response code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var identity Identity
|
||||
err = json.NewDecoder(resp.Body).Decode(&identity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &identity, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue