summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/xenolf/lego/providers/dns/auroradns
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/xenolf/lego/providers/dns/auroradns')
-rw-r--r--vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns.go141
-rw-r--r--vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns_test.go148
2 files changed, 289 insertions, 0 deletions
diff --git a/vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns.go b/vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns.go
new file mode 100644
index 000000000..55b48f9b4
--- /dev/null
+++ b/vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns.go
@@ -0,0 +1,141 @@
+package auroradns
+
+import (
+ "fmt"
+ "github.com/edeckers/auroradnsclient"
+ "github.com/edeckers/auroradnsclient/records"
+ "github.com/edeckers/auroradnsclient/zones"
+ "github.com/xenolf/lego/acme"
+ "os"
+ "sync"
+)
+
+// DNSProvider describes a provider for AuroraDNS
+type DNSProvider struct {
+ recordIDs map[string]string
+ recordIDsMu sync.Mutex
+ client *auroradnsclient.AuroraDNSClient
+}
+
+// NewDNSProvider returns a DNSProvider instance configured for AuroraDNS.
+// Credentials must be passed in the environment variables: AURORA_USER_ID
+// and AURORA_KEY.
+func NewDNSProvider() (*DNSProvider, error) {
+ userID := os.Getenv("AURORA_USER_ID")
+ key := os.Getenv("AURORA_KEY")
+
+ endpoint := os.Getenv("AURORA_ENDPOINT")
+ if endpoint == "" {
+ endpoint = "https://api.auroradns.eu"
+ }
+
+ return NewDNSProviderCredentials(endpoint, userID, key)
+}
+
+// NewDNSProviderCredentials uses the supplied credentials to return a
+// DNSProvider instance configured for AuroraDNS.
+func NewDNSProviderCredentials(baseURL string, userID string, key string) (*DNSProvider, error) {
+ client, err := auroradnsclient.NewAuroraDNSClient(baseURL, userID, key)
+ if err != nil {
+ return nil, err
+ }
+
+ return &DNSProvider{
+ client: client,
+ recordIDs: make(map[string]string),
+ }, nil
+}
+
+func (provider *DNSProvider) getZoneInformationByName(name string) (zones.ZoneRecord, error) {
+ zs, err := provider.client.GetZones()
+
+ if err != nil {
+ return zones.ZoneRecord{}, err
+ }
+
+ for _, element := range zs {
+ if element.Name == name {
+ return element, nil
+ }
+ }
+
+ return zones.ZoneRecord{}, fmt.Errorf("Could not find Zone record")
+}
+
+// Present creates a record with a secret
+func (provider *DNSProvider) Present(domain, token, keyAuth string) error {
+ fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
+
+ authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameservers)
+ if err != nil {
+ return fmt.Errorf("Could not determine zone for domain: '%s'. %s", domain, err)
+ }
+
+ // 1. Aurora will happily create the TXT record when it is provided a fqdn,
+ // but it will only appear in the control panel and will not be
+ // propagated to DNS servers. Extract and use subdomain instead.
+ // 2. A trailing dot in the fqdn will cause Aurora to add a trailing dot to
+ // the subdomain, resulting in _acme-challenge..<domain> rather
+ // than _acme-challenge.<domain>
+
+ subdomain := fqdn[0 : len(fqdn)-len(authZone)-1]
+
+ authZone = acme.UnFqdn(authZone)
+
+ zoneRecord, err := provider.getZoneInformationByName(authZone)
+
+ reqData :=
+ records.CreateRecordRequest{
+ RecordType: "TXT",
+ Name: subdomain,
+ Content: value,
+ TTL: 300,
+ }
+
+ respData, err := provider.client.CreateRecord(zoneRecord.ID, reqData)
+ if err != nil {
+ return fmt.Errorf("Could not create record: '%s'.", err)
+ }
+
+ provider.recordIDsMu.Lock()
+ provider.recordIDs[fqdn] = respData.ID
+ provider.recordIDsMu.Unlock()
+
+ return nil
+}
+
+// CleanUp removes a given record that was generated by Present
+func (provider *DNSProvider) CleanUp(domain, token, keyAuth string) error {
+ fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
+
+ provider.recordIDsMu.Lock()
+ recordID, ok := provider.recordIDs[fqdn]
+ provider.recordIDsMu.Unlock()
+
+ if !ok {
+ return fmt.Errorf("Unknown recordID for '%s'", fqdn)
+ }
+
+ authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameservers)
+ if err != nil {
+ return fmt.Errorf("Could not determine zone for domain: '%s'. %s", domain, err)
+ }
+
+ authZone = acme.UnFqdn(authZone)
+
+ zoneRecord, err := provider.getZoneInformationByName(authZone)
+ if err != nil {
+ return err
+ }
+
+ _, err = provider.client.RemoveRecord(zoneRecord.ID, recordID)
+ if err != nil {
+ return err
+ }
+
+ provider.recordIDsMu.Lock()
+ delete(provider.recordIDs, fqdn)
+ provider.recordIDsMu.Unlock()
+
+ return nil
+}
diff --git a/vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns_test.go b/vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns_test.go
new file mode 100644
index 000000000..f4df7fa61
--- /dev/null
+++ b/vendor/github.com/xenolf/lego/providers/dns/auroradns/auroradns_test.go
@@ -0,0 +1,148 @@
+package auroradns
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+)
+
+var fakeAuroraDNSUserId = "asdf1234"
+var fakeAuroraDNSKey = "key"
+
+func TestAuroraDNSPresent(t *testing.T) {
+ var requestReceived bool
+
+ mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "GET" && r.URL.Path == "/zones" {
+ w.WriteHeader(http.StatusCreated)
+ fmt.Fprintf(w, `[{
+ "id": "c56a4180-65aa-42ec-a945-5fd21dec0538",
+ "name": "example.com"
+ }]`)
+ return
+ }
+
+ requestReceived = true
+
+ if got, want := r.Method, "POST"; got != want {
+ t.Errorf("Expected method to be '%s' but got '%s'", want, got)
+ }
+
+ if got, want := r.URL.Path, "/zones/c56a4180-65aa-42ec-a945-5fd21dec0538/records"; got != want {
+ t.Errorf("Expected path to be '%s' but got '%s'", want, got)
+ }
+
+ if got, want := r.Header.Get("Content-Type"), "application/json"; got != want {
+ t.Errorf("Expected Content-Type to be '%s' but got '%s'", want, got)
+ }
+
+ reqBody, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ t.Fatalf("Error reading request body: %v", err)
+ }
+
+ if got, want := string(reqBody),
+ `{"type":"TXT","name":"_acme-challenge","content":"w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI","ttl":300}`; got != want {
+
+ t.Errorf("Expected body data to be: `%s` but got `%s`", want, got)
+ }
+
+ w.WriteHeader(http.StatusCreated)
+ fmt.Fprintf(w, `{
+ "id": "c56a4180-65aa-42ec-a945-5fd21dec0538",
+ "type": "TXT",
+ "name": "_acme-challenge",
+ "ttl": 300
+ }`)
+ }))
+
+ defer mock.Close()
+
+ auroraProvider, err := NewDNSProviderCredentials(mock.URL, fakeAuroraDNSUserId, fakeAuroraDNSKey)
+ if auroraProvider == nil {
+ t.Fatal("Expected non-nil AuroraDNS provider, but was nil")
+ }
+
+ if err != nil {
+ t.Fatalf("Expected no error creating provider, but got: %v", err)
+ }
+
+ err = auroraProvider.Present("example.com", "", "foobar")
+ if err != nil {
+ t.Fatalf("Expected no error creating TXT record, but got: %v", err)
+ }
+
+ if !requestReceived {
+ t.Error("Expected request to be received by mock backend, but it wasn't")
+ }
+}
+
+func TestAuroraDNSCleanUp(t *testing.T) {
+ var requestReceived bool
+
+ mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "GET" && r.URL.Path == "/zones" {
+ w.WriteHeader(http.StatusCreated)
+ fmt.Fprintf(w, `[{
+ "id": "c56a4180-65aa-42ec-a945-5fd21dec0538",
+ "name": "example.com"
+ }]`)
+ return
+ }
+
+ if r.Method == "POST" && r.URL.Path == "/zones/c56a4180-65aa-42ec-a945-5fd21dec0538/records" {
+ w.WriteHeader(http.StatusCreated)
+ fmt.Fprintf(w, `{
+ "id": "ec56a4180-65aa-42ec-a945-5fd21dec0538",
+ "type": "TXT",
+ "name": "_acme-challenge",
+ "ttl": 300
+ }`)
+ return
+ }
+
+ requestReceived = true
+
+ if got, want := r.Method, "DELETE"; got != want {
+ t.Errorf("Expected method to be '%s' but got '%s'", want, got)
+ }
+
+ if got, want := r.URL.Path,
+ "/zones/c56a4180-65aa-42ec-a945-5fd21dec0538/records/ec56a4180-65aa-42ec-a945-5fd21dec0538"; got != want {
+ t.Errorf("Expected path to be '%s' but got '%s'", want, got)
+ }
+
+ if got, want := r.Header.Get("Content-Type"), "application/json"; got != want {
+ t.Errorf("Expected Content-Type to be '%s' but got '%s'", want, got)
+ }
+
+ w.WriteHeader(http.StatusCreated)
+ fmt.Fprintf(w, `{}`)
+ }))
+ defer mock.Close()
+
+ auroraProvider, err := NewDNSProviderCredentials(mock.URL, fakeAuroraDNSUserId, fakeAuroraDNSKey)
+ if auroraProvider == nil {
+ t.Fatal("Expected non-nil AuroraDNS provider, but was nil")
+ }
+
+ if err != nil {
+ t.Fatalf("Expected no error creating provider, but got: %v", err)
+ }
+
+ err = auroraProvider.Present("example.com", "", "foobar")
+ if err != nil {
+ t.Fatalf("Expected no error creating TXT record, but got: %v", err)
+ }
+
+ err = auroraProvider.CleanUp("example.com", "", "foobar")
+ if err != nil {
+ t.Fatalf("Expected no error removing TXT record, but got: %v", err)
+ }
+
+ if !requestReceived {
+ t.Error("Expected request to be received by mock backend, but it wasn't")
+ }
+}