2019-03-11 18:56:48 +02:00
|
|
|
package rackspace
|
2016-11-04 11:29:14 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2021-08-25 11:44:11 +02:00
|
|
|
"io"
|
2016-11-04 11:29:14 +02:00
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2020-09-02 03:20:01 +02:00
|
|
|
"github.com/go-acme/lego/v4/platform/tester"
|
2016-11-04 11:29:14 +02:00
|
|
|
"github.com/stretchr/testify/assert"
|
2018-09-15 19:07:24 +02:00
|
|
|
"github.com/stretchr/testify/require"
|
2016-11-04 11:29:14 +02:00
|
|
|
)
|
|
|
|
|
2020-03-12 00:51:10 +02:00
|
|
|
const envDomain = envNamespace + "DOMAIN"
|
|
|
|
|
2018-10-16 17:52:57 +02:00
|
|
|
var envTest = tester.NewEnvTest(
|
2020-03-12 00:51:10 +02:00
|
|
|
EnvUser,
|
|
|
|
EnvAPIKey).
|
|
|
|
WithDomain(envDomain)
|
2018-10-12 19:29:18 +02:00
|
|
|
|
|
|
|
func TestNewDNSProviderConfig(t *testing.T) {
|
|
|
|
config, tearDown := setupTest()
|
|
|
|
defer tearDown()
|
|
|
|
|
|
|
|
provider, err := NewDNSProviderConfig(config)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.NotNil(t, provider.config)
|
|
|
|
|
|
|
|
assert.Equal(t, provider.token, "testToken", "The token should match")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewDNSProviderConfig_MissingCredErr(t *testing.T) {
|
|
|
|
_, err := NewDNSProviderConfig(NewDefaultConfig())
|
|
|
|
assert.EqualError(t, err, "rackspace: credentials missing")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDNSProvider_Present(t *testing.T) {
|
|
|
|
config, tearDown := setupTest()
|
|
|
|
defer tearDown()
|
|
|
|
|
|
|
|
provider, err := NewDNSProviderConfig(config)
|
|
|
|
|
|
|
|
if assert.NoError(t, err) {
|
|
|
|
err = provider.Present("example.com", "token", "keyAuth")
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDNSProvider_CleanUp(t *testing.T) {
|
|
|
|
config, tearDown := setupTest()
|
|
|
|
defer tearDown()
|
|
|
|
|
|
|
|
provider, err := NewDNSProviderConfig(config)
|
|
|
|
|
|
|
|
if assert.NoError(t, err) {
|
|
|
|
err = provider.CleanUp("example.com", "token", "keyAuth")
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLiveNewDNSProvider_ValidEnv(t *testing.T) {
|
2018-10-16 17:52:57 +02:00
|
|
|
if !envTest.IsLiveTest() {
|
2018-10-12 19:29:18 +02:00
|
|
|
t.Skip("skipping live test")
|
2016-11-04 11:29:14 +02:00
|
|
|
}
|
2018-10-12 19:29:18 +02:00
|
|
|
|
2018-10-16 17:52:57 +02:00
|
|
|
envTest.RestoreEnv()
|
2018-10-12 19:29:18 +02:00
|
|
|
provider, err := NewDNSProvider()
|
|
|
|
require.NoError(t, err)
|
2018-10-16 17:52:57 +02:00
|
|
|
|
2018-10-12 19:29:18 +02:00
|
|
|
assert.Contains(t, provider.cloudDNSEndpoint, "https://dns.api.rackspacecloud.com/v1.0/", "The endpoint URL should contain the base")
|
2016-11-04 11:29:14 +02:00
|
|
|
}
|
|
|
|
|
2018-10-12 19:29:18 +02:00
|
|
|
func TestLivePresent(t *testing.T) {
|
2018-10-16 17:52:57 +02:00
|
|
|
if !envTest.IsLiveTest() {
|
2018-10-12 19:29:18 +02:00
|
|
|
t.Skip("skipping live test")
|
|
|
|
}
|
|
|
|
|
2018-10-16 17:52:57 +02:00
|
|
|
envTest.RestoreEnv()
|
2018-10-12 19:29:18 +02:00
|
|
|
provider, err := NewDNSProvider()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2018-10-16 17:52:57 +02:00
|
|
|
err = provider.Present(envTest.GetDomain(), "", "112233445566==")
|
2018-10-12 19:29:18 +02:00
|
|
|
require.NoError(t, err)
|
2016-11-04 11:29:14 +02:00
|
|
|
}
|
|
|
|
|
2018-10-12 19:29:18 +02:00
|
|
|
func TestLiveCleanUp(t *testing.T) {
|
2018-10-16 17:52:57 +02:00
|
|
|
if !envTest.IsLiveTest() {
|
2018-10-12 19:29:18 +02:00
|
|
|
t.Skip("skipping live test")
|
|
|
|
}
|
|
|
|
|
2018-10-16 17:52:57 +02:00
|
|
|
envTest.RestoreEnv()
|
2018-10-12 19:29:18 +02:00
|
|
|
provider, err := NewDNSProvider()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2018-10-16 17:52:57 +02:00
|
|
|
time.Sleep(15 * time.Second)
|
|
|
|
|
|
|
|
err = provider.CleanUp(envTest.GetDomain(), "", "112233445566==")
|
2018-10-12 19:29:18 +02:00
|
|
|
require.NoError(t, err)
|
2016-11-04 11:29:14 +02:00
|
|
|
}
|
|
|
|
|
2018-10-12 19:29:18 +02:00
|
|
|
func setupTest() (*Config, func()) {
|
|
|
|
apiURL, tearDown := startTestServers()
|
2016-11-04 11:29:14 +02:00
|
|
|
|
2018-10-12 19:29:18 +02:00
|
|
|
config := NewDefaultConfig()
|
|
|
|
config.APIUser = "testUser"
|
|
|
|
config.APIKey = "testKey"
|
|
|
|
config.BaseURL = apiURL
|
2018-05-30 19:53:04 +02:00
|
|
|
|
2018-10-12 19:29:18 +02:00
|
|
|
return config, tearDown
|
2016-11-04 11:29:14 +02:00
|
|
|
}
|
|
|
|
|
2018-10-12 19:29:18 +02:00
|
|
|
func startTestServers() (string, func()) {
|
|
|
|
dnsAPI := httptest.NewServer(dnsHandler())
|
|
|
|
identityAPI := httptest.NewServer(identityHandler(dnsAPI.URL + "/123456"))
|
|
|
|
|
|
|
|
return identityAPI.URL + "/", func() {
|
|
|
|
identityAPI.Close()
|
|
|
|
dnsAPI.Close()
|
|
|
|
}
|
2016-11-04 11:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func identityHandler(dnsEndpoint string) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2021-08-25 11:44:11 +02:00
|
|
|
reqBody, err := io.ReadAll(r.Body)
|
2016-11-04 11:29:14 +02:00
|
|
|
if err != nil {
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
2018-10-12 19:29:18 +02:00
|
|
|
|
2018-12-06 23:50:17 +02:00
|
|
|
if string(reqBody) != `{"auth":{"RAX-KSKEY:apiKeyCredentials":{"username":"testUser","apiKey":"testKey"}}}` {
|
2016-11-04 11:29:14 +02:00
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
2018-10-12 19:29:18 +02:00
|
|
|
|
2018-12-06 23:50:17 +02:00
|
|
|
resp := strings.Replace(identityResponseMock, "https://dns.api.rackspacecloud.com/v1.0/123456", dnsEndpoint, 1)
|
2016-11-04 11:29:14 +02:00
|
|
|
w.WriteHeader(http.StatusOK)
|
2019-02-06 19:15:53 +02:00
|
|
|
fmt.Fprint(w, resp)
|
2016-11-04 11:29:14 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-10-12 19:29:18 +02:00
|
|
|
func dnsHandler() *http.ServeMux {
|
2016-11-04 11:29:14 +02:00
|
|
|
mux := http.NewServeMux()
|
|
|
|
|
|
|
|
// Used by `getHostedZoneID()` finding `zoneID` "?name=example.com"
|
|
|
|
mux.HandleFunc("/123456/domains", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if r.URL.Query().Get("name") == "example.com" {
|
|
|
|
w.WriteHeader(http.StatusOK)
|
2019-02-06 19:15:53 +02:00
|
|
|
fmt.Fprint(w, zoneDetailsMock)
|
2016-11-04 11:29:14 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
})
|
|
|
|
|
|
|
|
mux.HandleFunc("/123456/domains/112233/records", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
switch r.Method {
|
|
|
|
// Used by `Present()` creating the TXT record
|
|
|
|
case http.MethodPost:
|
2021-08-25 11:44:11 +02:00
|
|
|
reqBody, err := io.ReadAll(r.Body)
|
2016-11-04 11:29:14 +02:00
|
|
|
if err != nil {
|
2018-10-12 19:29:18 +02:00
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
2016-11-04 11:29:14 +02:00
|
|
|
return
|
|
|
|
}
|
2018-12-06 23:50:17 +02:00
|
|
|
|
|
|
|
if string(reqBody) != `{"records":[{"name":"_acme-challenge.example.com","type":"TXT","data":"pW9ZKG0xz_PCriK-nCMOjADy9eJcgGWIzkkj2fN4uZM","ttl":300}]}` {
|
2016-11-04 11:29:14 +02:00
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
2018-12-06 23:50:17 +02:00
|
|
|
|
2016-11-04 11:29:14 +02:00
|
|
|
w.WriteHeader(http.StatusAccepted)
|
2019-02-06 19:15:53 +02:00
|
|
|
fmt.Fprint(w, recordResponseMock)
|
2018-10-12 19:29:18 +02:00
|
|
|
// Used by `findTxtRecord()` finding `record.ID` "?type=TXT&name=_acme-challenge.example.com"
|
2016-11-04 11:29:14 +02:00
|
|
|
case http.MethodGet:
|
|
|
|
if r.URL.Query().Get("type") == "TXT" && r.URL.Query().Get("name") == "_acme-challenge.example.com" {
|
|
|
|
w.WriteHeader(http.StatusOK)
|
2019-02-06 19:15:53 +02:00
|
|
|
fmt.Fprint(w, recordDetailsMock)
|
2016-11-04 11:29:14 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
return
|
2018-10-12 19:29:18 +02:00
|
|
|
// Used by `CleanUp()` deleting the TXT record "?id=445566"
|
2016-11-04 11:29:14 +02:00
|
|
|
case http.MethodDelete:
|
|
|
|
if r.URL.Query().Get("id") == "TXT-654321" {
|
|
|
|
w.WriteHeader(http.StatusOK)
|
2019-02-06 19:15:53 +02:00
|
|
|
fmt.Fprint(w, recordDeleteMock)
|
2016-11-04 11:29:14 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.WriteHeader(http.StatusNotFound)
|
|
|
|
fmt.Printf("Not Found for Request: (%+v)\n\n", r)
|
|
|
|
})
|
|
|
|
|
|
|
|
return mux
|
|
|
|
}
|