From 6d8f122a5160f6d9e4c51579f2429dfaa62c7271 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Fri, 16 Feb 2018 06:47:51 -0800 Subject: Upgrading server dependancies (#8308) --- .../lego/providers/dns/rackspace/rackspace.go | 284 --------------------- .../lego/providers/dns/rackspace/rackspace_test.go | 220 ---------------- 2 files changed, 504 deletions(-) delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace.go delete mode 100644 vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace_test.go (limited to 'vendor/github.com/xenolf/lego/providers/dns/rackspace') diff --git a/vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace.go b/vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace.go deleted file mode 100644 index 13daa8c8a..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace.go +++ /dev/null @@ -1,284 +0,0 @@ -// Package rackspace implements a DNS provider for solving the DNS-01 -// challenge using rackspace DNS. -package rackspace - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "os" - "time" - - "github.com/xenolf/lego/acme" -) - -// rackspaceAPIURL represents the Identity API endpoint to call -var rackspaceAPIURL = "https://identity.api.rackspacecloud.com/v2.0/tokens" - -// DNSProvider is an implementation of the acme.ChallengeProvider interface -// used to store the reusable token and DNS API endpoint -type DNSProvider struct { - token string - cloudDNSEndpoint string -} - -// NewDNSProvider returns a DNSProvider instance configured for Rackspace. -// Credentials must be passed in the environment variables: RACKSPACE_USER -// and RACKSPACE_API_KEY. -func NewDNSProvider() (*DNSProvider, error) { - user := os.Getenv("RACKSPACE_USER") - key := os.Getenv("RACKSPACE_API_KEY") - return NewDNSProviderCredentials(user, key) -} - -// NewDNSProviderCredentials uses the supplied credentials to return a -// DNSProvider instance configured for Rackspace. It authenticates against -// the API, also grabbing the DNS Endpoint. -func NewDNSProviderCredentials(user, key string) (*DNSProvider, error) { - if user == "" || key == "" { - return nil, fmt.Errorf("Rackspace credentials missing") - } - - type APIKeyCredentials struct { - Username string `json:"username"` - APIKey string `json:"apiKey"` - } - - type Auth struct { - APIKeyCredentials `json:"RAX-KSKEY:apiKeyCredentials"` - } - - type RackspaceAuthData struct { - Auth `json:"auth"` - } - - type RackspaceIdentity 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"` - } - - authData := RackspaceAuthData{ - Auth: Auth{ - APIKeyCredentials: APIKeyCredentials{ - Username: user, - APIKey: key, - }, - }, - } - - body, err := json.Marshal(authData) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", rackspaceAPIURL, 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 := client.Do(req) - if err != nil { - return nil, fmt.Errorf("Error querying Rackspace 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 rackspaceIdentity RackspaceIdentity - err = json.NewDecoder(resp.Body).Decode(&rackspaceIdentity) - if err != nil { - return nil, err - } - - // Iterate through the Service Catalog to get the DNS Endpoint - var dnsEndpoint string - for _, service := range rackspaceIdentity.Access.ServiceCatalog { - if service.Name == "cloudDNS" { - dnsEndpoint = service.Endpoints[0].PublicURL - break - } - } - if dnsEndpoint == "" { - return nil, fmt.Errorf("Failed to populate DNS endpoint, check Rackspace API for changes.") - } - - return &DNSProvider{ - token: rackspaceIdentity.Access.Token.ID, - cloudDNSEndpoint: dnsEndpoint, - }, nil -} - -// Present creates a TXT record to fulfil the dns-01 challenge -func (c *DNSProvider) Present(domain, token, keyAuth string) error { - fqdn, value, _ := acme.DNS01Record(domain, keyAuth) - zoneID, err := c.getHostedZoneID(fqdn) - if err != nil { - return err - } - - rec := RackspaceRecords{ - RackspaceRecord: []RackspaceRecord{{ - Name: acme.UnFqdn(fqdn), - Type: "TXT", - Data: value, - TTL: 300, - }}, - } - - body, err := json.Marshal(rec) - if err != nil { - return err - } - - _, err = c.makeRequest("POST", fmt.Sprintf("/domains/%d/records", zoneID), bytes.NewReader(body)) - if err != nil { - return err - } - - return nil -} - -// CleanUp removes the TXT record matching the specified parameters -func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - zoneID, err := c.getHostedZoneID(fqdn) - if err != nil { - return err - } - - record, err := c.findTxtRecord(fqdn, zoneID) - if err != nil { - return err - } - - _, err = c.makeRequest("DELETE", fmt.Sprintf("/domains/%d/records?id=%s", zoneID, record.ID), nil) - if err != nil { - return err - } - - return nil -} - -// getHostedZoneID performs a lookup to get the DNS zone which needs -// modifying for a given FQDN -func (c *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 - } - - result, err := c.makeRequest("GET", fmt.Sprintf("/domains?name=%s", acme.UnFqdn(authZone)), nil) - if err != nil { - return 0, err - } - - var zoneSearchResponse ZoneSearchResponse - err = json.Unmarshal(result, &zoneSearchResponse) - if err != nil { - return 0, err - } - - // If nothing was returned, or for whatever reason more than 1 was returned (the search uses exact match, so should not occur) - if zoneSearchResponse.TotalEntries != 1 { - return 0, fmt.Errorf("Found %d zones for %s in Rackspace for domain %s", zoneSearchResponse.TotalEntries, authZone, fqdn) - } - - return zoneSearchResponse.HostedZones[0].ID, nil -} - -// findTxtRecord searches a DNS zone for a TXT record with a specific name -func (c *DNSProvider) findTxtRecord(fqdn string, zoneID int) (*RackspaceRecord, error) { - result, err := c.makeRequest("GET", fmt.Sprintf("/domains/%d/records?type=TXT&name=%s", zoneID, acme.UnFqdn(fqdn)), nil) - if err != nil { - return nil, err - } - - var records RackspaceRecords - err = json.Unmarshal(result, &records) - if err != nil { - return nil, err - } - - recordsLength := len(records.RackspaceRecord) - switch recordsLength { - case 1: - break - case 0: - return nil, fmt.Errorf("No TXT record found for %s", fqdn) - default: - return nil, fmt.Errorf("More than 1 TXT record found for %s", fqdn) - } - - return &records.RackspaceRecord[0], nil -} - -// makeRequest is a wrapper function used for making DNS API requests -func (c *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawMessage, error) { - url := c.cloudDNSEndpoint + uri - req, err := http.NewRequest(method, url, body) - if err != nil { - return nil, err - } - - req.Header.Set("X-Auth-Token", c.token) - req.Header.Set("Content-Type", "application/json") - - client := http.Client{Timeout: 30 * time.Second} - resp, err := client.Do(req) - if err != nil { - return nil, fmt.Errorf("Error querying DNS API: %v", err) - } - - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted { - return nil, fmt.Errorf("Request failed for %s %s. Response code: %d", method, url, resp.StatusCode) - } - - var r json.RawMessage - err = json.NewDecoder(resp.Body).Decode(&r) - if err != nil { - return nil, fmt.Errorf("JSON decode failed for %s %s. Response code: %d", method, url, resp.StatusCode) - } - - return r, nil -} - -// RackspaceRecords is the list of records sent/received from the DNS API -type RackspaceRecords struct { - RackspaceRecord []RackspaceRecord `json:"records"` -} - -// RackspaceRecord represents a Rackspace DNS record -type RackspaceRecord struct { - Name string `json:"name"` - Type string `json:"type"` - Data string `json:"data"` - TTL int `json:"ttl,omitempty"` - ID string `json:"id,omitempty"` -} diff --git a/vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace_test.go b/vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace_test.go deleted file mode 100644 index 22c979cad..000000000 --- a/vendor/github.com/xenolf/lego/providers/dns/rackspace/rackspace_test.go +++ /dev/null @@ -1,220 +0,0 @@ -package rackspace - -import ( - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var ( - rackspaceLiveTest bool - rackspaceUser string - rackspaceAPIKey string - rackspaceDomain string - testAPIURL string -) - -func init() { - rackspaceUser = os.Getenv("RACKSPACE_USER") - rackspaceAPIKey = os.Getenv("RACKSPACE_API_KEY") - rackspaceDomain = os.Getenv("RACKSPACE_DOMAIN") - if len(rackspaceUser) > 0 && len(rackspaceAPIKey) > 0 && len(rackspaceDomain) > 0 { - rackspaceLiveTest = true - } -} - -func testRackspaceEnv() { - rackspaceAPIURL = testAPIURL - os.Setenv("RACKSPACE_USER", "testUser") - os.Setenv("RACKSPACE_API_KEY", "testKey") -} - -func liveRackspaceEnv() { - rackspaceAPIURL = "https://identity.api.rackspacecloud.com/v2.0/tokens" - os.Setenv("RACKSPACE_USER", rackspaceUser) - os.Setenv("RACKSPACE_API_KEY", rackspaceAPIKey) -} - -func startTestServers() (identityAPI, dnsAPI *httptest.Server) { - dnsAPI = httptest.NewServer(dnsMux()) - dnsEndpoint := dnsAPI.URL + "/123456" - - identityAPI = httptest.NewServer(identityHandler(dnsEndpoint)) - testAPIURL = identityAPI.URL + "/" - return -} - -func closeTestServers(identityAPI, dnsAPI *httptest.Server) { - identityAPI.Close() - dnsAPI.Close() -} - -func identityHandler(dnsEndpoint string) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - reqBody, err := ioutil.ReadAll(r.Body) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - resp, found := jsonMap[string(reqBody)] - if !found { - w.WriteHeader(http.StatusBadRequest) - return - } - resp = strings.Replace(resp, "https://dns.api.rackspacecloud.com/v1.0/123456", dnsEndpoint, 1) - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, resp) - }) -} - -func dnsMux() *http.ServeMux { - 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) - fmt.Fprintf(w, jsonMap["zoneDetails"]) - return - } - w.WriteHeader(http.StatusBadRequest) - return - }) - - 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: - reqBody, err := ioutil.ReadAll(r.Body) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - resp, found := jsonMap[string(reqBody)] - if !found { - w.WriteHeader(http.StatusBadRequest) - return - } - w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, resp) - // Used by `findTxtRecord()` finding `record.ID` "?type=TXT&name=_acme-challenge.example.com" - case http.MethodGet: - if r.URL.Query().Get("type") == "TXT" && r.URL.Query().Get("name") == "_acme-challenge.example.com" { - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, jsonMap["recordDetails"]) - return - } - w.WriteHeader(http.StatusBadRequest) - return - // Used by `CleanUp()` deleting the TXT record "?id=445566" - case http.MethodDelete: - if r.URL.Query().Get("id") == "TXT-654321" { - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, jsonMap["recordDelete"]) - 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 -} - -func TestNewDNSProviderMissingCredErr(t *testing.T) { - testRackspaceEnv() - _, err := NewDNSProviderCredentials("", "") - assert.EqualError(t, err, "Rackspace credentials missing") -} - -func TestOfflineRackspaceValid(t *testing.T) { - testRackspaceEnv() - provider, err := NewDNSProviderCredentials(os.Getenv("RACKSPACE_USER"), os.Getenv("RACKSPACE_API_KEY")) - - assert.NoError(t, err) - assert.Equal(t, provider.token, "testToken", "The token should match") -} - -func TestOfflineRackspacePresent(t *testing.T) { - testRackspaceEnv() - provider, err := NewDNSProvider() - - if assert.NoError(t, err) { - err = provider.Present("example.com", "token", "keyAuth") - assert.NoError(t, err) - } -} - -func TestOfflineRackspaceCleanUp(t *testing.T) { - testRackspaceEnv() - provider, err := NewDNSProvider() - - if assert.NoError(t, err) { - err = provider.CleanUp("example.com", "token", "keyAuth") - assert.NoError(t, err) - } -} - -func TestNewDNSProviderValidEnv(t *testing.T) { - if !rackspaceLiveTest { - t.Skip("skipping live test") - } - - liveRackspaceEnv() - provider, err := NewDNSProvider() - assert.NoError(t, err) - assert.Contains(t, provider.cloudDNSEndpoint, "https://dns.api.rackspacecloud.com/v1.0/", "The endpoint URL should contain the base") -} - -func TestRackspacePresent(t *testing.T) { - if !rackspaceLiveTest { - t.Skip("skipping live test") - } - - liveRackspaceEnv() - provider, err := NewDNSProvider() - assert.NoError(t, err) - - err = provider.Present(rackspaceDomain, "", "112233445566==") - assert.NoError(t, err) -} - -func TestRackspaceCleanUp(t *testing.T) { - if !rackspaceLiveTest { - t.Skip("skipping live test") - } - - time.Sleep(time.Second * 15) - - liveRackspaceEnv() - provider, err := NewDNSProvider() - assert.NoError(t, err) - - err = provider.CleanUp(rackspaceDomain, "", "112233445566==") - assert.NoError(t, err) -} - -func TestMain(m *testing.M) { - identityAPI, dnsAPI := startTestServers() - defer closeTestServers(identityAPI, dnsAPI) - os.Exit(m.Run()) -} - -var jsonMap = map[string]string{ - `{"auth":{"RAX-KSKEY:apiKeyCredentials":{"username":"testUser","apiKey":"testKey"}}}`: `{"access":{"token":{"id":"testToken","expires":"1970-01-01T00:00:00.000Z","tenant":{"id":"123456","name":"123456"},"RAX-AUTH:authenticatedBy":["APIKEY"]},"serviceCatalog":[{"type":"rax:dns","endpoints":[{"publicURL":"https://dns.api.rackspacecloud.com/v1.0/123456","tenantId":"123456"}],"name":"cloudDNS"}],"user":{"id":"fakeUseID","name":"testUser"}}}`, - "zoneDetails": `{"domains":[{"name":"example.com","id":112233,"emailAddress":"hostmaster@example.com","updated":"1970-01-01T00:00:00.000+0000","created":"1970-01-01T00:00:00.000+0000"}],"totalEntries":1}`, - `{"records":[{"name":"_acme-challenge.example.com","type":"TXT","data":"pW9ZKG0xz_PCriK-nCMOjADy9eJcgGWIzkkj2fN4uZM","ttl":300}]}`: `{"request":"{\"records\":[{\"name\":\"_acme-challenge.example.com\",\"type\":\"TXT\",\"data\":\"pW9ZKG0xz_PCriK-nCMOjADy9eJcgGWIzkkj2fN4uZM\",\"ttl\":300}]}","status":"RUNNING","verb":"POST","jobId":"00000000-0000-0000-0000-0000000000","callbackUrl":"https://dns.api.rackspacecloud.com/v1.0/123456/status/00000000-0000-0000-0000-0000000000","requestUrl":"https://dns.api.rackspacecloud.com/v1.0/123456/domains/112233/records"}`, - "recordDetails": `{"records":[{"name":"_acme-challenge.example.com","id":"TXT-654321","type":"TXT","data":"pW9ZKG0xz_PCriK-nCMOjADy9eJcgGWIzkkj2fN4uZM","ttl":300,"updated":"1970-01-01T00:00:00.000+0000","created":"1970-01-01T00:00:00.000+0000"}]}`, - "recordDelete": `{"status":"RUNNING","verb":"DELETE","jobId":"00000000-0000-0000-0000-0000000000","callbackUrl":"https://dns.api.rackspacecloud.com/v1.0/123456/status/00000000-0000-0000-0000-0000000000","requestUrl":"https://dns.api.rackspacecloud.com/v1.0/123456/domains/112233/recordsid=TXT-654321"}`, -} -- cgit v1.2.3-1-g7c22