forked from TrueCloudLab/certificates
Merge pull request #1136 from smallstep/herman/ignore-empty-acme-meta
This commit is contained in:
commit
c169defc73
6 changed files with 176 additions and 8 deletions
|
@ -205,7 +205,7 @@ type Directory struct {
|
||||||
NewOrder string `json:"newOrder"`
|
NewOrder string `json:"newOrder"`
|
||||||
RevokeCert string `json:"revokeCert"`
|
RevokeCert string `json:"revokeCert"`
|
||||||
KeyChange string `json:"keyChange"`
|
KeyChange string `json:"keyChange"`
|
||||||
Meta Meta `json:"meta"`
|
Meta *Meta `json:"meta,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToLog enables response logging for the Directory type.
|
// ToLog enables response logging for the Directory type.
|
||||||
|
@ -228,18 +228,49 @@ func GetDirectory(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
linker := acme.MustLinkerFromContext(ctx)
|
linker := acme.MustLinkerFromContext(ctx)
|
||||||
|
|
||||||
render.JSON(w, &Directory{
|
render.JSON(w, &Directory{
|
||||||
NewNonce: linker.GetLink(ctx, acme.NewNonceLinkType),
|
NewNonce: linker.GetLink(ctx, acme.NewNonceLinkType),
|
||||||
NewAccount: linker.GetLink(ctx, acme.NewAccountLinkType),
|
NewAccount: linker.GetLink(ctx, acme.NewAccountLinkType),
|
||||||
NewOrder: linker.GetLink(ctx, acme.NewOrderLinkType),
|
NewOrder: linker.GetLink(ctx, acme.NewOrderLinkType),
|
||||||
RevokeCert: linker.GetLink(ctx, acme.RevokeCertLinkType),
|
RevokeCert: linker.GetLink(ctx, acme.RevokeCertLinkType),
|
||||||
KeyChange: linker.GetLink(ctx, acme.KeyChangeLinkType),
|
KeyChange: linker.GetLink(ctx, acme.KeyChangeLinkType),
|
||||||
Meta: Meta{
|
Meta: createMetaObject(acmeProv),
|
||||||
ExternalAccountRequired: acmeProv.RequireEAB,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createMetaObject creates a Meta object if the ACME provisioner
|
||||||
|
// has one or more properties that are written in the ACME directory output.
|
||||||
|
// It returns nil if none of the properties are set.
|
||||||
|
func createMetaObject(p *provisioner.ACME) *Meta {
|
||||||
|
if shouldAddMetaObject(p) {
|
||||||
|
return &Meta{
|
||||||
|
TermsOfService: p.TermsOfService,
|
||||||
|
Website: p.Website,
|
||||||
|
CaaIdentities: p.CaaIdentities,
|
||||||
|
ExternalAccountRequired: p.RequireEAB,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// shouldAddMetaObject returns whether or not the ACME provisioner
|
||||||
|
// has properties configured that must be added to the ACME directory object.
|
||||||
|
func shouldAddMetaObject(p *provisioner.ACME) bool {
|
||||||
|
switch {
|
||||||
|
case p.TermsOfService != "":
|
||||||
|
return true
|
||||||
|
case p.Website != "":
|
||||||
|
return true
|
||||||
|
case len(p.CaaIdentities) > 0:
|
||||||
|
return true
|
||||||
|
case p.RequireEAB:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NotImplemented returns a 501 and is generally a placeholder for functionality which
|
// NotImplemented returns a 501 and is generally a placeholder for functionality which
|
||||||
// MAY be added at some point in the future but is not in any way a guarantee of such.
|
// MAY be added at some point in the future but is not in any way a guarantee of such.
|
||||||
func NotImplemented(w http.ResponseWriter, r *http.Request) {
|
func NotImplemented(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -18,10 +18,13 @@ import (
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/smallstep/assert"
|
|
||||||
"github.com/smallstep/certificates/acme"
|
|
||||||
"go.step.sm/crypto/jose"
|
"go.step.sm/crypto/jose"
|
||||||
"go.step.sm/crypto/pemutil"
|
"go.step.sm/crypto/pemutil"
|
||||||
|
|
||||||
|
"github.com/smallstep/assert"
|
||||||
|
"github.com/smallstep/certificates/acme"
|
||||||
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockClient struct {
|
type mockClient struct {
|
||||||
|
@ -129,7 +132,35 @@ func TestHandler_GetDirectory(t *testing.T) {
|
||||||
NewOrder: fmt.Sprintf("%s/acme/%s/new-order", baseURL.String(), provName),
|
NewOrder: fmt.Sprintf("%s/acme/%s/new-order", baseURL.String(), provName),
|
||||||
RevokeCert: fmt.Sprintf("%s/acme/%s/revoke-cert", baseURL.String(), provName),
|
RevokeCert: fmt.Sprintf("%s/acme/%s/revoke-cert", baseURL.String(), provName),
|
||||||
KeyChange: fmt.Sprintf("%s/acme/%s/key-change", baseURL.String(), provName),
|
KeyChange: fmt.Sprintf("%s/acme/%s/key-change", baseURL.String(), provName),
|
||||||
Meta: Meta{
|
Meta: &Meta{
|
||||||
|
ExternalAccountRequired: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return test{
|
||||||
|
ctx: ctx,
|
||||||
|
dir: expDir,
|
||||||
|
statusCode: 200,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ok/full-meta": func(t *testing.T) test {
|
||||||
|
prov := newACMEProv(t)
|
||||||
|
prov.TermsOfService = "https://terms.ca.local/"
|
||||||
|
prov.Website = "https://ca.local/"
|
||||||
|
prov.CaaIdentities = []string{"ca.local"}
|
||||||
|
prov.RequireEAB = true
|
||||||
|
provName := url.PathEscape(prov.GetName())
|
||||||
|
baseURL := &url.URL{Scheme: "https", Host: "test.ca.smallstep.com"}
|
||||||
|
ctx := acme.NewProvisionerContext(context.Background(), prov)
|
||||||
|
expDir := Directory{
|
||||||
|
NewNonce: fmt.Sprintf("%s/acme/%s/new-nonce", baseURL.String(), provName),
|
||||||
|
NewAccount: fmt.Sprintf("%s/acme/%s/new-account", baseURL.String(), provName),
|
||||||
|
NewOrder: fmt.Sprintf("%s/acme/%s/new-order", baseURL.String(), provName),
|
||||||
|
RevokeCert: fmt.Sprintf("%s/acme/%s/revoke-cert", baseURL.String(), provName),
|
||||||
|
KeyChange: fmt.Sprintf("%s/acme/%s/key-change", baseURL.String(), provName),
|
||||||
|
Meta: &Meta{
|
||||||
|
TermsOfService: "https://terms.ca.local/",
|
||||||
|
Website: "https://ca.local/",
|
||||||
|
CaaIdentities: []string{"ca.local"},
|
||||||
ExternalAccountRequired: true,
|
ExternalAccountRequired: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -751,3 +782,89 @@ func TestHandler_GetChallenge(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_createMetaObject(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
p *provisioner.ACME
|
||||||
|
want *Meta
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no-meta",
|
||||||
|
p: &provisioner.ACME{
|
||||||
|
Type: "ACME",
|
||||||
|
Name: "acme",
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "terms-of-service",
|
||||||
|
p: &provisioner.ACME{
|
||||||
|
Type: "ACME",
|
||||||
|
Name: "acme",
|
||||||
|
TermsOfService: "https://terms.ca.local",
|
||||||
|
},
|
||||||
|
want: &Meta{
|
||||||
|
TermsOfService: "https://terms.ca.local",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "website",
|
||||||
|
p: &provisioner.ACME{
|
||||||
|
Type: "ACME",
|
||||||
|
Name: "acme",
|
||||||
|
Website: "https://ca.local",
|
||||||
|
},
|
||||||
|
want: &Meta{
|
||||||
|
Website: "https://ca.local",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "caa",
|
||||||
|
p: &provisioner.ACME{
|
||||||
|
Type: "ACME",
|
||||||
|
Name: "acme",
|
||||||
|
CaaIdentities: []string{"ca.local", "ca.remote"},
|
||||||
|
},
|
||||||
|
want: &Meta{
|
||||||
|
CaaIdentities: []string{"ca.local", "ca.remote"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "require-eab",
|
||||||
|
p: &provisioner.ACME{
|
||||||
|
Type: "ACME",
|
||||||
|
Name: "acme",
|
||||||
|
RequireEAB: true,
|
||||||
|
},
|
||||||
|
want: &Meta{
|
||||||
|
ExternalAccountRequired: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "full-meta",
|
||||||
|
p: &provisioner.ACME{
|
||||||
|
Type: "ACME",
|
||||||
|
Name: "acme",
|
||||||
|
TermsOfService: "https://terms.ca.local",
|
||||||
|
Website: "https://ca.local",
|
||||||
|
CaaIdentities: []string{"ca.local", "ca.remote"},
|
||||||
|
RequireEAB: true,
|
||||||
|
},
|
||||||
|
want: &Meta{
|
||||||
|
TermsOfService: "https://terms.ca.local",
|
||||||
|
Website: "https://ca.local",
|
||||||
|
CaaIdentities: []string{"ca.local", "ca.remote"},
|
||||||
|
ExternalAccountRequired: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := createMetaObject(tt.p)
|
||||||
|
if !cmp.Equal(tt.want, got) {
|
||||||
|
t.Errorf("createMetaObject() diff =\n%s", cmp.Diff(tt.want, got))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -84,6 +84,17 @@ type ACME struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ForceCN bool `json:"forceCN,omitempty"`
|
ForceCN bool `json:"forceCN,omitempty"`
|
||||||
|
// TermsOfService contains a URL pointing to the ACME server's
|
||||||
|
// terms of service. Defaults to empty.
|
||||||
|
TermsOfService string `json:"termsOfService,omitempty"`
|
||||||
|
// Website contains an URL pointing to more information about
|
||||||
|
// the ACME server. Defaults to empty.
|
||||||
|
Website string `json:"website,omitempty"`
|
||||||
|
// CaaIdentities is an array of hostnames that the ACME server
|
||||||
|
// identifies itself with. These hostnames can be used by ACME
|
||||||
|
// clients to determine the correct issuer domain name to use
|
||||||
|
// when configuring CAA records. Defaults to empty array.
|
||||||
|
CaaIdentities []string `json:"caaIdentities,omitempty"`
|
||||||
// RequireEAB makes the provisioner require ACME EAB to be provided
|
// RequireEAB makes the provisioner require ACME EAB to be provided
|
||||||
// by clients when creating a new Account. If set to true, the provided
|
// by clients when creating a new Account. If set to true, the provided
|
||||||
// EAB will be verified. If set to false and an EAB is provided, it is
|
// EAB will be verified. If set to false and an EAB is provided, it is
|
||||||
|
|
|
@ -880,6 +880,9 @@ func ProvisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface,
|
||||||
Type: p.Type.String(),
|
Type: p.Type.String(),
|
||||||
Name: p.Name,
|
Name: p.Name,
|
||||||
ForceCN: cfg.ForceCn,
|
ForceCN: cfg.ForceCn,
|
||||||
|
TermsOfService: cfg.TermsOfService,
|
||||||
|
Website: cfg.Website,
|
||||||
|
CaaIdentities: cfg.CaaIdentities,
|
||||||
RequireEAB: cfg.RequireEab,
|
RequireEAB: cfg.RequireEab,
|
||||||
Challenges: challengesToCertificates(cfg.Challenges),
|
Challenges: challengesToCertificates(cfg.Challenges),
|
||||||
AttestationFormats: attestationFormatsToCertificates(cfg.AttestationFormats),
|
AttestationFormats: attestationFormatsToCertificates(cfg.AttestationFormats),
|
||||||
|
@ -1138,6 +1141,10 @@ func ProvisionerToLinkedca(p provisioner.Interface) (*linkedca.Provisioner, erro
|
||||||
Data: &linkedca.ProvisionerDetails_ACME{
|
Data: &linkedca.ProvisionerDetails_ACME{
|
||||||
ACME: &linkedca.ACMEProvisioner{
|
ACME: &linkedca.ACMEProvisioner{
|
||||||
ForceCn: p.ForceCN,
|
ForceCn: p.ForceCN,
|
||||||
|
TermsOfService: p.TermsOfService,
|
||||||
|
Website: p.Website,
|
||||||
|
CaaIdentities: p.CaaIdentities,
|
||||||
|
RequireEab: p.RequireEAB,
|
||||||
Challenges: challengesToLinkedca(p.Challenges),
|
Challenges: challengesToLinkedca(p.Challenges),
|
||||||
AttestationFormats: attestationFormatsToLinkedca(p.AttestationFormats),
|
AttestationFormats: attestationFormatsToLinkedca(p.AttestationFormats),
|
||||||
AttestationRoots: provisionerPEMToLinkedca(p.AttestationRoots),
|
AttestationRoots: provisionerPEMToLinkedca(p.AttestationRoots),
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -44,7 +44,7 @@ require (
|
||||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
|
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
|
||||||
go.step.sm/cli-utils v0.7.5
|
go.step.sm/cli-utils v0.7.5
|
||||||
go.step.sm/crypto v0.23.0
|
go.step.sm/crypto v0.23.0
|
||||||
go.step.sm/linkedca v0.19.0-rc.3
|
go.step.sm/linkedca v0.19.0-rc.4
|
||||||
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b
|
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b
|
||||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b
|
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b
|
||||||
golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 // indirect
|
golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 // indirect
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -688,6 +688,8 @@ go.step.sm/crypto v0.23.0 h1:pkkAlQxeDs+7qZ0mWSnN25qbtDm/AH6u0hYlwcmRWng=
|
||||||
go.step.sm/crypto v0.23.0/go.mod h1:sK4iH/xyQDbffE1jCgj5hraVrbdKY9CTs0Lnjskxnk4=
|
go.step.sm/crypto v0.23.0/go.mod h1:sK4iH/xyQDbffE1jCgj5hraVrbdKY9CTs0Lnjskxnk4=
|
||||||
go.step.sm/linkedca v0.19.0-rc.3 h1:3Uu8j187wm7mby+/pz/aQ0wHKRm7w/2AsVPpvcAn4v8=
|
go.step.sm/linkedca v0.19.0-rc.3 h1:3Uu8j187wm7mby+/pz/aQ0wHKRm7w/2AsVPpvcAn4v8=
|
||||||
go.step.sm/linkedca v0.19.0-rc.3/go.mod h1:MCZmPIdzElEofZbiw4eyUHayXgFTwa94cNAV34aJ5ew=
|
go.step.sm/linkedca v0.19.0-rc.3/go.mod h1:MCZmPIdzElEofZbiw4eyUHayXgFTwa94cNAV34aJ5ew=
|
||||||
|
go.step.sm/linkedca v0.19.0-rc.4 h1:kaBW+xHkRRgMNDa4gWiIj7gBq5yjbJKGlTWYYo5z2KQ=
|
||||||
|
go.step.sm/linkedca v0.19.0-rc.4/go.mod h1:b7vWPrHfYLEOTSUZitFEcztVCpTc+ileIN85CwEAluM=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
|
|
Loading…
Reference in a new issue