forked from TrueCloudLab/lego
Merge pull request #710 from ldez/feature/httpreq
Add DNS provider for "HTTP request".
This commit is contained in:
commit
fac6e4995c
5 changed files with 519 additions and 0 deletions
2
cli.go
2
cli.go
|
@ -226,6 +226,7 @@ Here is an example bash command using the CloudFlare DNS provider:
|
||||||
fmt.Fprintln(w, "\tglesys:\tGLESYS_API_USER, GLESYS_API_KEY")
|
fmt.Fprintln(w, "\tglesys:\tGLESYS_API_USER, GLESYS_API_KEY")
|
||||||
fmt.Fprintln(w, "\tgodaddy:\tGODADDY_API_KEY, GODADDY_API_SECRET")
|
fmt.Fprintln(w, "\tgodaddy:\tGODADDY_API_KEY, GODADDY_API_SECRET")
|
||||||
fmt.Fprintln(w, "\thostingde:\tHOSTINGDE_API_KEY, HOSTINGDE_ZONE_NAME")
|
fmt.Fprintln(w, "\thostingde:\tHOSTINGDE_API_KEY, HOSTINGDE_ZONE_NAME")
|
||||||
|
fmt.Fprintln(w, "\thttpreq:\tHTTPREQ_ENDPOINT, HTTPREQ_MODE, HTTPREQ_USERNAME, HTTPREQ_PASSWORD")
|
||||||
fmt.Fprintln(w, "\tiij:\tIIJ_API_ACCESS_KEY, IIJ_API_SECRET_KEY, IIJ_DO_SERVICE_CODE")
|
fmt.Fprintln(w, "\tiij:\tIIJ_API_ACCESS_KEY, IIJ_API_SECRET_KEY, IIJ_DO_SERVICE_CODE")
|
||||||
fmt.Fprintln(w, "\tinwx:\tINWX_USERNAME, INWX_PASSWORD")
|
fmt.Fprintln(w, "\tinwx:\tINWX_USERNAME, INWX_PASSWORD")
|
||||||
fmt.Fprintln(w, "\tlightsail:\tAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, DNS_ZONE")
|
fmt.Fprintln(w, "\tlightsail:\tAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, DNS_ZONE")
|
||||||
|
@ -275,6 +276,7 @@ Here is an example bash command using the CloudFlare DNS provider:
|
||||||
fmt.Fprintln(w, "\tglesys:\tGLESYS_POLLING_INTERVAL, GLESYS_PROPAGATION_TIMEOUT, GLESYS_TTL, GLESYS_HTTP_TIMEOUT")
|
fmt.Fprintln(w, "\tglesys:\tGLESYS_POLLING_INTERVAL, GLESYS_PROPAGATION_TIMEOUT, GLESYS_TTL, GLESYS_HTTP_TIMEOUT")
|
||||||
fmt.Fprintln(w, "\tgodaddy:\tGODADDY_POLLING_INTERVAL, GODADDY_PROPAGATION_TIMEOUT, GODADDY_TTL, GODADDY_HTTP_TIMEOUT")
|
fmt.Fprintln(w, "\tgodaddy:\tGODADDY_POLLING_INTERVAL, GODADDY_PROPAGATION_TIMEOUT, GODADDY_TTL, GODADDY_HTTP_TIMEOUT")
|
||||||
fmt.Fprintln(w, "\thostingde:\tHOSTINGDE_POLLING_INTERVAL, HOSTINGDE_PROPAGATION_TIMEOUT, HOSTINGDE_TTL, HOSTINGDE_HTTP_TIMEOUT")
|
fmt.Fprintln(w, "\thostingde:\tHOSTINGDE_POLLING_INTERVAL, HOSTINGDE_PROPAGATION_TIMEOUT, HOSTINGDE_TTL, HOSTINGDE_HTTP_TIMEOUT")
|
||||||
|
fmt.Fprintln(w, "\thttpreq:\t,HTTPREQ_POLLING_INTERVAL, HTTPREQ_PROPAGATION_TIMEOUT, HTTPREQ_HTTP_TIMEOUT")
|
||||||
fmt.Fprintln(w, "\tiij:\tIIJ_POLLING_INTERVAL, IIJ_PROPAGATION_TIMEOUT, IIJ_TTL")
|
fmt.Fprintln(w, "\tiij:\tIIJ_POLLING_INTERVAL, IIJ_PROPAGATION_TIMEOUT, IIJ_TTL")
|
||||||
fmt.Fprintln(w, "\tinwx:\tINWX_POLLING_INTERVAL, INWX_PROPAGATION_TIMEOUT, INWX_TTL, INWX_SANDBOX")
|
fmt.Fprintln(w, "\tinwx:\tINWX_POLLING_INTERVAL, INWX_PROPAGATION_TIMEOUT, INWX_TTL, INWX_SANDBOX")
|
||||||
fmt.Fprintln(w, "\tlightsail:\tLIGHTSAIL_POLLING_INTERVAL, LIGHTSAIL_PROPAGATION_TIMEOUT")
|
fmt.Fprintln(w, "\tlightsail:\tLIGHTSAIL_POLLING_INTERVAL, LIGHTSAIL_PROPAGATION_TIMEOUT")
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/xenolf/lego/providers/dns/glesys"
|
"github.com/xenolf/lego/providers/dns/glesys"
|
||||||
"github.com/xenolf/lego/providers/dns/godaddy"
|
"github.com/xenolf/lego/providers/dns/godaddy"
|
||||||
"github.com/xenolf/lego/providers/dns/hostingde"
|
"github.com/xenolf/lego/providers/dns/hostingde"
|
||||||
|
"github.com/xenolf/lego/providers/dns/httpreq"
|
||||||
"github.com/xenolf/lego/providers/dns/iij"
|
"github.com/xenolf/lego/providers/dns/iij"
|
||||||
"github.com/xenolf/lego/providers/dns/inwx"
|
"github.com/xenolf/lego/providers/dns/inwx"
|
||||||
"github.com/xenolf/lego/providers/dns/lightsail"
|
"github.com/xenolf/lego/providers/dns/lightsail"
|
||||||
|
@ -105,6 +106,8 @@ func NewDNSChallengeProviderByName(name string) (acme.ChallengeProvider, error)
|
||||||
return godaddy.NewDNSProvider()
|
return godaddy.NewDNSProvider()
|
||||||
case "hostingde":
|
case "hostingde":
|
||||||
return hostingde.NewDNSProvider()
|
return hostingde.NewDNSProvider()
|
||||||
|
case "httpreq":
|
||||||
|
return httpreq.NewDNSProvider()
|
||||||
case "iij":
|
case "iij":
|
||||||
return iij.NewDNSProvider()
|
return iij.NewDNSProvider()
|
||||||
case "inwx":
|
case "inwx":
|
||||||
|
|
193
providers/dns/httpreq/httpreq.go
Normal file
193
providers/dns/httpreq/httpreq.go
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
// Package httpreq implements a DNS provider for solving the DNS-01 challenge through a HTTP server.
|
||||||
|
package httpreq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xenolf/lego/acme"
|
||||||
|
"github.com/xenolf/lego/platform/config/env"
|
||||||
|
)
|
||||||
|
|
||||||
|
type message struct {
|
||||||
|
FQDN string `json:"fqdn"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type messageRaw struct {
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
KeyAuth string `json:"keyAuth"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config is used to configure the creation of the DNSProvider
|
||||||
|
type Config struct {
|
||||||
|
Endpoint *url.URL
|
||||||
|
Mode string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
PropagationTimeout time.Duration
|
||||||
|
PollingInterval time.Duration
|
||||||
|
HTTPClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultConfig returns a default configuration for the DNSProvider
|
||||||
|
func NewDefaultConfig() *Config {
|
||||||
|
return &Config{
|
||||||
|
PropagationTimeout: env.GetOrDefaultSecond("HTTPREQ_PROPAGATION_TIMEOUT", acme.DefaultPropagationTimeout),
|
||||||
|
PollingInterval: env.GetOrDefaultSecond("HTTPREQ_POLLING_INTERVAL", acme.DefaultPollingInterval),
|
||||||
|
HTTPClient: &http.Client{
|
||||||
|
Timeout: env.GetOrDefaultSecond("HTTPREQ_HTTP_TIMEOUT", 30*time.Second),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSProvider describes a provider for acme-proxy
|
||||||
|
type DNSProvider struct {
|
||||||
|
config *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDNSProvider returns a DNSProvider instance.
|
||||||
|
func NewDNSProvider() (*DNSProvider, error) {
|
||||||
|
values, err := env.Get("HTTPREQ_ENDPOINT")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("httpreq: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint, err := url.Parse(values["HTTPREQ_ENDPOINT"])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("httpreq: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := NewDefaultConfig()
|
||||||
|
config.Mode = os.Getenv("HTTPREQ_MODE")
|
||||||
|
config.Username = os.Getenv("HTTPREQ_USERNAME")
|
||||||
|
config.Password = os.Getenv("HTTPREQ_PASSWORD")
|
||||||
|
config.Endpoint = endpoint
|
||||||
|
return NewDNSProviderConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDNSProviderConfig return a DNSProvider .
|
||||||
|
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||||
|
if config == nil {
|
||||||
|
return nil, errors.New("httpreq: the configuration of the DNS provider is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Endpoint == nil {
|
||||||
|
return nil, errors.New("httpreq: the endpoint is missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DNSProvider{config: config}, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Present creates a TXT record to fulfill the dns-01 challenge
|
||||||
|
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
|
if d.config.Mode == "RAW" {
|
||||||
|
msg := &messageRaw{
|
||||||
|
Domain: domain,
|
||||||
|
Token: token,
|
||||||
|
KeyAuth: keyAuth,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := d.doPost("/present", msg)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("httpreq: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||||
|
msg := &message{
|
||||||
|
FQDN: fqdn,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := d.doPost("/present", msg)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("httpreq: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanUp removes the TXT record matching the specified parameters
|
||||||
|
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
|
if d.config.Mode == "RAW" {
|
||||||
|
msg := &messageRaw{
|
||||||
|
Domain: domain,
|
||||||
|
Token: token,
|
||||||
|
KeyAuth: keyAuth,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := d.doPost("/cleanup", msg)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("httpreq: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||||
|
msg := &message{
|
||||||
|
FQDN: fqdn,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := d.doPost("/cleanup", msg)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("httpreq: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) doPost(uri string, msg interface{}) error {
|
||||||
|
reqBody := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(reqBody).Encode(msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint, err := d.config.Endpoint.Parse(uri)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPost, endpoint.String(), reqBody)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
if len(d.config.Username) > 0 && len(d.config.Password) > 0 {
|
||||||
|
req.SetBasicAuth(d.config.Username, d.config.Password)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := d.config.HTTPClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode >= http.StatusBadRequest {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%d: failed to read response body: %v", resp.StatusCode, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("%d: request failed: %v", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
288
providers/dns/httpreq/httpreq_test.go
Normal file
288
providers/dns/httpreq/httpreq_test.go
Normal file
|
@ -0,0 +1,288 @@
|
||||||
|
package httpreq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/xenolf/lego/platform/tester"
|
||||||
|
)
|
||||||
|
|
||||||
|
var envTest = tester.NewEnvTest("HTTPREQ_ENDPOINT", "HTTPREQ_MODE", "HTTPREQ_USERNAME", "HTTPREQ_PASSWORD")
|
||||||
|
|
||||||
|
func TestNewDNSProvider(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
envVars map[string]string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "success",
|
||||||
|
envVars: map[string]string{
|
||||||
|
"HTTPREQ_ENDPOINT": "http://localhost:8090",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid URL",
|
||||||
|
envVars: map[string]string{
|
||||||
|
"HTTPREQ_ENDPOINT": ":",
|
||||||
|
},
|
||||||
|
expected: "httpreq: parse :: missing protocol scheme",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "missing endpoint",
|
||||||
|
envVars: map[string]string{
|
||||||
|
"HTTPREQ_ENDPOINT": "",
|
||||||
|
},
|
||||||
|
expected: "httpreq: some credentials information are missing: HTTPREQ_ENDPOINT",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
defer envTest.RestoreEnv()
|
||||||
|
envTest.ClearEnv()
|
||||||
|
|
||||||
|
envTest.Apply(test.envVars)
|
||||||
|
|
||||||
|
p, err := NewDNSProvider()
|
||||||
|
|
||||||
|
if len(test.expected) == 0 {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, p)
|
||||||
|
require.NotNil(t, p.config)
|
||||||
|
} else {
|
||||||
|
require.EqualError(t, err, test.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewDNSProviderConfig(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
endpoint *url.URL
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "success",
|
||||||
|
endpoint: mustParse("http://localhost:8090"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "missing endpoint",
|
||||||
|
expected: "httpreq: the endpoint is missing",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
config := NewDefaultConfig()
|
||||||
|
config.Endpoint = test.endpoint
|
||||||
|
|
||||||
|
p, err := NewDNSProviderConfig(config)
|
||||||
|
|
||||||
|
if len(test.expected) == 0 {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, p)
|
||||||
|
require.NotNil(t, p.config)
|
||||||
|
} else {
|
||||||
|
require.EqualError(t, err, test.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewDNSProvider_Present(t *testing.T) {
|
||||||
|
envTest.RestoreEnv()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
mode string
|
||||||
|
username string
|
||||||
|
password string
|
||||||
|
handler http.HandlerFunc
|
||||||
|
expectedError string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "success",
|
||||||
|
handler: successHandler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "error",
|
||||||
|
handler: http.NotFound,
|
||||||
|
expectedError: "httpreq: 404: request failed: 404 page not found\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "success raw mode",
|
||||||
|
mode: "RAW",
|
||||||
|
handler: successRawModeHandler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "error raw mode",
|
||||||
|
mode: "RAW",
|
||||||
|
handler: http.NotFound,
|
||||||
|
expectedError: "httpreq: 404: request failed: 404 page not found\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "basic auth",
|
||||||
|
username: "bar",
|
||||||
|
password: "foo",
|
||||||
|
handler: func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
username, password, ok := req.BasicAuth()
|
||||||
|
if username != "bar" || password != "foo" || !ok {
|
||||||
|
rw.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, "Please enter your username and password."))
|
||||||
|
http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(rw, "lego")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/present", test.handler)
|
||||||
|
server := httptest.NewServer(mux)
|
||||||
|
|
||||||
|
config := NewDefaultConfig()
|
||||||
|
config.Endpoint = mustParse(server.URL)
|
||||||
|
config.Mode = test.mode
|
||||||
|
config.Username = test.username
|
||||||
|
config.Password = test.password
|
||||||
|
|
||||||
|
p, err := NewDNSProviderConfig(config)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = p.Present("domain", "token", "key")
|
||||||
|
if test.expectedError == "" {
|
||||||
|
require.NoError(t, err)
|
||||||
|
} else {
|
||||||
|
require.EqualError(t, err, test.expectedError)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewDNSProvider_Cleanup(t *testing.T) {
|
||||||
|
envTest.RestoreEnv()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
mode string
|
||||||
|
username string
|
||||||
|
password string
|
||||||
|
handler http.HandlerFunc
|
||||||
|
expectedError string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "success",
|
||||||
|
handler: successHandler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "error",
|
||||||
|
handler: http.NotFound,
|
||||||
|
expectedError: "httpreq: 404: request failed: 404 page not found\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "success raw mode",
|
||||||
|
mode: "RAW",
|
||||||
|
handler: successRawModeHandler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "error raw mode",
|
||||||
|
mode: "RAW",
|
||||||
|
handler: http.NotFound,
|
||||||
|
expectedError: "httpreq: 404: request failed: 404 page not found\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "basic auth",
|
||||||
|
username: "bar",
|
||||||
|
password: "foo",
|
||||||
|
handler: func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
username, password, ok := req.BasicAuth()
|
||||||
|
if username != "bar" || password != "foo" || !ok {
|
||||||
|
rw.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, "Please enter your username and password."))
|
||||||
|
http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprint(rw, "lego")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/cleanup", test.handler)
|
||||||
|
server := httptest.NewServer(mux)
|
||||||
|
|
||||||
|
config := NewDefaultConfig()
|
||||||
|
config.Endpoint = mustParse(server.URL)
|
||||||
|
config.Mode = test.mode
|
||||||
|
config.Username = test.username
|
||||||
|
config.Password = test.password
|
||||||
|
|
||||||
|
p, err := NewDNSProviderConfig(config)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = p.CleanUp("domain", "token", "key")
|
||||||
|
if test.expectedError == "" {
|
||||||
|
require.NoError(t, err)
|
||||||
|
} else {
|
||||||
|
require.EqualError(t, err, test.expectedError)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func successHandler(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
if req.Method != http.MethodPost {
|
||||||
|
http.Error(rw, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := &message{}
|
||||||
|
err := json.NewDecoder(req.Body).Decode(msg)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(rw, "lego")
|
||||||
|
}
|
||||||
|
|
||||||
|
func successRawModeHandler(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
if req.Method != http.MethodPost {
|
||||||
|
http.Error(rw, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := &messageRaw{}
|
||||||
|
err := json.NewDecoder(req.Body).Decode(msg)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(rw, "lego")
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustParse(rawURL string) *url.URL {
|
||||||
|
uri, err := url.Parse(rawURL)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return uri
|
||||||
|
}
|
33
providers/dns/httpreq/readme.md
Normal file
33
providers/dns/httpreq/readme.md
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# HTTP request
|
||||||
|
|
||||||
|
The server must provide:
|
||||||
|
- `POST` `/present`
|
||||||
|
- `POST` `/cleanup`
|
||||||
|
|
||||||
|
The URL of the server must be define by `HTTPREQ_ENDPOINT`.
|
||||||
|
|
||||||
|
## Mode
|
||||||
|
|
||||||
|
There are 2 modes (`HTTPREQ_MODE`):
|
||||||
|
- default mode:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"fqdn": "_acme-challenge.domain.",
|
||||||
|
"value": "LHDhK3oGRvkiefQnx7OOczTY5Tic_xZ6HcMOc_gmtoM"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `RAW`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domain": "domain",
|
||||||
|
"token": "token",
|
||||||
|
"keyAuth": "key"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
Basic authentication (optional) can be set with some environment variables:
|
||||||
|
- `HTTPREQ_USERNAME` and `HTTPREQ_PASSWORD`
|
||||||
|
- both values must be set, otherwise basic authentication is not defined.
|
Loading…
Reference in a new issue