Scert/backend/internal/dnsprovider/aliyun_scope_test.go

195 lines
6.4 KiB
Go

package dnsprovider
import (
"context"
"errors"
"strings"
"testing"
)
func scopeCredentials() map[string]string {
return map[string]string{
"access_key_id": "test-id",
"access_key_secret": "test-secret",
}
}
func TestResolveAliyunTargetDomainUsesOnlyRegistrableRoot(t *testing.T) {
tests := []struct {
name string
want string
}{
{name: "www.sub.example.com", want: "example.com"},
{name: "WWW.EXAMPLE.COM.", want: "example.com"},
{name: "*.example.com", want: "example.com"},
{name: "example.co.uk", want: "example.co.uk"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got, err := ResolveAliyunTargetDomain(test.name)
if err != nil || got != test.want {
t.Fatalf("ResolveAliyunTargetDomain(%q) = %q, %v; want %q", test.name, got, err, test.want)
}
})
}
}
func TestResolveAliyunTargetDomainRejectsProtectedAndInvalidDomains(t *testing.T) {
for _, name := range []string{"pcux.cn", "*.pcux.cn", "api.pcux.cn", "com", "*.com", ""} {
t.Run(name, func(t *testing.T) {
if _, err := ResolveAliyunTargetDomain(name); err == nil {
t.Fatalf("ResolveAliyunTargetDomain(%q) unexpectedly succeeded", name)
}
})
}
}
type fakeAliyunRecords struct {
zones, rrs, values, described, deleted []string
addErr, describeErr, deleteErr error
describeInfo aliyunRecordInfo
canceledCleanup bool
}
func (f *fakeAliyunRecords) Add(_ context.Context, zone, rr, value string) (string, error) {
f.zones = append(f.zones, zone)
f.rrs = append(f.rrs, rr)
f.values = append(f.values, value)
if f.addErr != nil {
return "", f.addErr
}
return "created-record-id", nil
}
func (f *fakeAliyunRecords) Describe(_ context.Context, id string) (aliyunRecordInfo, error) {
f.described = append(f.described, id)
if f.describeErr != nil {
return aliyunRecordInfo{}, f.describeErr
}
if f.describeInfo.RecordID != "" {
return f.describeInfo, nil
}
if len(f.zones) == 0 || len(f.rrs) == 0 || len(f.values) == 0 {
return aliyunRecordInfo{}, errors.New("no temporary record exists")
}
return aliyunRecordInfo{
RecordID: id,
DomainName: f.zones[len(f.zones)-1],
RR: f.rrs[len(f.rrs)-1],
Type: "TXT",
Value: f.values[len(f.values)-1],
}, nil
}
func (f *fakeAliyunRecords) Delete(ctx context.Context, id string) error {
f.deleted = append(f.deleted, id)
f.canceledCleanup = ctx.Err() != nil
return f.deleteErr
}
func TestAliyunProbeUsesTheSingleRegistrableRootWithoutFallback(t *testing.T) {
api := &fakeAliyunRecords{addErr: errors.New("Forbidden.RAM")}
checker := NewAliyunAuthorizationChecker()
constructed := 0
checker.recordAPI = func(map[string]string) (aliyunRecordAPI, error) {
constructed++
return api, nil
}
if _, err := checker.Verify(t.Context(), "www.sub.example.com", scopeCredentials()); err == nil {
t.Fatal("RAM denial unexpectedly succeeded")
}
if constructed != 1 || len(api.zones) != 1 || api.zones[0] != "example.com" {
t.Fatalf("probe did not use only the registrable root: constructed=%d zones=%v", constructed, api.zones)
}
if len(api.deleted) != 0 {
t.Fatalf("failed Add must not guess a record ID to delete: %v", api.deleted)
}
}
func TestAliyunProtectedDomainDoesNotConstructClientOrCallCloud(t *testing.T) {
api := &fakeAliyunRecords{}
checker := NewAliyunAuthorizationChecker()
constructed := 0
checker.recordAPI = func(map[string]string) (aliyunRecordAPI, error) {
constructed++
return api, nil
}
for _, name := range []string{"pcux.cn", "*.pcux.cn", "api.pcux.cn"} {
if _, err := checker.Verify(t.Context(), name, scopeCredentials()); err == nil {
t.Fatalf("protected domain %q unexpectedly succeeded", name)
}
}
if constructed != 0 || len(api.zones) != 0 || len(api.described) != 0 || len(api.deleted) != 0 {
t.Fatalf("protected domain touched cloud state: constructed=%d zones=%v described=%v deleted=%v", constructed, api.zones, api.described, api.deleted)
}
}
func TestAliyunProviderDefersClientCreationAndPinsCleanupIdentity(t *testing.T) {
provider, err := newScopedAliyunProvider(scopeCredentials())
if err != nil {
t.Fatal(err)
}
api := &fakeAliyunRecords{}
constructed := 0
provider.newAPI = func(map[string]string) (aliyunRecordAPI, error) {
constructed++
return api, nil
}
provider.challengeInfo = func(_ context.Context, name, _ string) (string, string, string) {
fqdn := "_acme-challenge." + name + "."
return fqdn, fqdn, "txt-value"
}
if constructed != 0 {
t.Fatal("provider construction must not construct a cloud client")
}
if err := provider.Present(t.Context(), "www.sub.example.com", "token", "key"); err != nil {
t.Fatal(err)
}
if constructed != 1 || len(api.zones) != 1 || api.zones[0] != "example.com" || api.rrs[0] != "_acme-challenge.www.sub" {
t.Fatalf("provider wrote outside its single registrable root: constructed=%d zones=%v rrs=%v", constructed, api.zones, api.rrs)
}
if err := provider.Present(t.Context(), "www.sub.example.com", "token", "key"); err == nil {
t.Fatal("duplicate challenge unexpectedly overwrote a pending record")
}
if err := provider.CleanUp(t.Context(), "www.sub.example.com", "other-token", "key"); err != nil {
t.Fatal(err)
}
if len(api.deleted) != 0 {
t.Fatalf("cleanup for a different challenge deleted a record: %v", api.deleted)
}
ctx, cancel := context.WithCancel(t.Context())
cancel()
if err := provider.CleanUp(ctx, "www.sub.example.com", "token", "key"); err != nil {
t.Fatal(err)
}
if len(api.deleted) != 1 || api.deleted[0] != "created-record-id" || api.canceledCleanup {
t.Fatalf("cleanup did not use the exact created record ID: deleted=%v canceled=%v", api.deleted, api.canceledCleanup)
}
}
func TestAliyunProviderRejectsCNAMEBeforeClientConstruction(t *testing.T) {
provider, err := newScopedAliyunProvider(scopeCredentials())
if err != nil {
t.Fatal(err)
}
constructed := 0
provider.newAPI = func(map[string]string) (aliyunRecordAPI, error) {
constructed++
return &fakeAliyunRecords{}, nil
}
provider.challengeInfo = func(context.Context, string, string) (string, string, string) {
return "_acme-challenge.www.sub.example.com.", "_acme-challenge.delegated.example.net.", "txt-value"
}
if err := provider.Present(t.Context(), "www.sub.example.com", "token", "key"); err == nil || !strings.Contains(err.Error(), "CNAME") {
t.Fatalf("CNAME redirection was not rejected: %v", err)
}
if constructed != 0 {
t.Fatalf("CNAME redirection constructed a cloud client: %d", constructed)
}
}