Revert "Allow account deactivation (#2138)" (#2188)

This reverts commit 6f3d078414, reversing
changes made to c8f1fb3e2f.
This commit is contained in:
Roland Bracewell Shoemaker 2016-09-19 11:20:41 -07:00 committed by GitHub
parent c6af5d1902
commit 2c966c61b2
14 changed files with 11 additions and 322 deletions

View File

@ -69,9 +69,6 @@ type RegistrationAuthority interface {
// [WebFrontEnd]
RevokeCertificateWithReg(ctx context.Context, cert x509.Certificate, code revocation.Reason, regID int64) error
// [WebFrontEnd]
DeactivateRegistration(ctx context.Context, reg Registration) error
// [WebFrontEnd]
DeactivateAuthorization(ctx context.Context, auth Authorization) error
@ -120,7 +117,6 @@ type StorageAdder interface {
AddCertificate(ctx context.Context, der []byte, regID int64) (digest string, err error)
AddSCTReceipt(ctx context.Context, sct SignedCertificateTimestamp) error
RevokeAuthorizationsByDomain(ctx context.Context, domain AcmeIdentifier) (finalized, pending int64, err error)
DeactivateRegistration(ctx context.Context, id int64) error
DeactivateAuthorization(ctx context.Context, id string) error
}

View File

@ -31,12 +31,12 @@ type IdentifierType string
// OCSPStatus defines the state of OCSP for a domain
type OCSPStatus string
// These statuses are the states of authorizations, challenges, and registrations
// These statuses are the states of authorizations
const (
StatusUnknown = AcmeStatus("unknown") // Unknown status; the default
StatusPending = AcmeStatus("pending") // In process; client has next action
StatusProcessing = AcmeStatus("processing") // In process; server has next action
StatusValid = AcmeStatus("valid") // Object is valid
StatusValid = AcmeStatus("valid") // Validation succeeded
StatusInvalid = AcmeStatus("invalid") // Validation failed
StatusRevoked = AcmeStatus("revoked") // Object no longer valid
StatusDeactivated = AcmeStatus("deactivated") // Object has been deactivated
@ -159,8 +159,6 @@ type Registration struct {
// CreatedAt is the time the registration was created.
CreatedAt time.Time `json:"createdAt"`
Status AcmeStatus
}
// ValidationRecord represents a validation attempt against a specific URL/hostname

View File

@ -47,6 +47,10 @@ Boulder does not allow `tel` URIs in the registrations `contact` list.
Boulder does not implement key roll-over.
## [Section 6.2.2.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.2.2)
Boulder does not implement account deactivation.
## [Section 6.3.](https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.3)
Boulder does not implement applications, instead it implements the `new-cert` flow from [draft-ietf-acme-02 Section 6.5](https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-6.5).

View File

@ -59,7 +59,6 @@ const (
"x":"S8FOmrZ3ywj4yyFqt0etAD90U-EnkNaOBSLfQmf7pNg",
"y":"vMvpDyqFDRHjGfZ1siDOm5LS6xNdR5xTpyoQGLDOX2Q"
}`
test3KeyPublicJSON = `{"kty":"RSA","n":"uTQER6vUA1RDixS8xsfCRiKUNGRzzyIK0MhbS2biClShbb0hSx2mPP7gBvis2lizZ9r-y9hL57kNQoYCKndOBg0FYsHzrQ3O9AcoV1z2Mq-XhHZbFrVYaXI0M3oY9BJCWog0dyi3XC0x8AxC1npd1U61cToHx-3uSvgZOuQA5ffEn5L38Dz1Ti7OV3E4XahnRJvejadUmTkki7phLBUXm5MnnyFm0CPpf6ApV7zhLjN5W-nV0WL17o7v8aDgV_t9nIdi1Y26c3PlCEtiVHZcebDH5F1Deta3oLLg9-g6rWnTqPbY3knffhp4m0scLD6e33k8MtzxDX_D7vHsg0_X1w","e":"AQAB"}`
agreementURL = "http://example.invalid/terms"
)
@ -88,7 +87,6 @@ func (sa *StorageAuthority) GetRegistration(_ context.Context, id int64) (core.R
Agreement: agreementURL,
InitialIP: net.ParseIP("5.6.7.8"),
CreatedAt: time.Date(2003, 9, 27, 0, 0, 0, 0, time.UTC),
Status: core.StatusValid,
}, nil
}
@ -96,7 +94,6 @@ func (sa *StorageAuthority) GetRegistration(_ context.Context, id int64) (core.R
func (sa *StorageAuthority) GetRegistrationByKey(_ context.Context, jwk jose.JsonWebKey) (core.Registration, error) {
var test1KeyPublic jose.JsonWebKey
var test2KeyPublic jose.JsonWebKey
var test3KeyPublic jose.JsonWebKey
var testE1KeyPublic jose.JsonWebKey
var testE2KeyPublic jose.JsonWebKey
var err error
@ -108,10 +105,6 @@ func (sa *StorageAuthority) GetRegistrationByKey(_ context.Context, jwk jose.Jso
if err != nil {
return core.Registration{}, err
}
err = test3KeyPublic.UnmarshalJSON([]byte(test3KeyPublicJSON))
if err != nil {
return core.Registration{}, err
}
err = testE1KeyPublic.UnmarshalJSON([]byte(testE1KeyPublicJSON))
if err != nil {
panic(err)
@ -124,13 +117,7 @@ func (sa *StorageAuthority) GetRegistrationByKey(_ context.Context, jwk jose.Jso
contacts := []string{"mailto:person@mail.com"}
if core.KeyDigestEquals(jwk, test1KeyPublic) {
return core.Registration{
ID: 1,
Key: jwk,
Agreement: agreementURL,
Contact: &contacts,
Status: core.StatusValid,
}, nil
return core.Registration{ID: 1, Key: jwk, Agreement: agreementURL, Contact: &contacts}, nil
}
if core.KeyDigestEquals(jwk, test2KeyPublic) {
@ -146,17 +133,6 @@ func (sa *StorageAuthority) GetRegistrationByKey(_ context.Context, jwk jose.Jso
return core.Registration{ID: 4}, core.NoSuchRegistrationError("reg not found")
}
if core.KeyDigestEquals(jwk, test3KeyPublic) {
// deactivated registration
return core.Registration{
ID: 2,
Key: jwk,
Agreement: agreementURL,
Contact: &contacts,
Status: core.StatusDeactivated,
}, nil
}
// Return a fake registration. Make sure to fill the key field to avoid marshaling errors.
return core.Registration{ID: 1, Key: test1KeyPublic, Agreement: agreementURL}, nil
}
@ -340,11 +316,6 @@ func (sa *StorageAuthority) DeactivateAuthorization(_ context.Context, _ string)
return nil
}
// DeactivateRegistration is a mock
func (sa *StorageAuthority) DeactivateRegistration(_ context.Context, _ int64) error {
return nil
}
// Publisher is a mock
type Publisher struct {
// empty

View File

@ -256,8 +256,7 @@ func (ra *RegistrationAuthorityImpl) NewRegistration(ctx context.Context, init c
}
reg = core.Registration{
Key: init.Key,
Status: core.StatusValid,
Key: init.Key,
}
_ = mergeUpdate(&reg, init)
@ -1075,18 +1074,6 @@ func (ra *RegistrationAuthorityImpl) onValidationUpdate(ctx context.Context, aut
return nil
}
// DeactivateRegistration deactivates a valid registration
func (ra *RegistrationAuthorityImpl) DeactivateRegistration(ctx context.Context, reg core.Registration) error {
if reg.Status != core.StatusValid {
return core.MalformedRequestError("Only vaid registrations can be deactivated")
}
err := ra.SA.DeactivateRegistration(ctx, reg.ID)
if err != nil {
return core.InternalServerError(err.Error())
}
return nil
}
// DeactivateAuthorization deactivates a currently valid authorization
func (ra *RegistrationAuthorityImpl) DeactivateAuthorization(ctx context.Context, auth core.Authorization) error {
if auth.Status != core.StatusValid && auth.Status != core.StatusPending {

View File

@ -236,7 +236,6 @@ func initAuthorities(t *testing.T) (*DummyValidationAuthority, *sa.SQLStorageAut
Registration, _ = ssa.NewRegistration(ctx, core.Registration{
Key: AccountKeyA,
InitialIP: net.ParseIP("3.2.3.3"),
Status: core.StatusValid,
})
ra := NewRegistrationAuthorityImpl(fc,
@ -1267,21 +1266,6 @@ func TestDeactivateAuthorization(t *testing.T) {
test.AssertEquals(t, deact.Status, core.StatusDeactivated)
}
func TestDeactivateRegistration(t *testing.T) {
_, _, ra, _, cleanUp := initAuthorities(t)
defer cleanUp()
err := ra.DeactivateRegistration(context.Background(), core.Registration{ID: 1})
test.AssertError(t, err, "DeactivateRegistration failed with a non-valid registration")
err = ra.DeactivateRegistration(context.Background(), core.Registration{ID: 1, Status: core.StatusDeactivated})
test.AssertError(t, err, "DeactivateRegistration failed with a non-valid registration")
err = ra.DeactivateRegistration(context.Background(), core.Registration{ID: 1, Status: core.StatusValid})
test.AssertNotError(t, err, "DeactivateRegistration failed")
dbReg, err := ra.SA.GetRegistration(context.Background(), 1)
test.AssertNotError(t, err, "GetRegistration failed")
test.AssertEquals(t, dbReg.Status, core.StatusDeactivated)
}
var CAkeyPEM = `
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEAqmM0dEf/J9MCk2ItzevL0dKJ84lVUtf/vQ7AXFi492vFXc3b

View File

@ -71,8 +71,6 @@ const (
MethodFQDNSetExists = "FQDNSetExists" // SA
MethodDeactivateAuthorizationSA = "DeactivateAuthorizationSA" // SA
MethodDeactivateAuthorization = "DeactivateAuthorization" // RA
MethodDeactivateRegistrationSA = "DeactivateRegistrationSA" // SA
MethodDeactivateRegistration = "DeactivateRegistration" // RA
)
// Request structs
@ -151,10 +149,6 @@ type performValidationRequest struct {
Authz core.Authorization
}
type deactivateRegistrationRequest struct {
ID int64
}
type performValidationResponse struct {
Records []core.ValidationRecord
Problem *probs.ProblemDetails
@ -380,21 +374,6 @@ func NewRegistrationAuthorityServer(rpc Server, impl core.RegistrationAuthority,
return
})
rpc.Handle(MethodDeactivateRegistration, func(ctx context.Context, req []byte) (response []byte, err error) {
var reg core.Registration
err = json.Unmarshal(req, &reg)
if err != nil {
errorCondition(MethodDeactivateRegistration, err, req)
return
}
err = impl.DeactivateRegistration(ctx, reg)
if err != nil {
errorCondition(MethodDeactivateRegistration, err, req)
return
}
return
})
return nil
}
@ -546,16 +525,6 @@ func (rac RegistrationAuthorityClient) DeactivateAuthorization(ctx context.Conte
return err
}
// DeactivateRegistration deactivates a currently valid registration
func (rac RegistrationAuthorityClient) DeactivateRegistration(ctx context.Context, reg core.Registration) error {
data, err := json.Marshal(reg)
if err != nil {
return err
}
_, err = rac.rpc.DispatchSync(MethodDeactivateRegistration, data)
return err
}
// NewValidationAuthorityServer constructs an RPC server
//
// ValidationAuthorityClient / Server
@ -1143,20 +1112,6 @@ func NewStorageAuthorityServer(rpc Server, impl core.StorageAuthority) error {
return
})
rpc.Handle(MethodDeactivateRegistrationSA, func(ctx context.Context, req []byte) (response []byte, err error) {
var drReq deactivateRegistrationRequest
err = json.Unmarshal(req, &drReq)
if err != nil {
return
}
err = impl.DeactivateRegistration(ctx, drReq.ID)
if err != nil {
errorCondition(MethodDeactivateRegistrationSA, err, req)
return
}
return
})
return nil
}
@ -1528,13 +1483,3 @@ func (cac StorageAuthorityClient) DeactivateAuthorization(ctx context.Context, i
_, err := cac.rpc.DispatchSync(MethodDeactivateAuthorizationSA, []byte(id))
return err
}
// DeactivateRegistration deactivates a currently valid registration
func (cac StorageAuthorityClient) DeactivateRegistration(ctx context.Context, id int64) error {
data, err := json.Marshal(deactivateRegistrationRequest{id})
if err != nil {
return err
}
_, err = cac.rpc.DispatchSync(MethodDeactivateRegistrationSA, data)
return err
}

View File

@ -1,11 +0,0 @@
-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied
ALTER TABLE `registrations` ADD COLUMN (`status` varchar(255) DEFAULT NULL);
UPDATE `registrations` SET `status` = 'valid';
-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back
ALTER TABLE `registrations` DROP COLUMN `status`;

View File

@ -32,7 +32,6 @@ type regModel struct {
// represents a v4 or v6 IP address.
InitialIP []byte `db:"initialIp"`
CreatedAt time.Time `db:"createdAt"`
Status string `db:"status"`
LockCol int64
}
@ -88,7 +87,6 @@ func registrationToModel(r *core.Registration) (*regModel, error) {
Agreement: r.Agreement,
InitialIP: []byte(r.InitialIP.To16()),
CreatedAt: r.CreatedAt,
Status: string(r.Status),
}
return rm, nil
}
@ -116,7 +114,6 @@ func modelToRegistration(rm *regModel) (core.Registration, error) {
Agreement: rm.Agreement,
InitialIP: net.IP(rm.InitialIP),
CreatedAt: rm.CreatedAt,
Status: core.AcmeStatus(rm.Status),
}
return r, nil
}

View File

@ -917,17 +917,6 @@ func (ssa *SQLStorageAuthority) FQDNSetExists(ctx context.Context, names []strin
return count > 0, err
}
// DeactivateRegistration deactivates a currently valid registration
func (ssa *SQLStorageAuthority) DeactivateRegistration(ctx context.Context, id int64) error {
_, err := ssa.dbMap.Exec(
"UPDATE registrations SET status = ? WHERE status = ? AND id = ?",
string(core.StatusDeactivated),
string(core.StatusValid),
id,
)
return err
}
// DeactivateAuthorization deactivates a currently valid or pending authorization
func (ssa *SQLStorageAuthority) DeactivateAuthorization(ctx context.Context, id string) error {
tx, err := ssa.dbMap.Begin()

View File

@ -828,17 +828,3 @@ func TestDeactivateAuthorization(t *testing.T) {
test.AssertNotError(t, err, "Couldn't get authorization with ID "+PA.ID)
test.AssertEquals(t, dbPa.Status, core.StatusDeactivated)
}
func TestDeactivateAccount(t *testing.T) {
sa, _, cleanUp := initSA(t)
defer cleanUp()
reg := satest.CreateWorkingRegistration(t, sa)
err := sa.DeactivateRegistration(context.Background(), reg.ID)
test.AssertNotError(t, err, "DeactivateRegistration failed")
dbReg, err := sa.GetRegistration(context.Background(), reg.ID)
test.AssertNotError(t, err, "GetRegistration failed")
test.AssertEquals(t, dbReg.Status, core.StatusDeactivated)
}

View File

@ -47,7 +47,6 @@ func CreateWorkingRegistration(t *testing.T, sa core.StorageAdder) core.Registra
Contact: contacts,
InitialIP: net.ParseIP("88.77.66.11"),
CreatedAt: time.Date(2003, 5, 10, 0, 0, 0, 0, time.UTC),
Status: core.StatusValid,
})
if err != nil {
t.Fatalf("Unable to create new registration: %s", err)

View File

@ -83,10 +83,9 @@ type WebFrontEndImpl struct {
RequestTimeout time.Duration
// Feature gates
CheckMalformedCSR bool
AcceptRevocationReason bool
AllowAccountDeactivation bool
AllowAuthzDeactivation bool
CheckMalformedCSR bool
AcceptRevocationReason bool
AllowAuthzDeactivation bool
}
// NewWebFrontEndImpl constructs a web service for Boulder
@ -452,10 +451,6 @@ func (wfe *WebFrontEndImpl) verifyPOST(ctx context.Context, logEvent *requestEve
logEvent.Contacts = reg.Contact
}
if wfe.AllowAccountDeactivation && reg.Status != core.StatusValid {
return nil, nil, reg, probs.Unauthorized(fmt.Sprintf("Registration is not valid, has status '%s'", reg.Status))
}
if statName, err := checkAlgorithm(key, parsedJws); err != nil {
wfe.stats.Inc(statName, 1)
return nil, nil, reg, probs.Malformed(err.Error())
@ -1116,23 +1111,6 @@ func (wfe *WebFrontEndImpl) Registration(ctx context.Context, logEvent *requestE
return
}
// People *will* POST their full registrations to this endpoint, including
// the 'valid' status, to avoid always failing out when that happens only
// attempt to deactivate if the provided status is different from their current
// status.
//
// If a user tries to send both a deactivation request and an update to their
// contacts or subscriber agreement URL the deactivation will take place and
// return before an update would be performed.
if wfe.AllowAccountDeactivation && (update.Status != currReg.Status) {
if update.Status != core.StatusDeactivated {
wfe.sendError(response, logEvent, probs.Malformed("Invalid value provided for status field"), nil)
return
}
wfe.deactivateRegistration(ctx, currReg, response, request, logEvent)
return
}
// If a user POSTs their registration object including a previously valid
// agreement URL but that URL has since changed we will fail out here
// since the update agreement URL doesn't match the current URL. To fix that we
@ -1390,23 +1368,3 @@ func (wfe *WebFrontEndImpl) setCORSHeaders(response http.ResponseWriter, request
response.Header().Set("Access-Control-Expose-Headers", "Link, Replay-Nonce")
response.Header().Set("Access-Control-Max-Age", "86400")
}
func (wfe *WebFrontEndImpl) deactivateRegistration(ctx context.Context, reg core.Registration, response http.ResponseWriter, request *http.Request, logEvent *requestEvent) {
err := wfe.RA.DeactivateRegistration(ctx, reg)
if err != nil {
logEvent.AddError("unable to deactivate registration", err)
wfe.sendError(response, logEvent, core.ProblemDetailsForError(err, "Error deactivating registration"), err)
return
}
reg.Status = core.StatusDeactivated
jsonReply, err := marshalIndent(reg)
if err != nil {
// ServerInternal because registration is from DB and should be fine
logEvent.AddError("unable to marshal updated registration: %s", err)
wfe.sendError(response, logEvent, probs.ServerInternal("Failed to marshal registration"), err)
return
}
response.Header().Set("Content-Type", "application/json")
response.WriteHeader(http.StatusOK)
response.Write(jsonReply)
}

View File

@ -111,43 +111,12 @@ TkLlEeVOuQfxTadw05gzKX0jKkMC4igGxvEeilYc6NR6a4nvRulG84Q8VV9Sy9Ie
wk6Oiadty3eQqSBJv0HnpmiEdQVffIK5Pg4M8Dd+aOBnEkbopAJOuA==
-----END RSA PRIVATE KEY-----
`
test3KeyPrivatePEM = `
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAuTQER6vUA1RDixS8xsfCRiKUNGRzzyIK0MhbS2biClShbb0h
Sx2mPP7gBvis2lizZ9r+y9hL57kNQoYCKndOBg0FYsHzrQ3O9AcoV1z2Mq+XhHZb
FrVYaXI0M3oY9BJCWog0dyi3XC0x8AxC1npd1U61cToHx+3uSvgZOuQA5ffEn5L3
8Dz1Ti7OV3E4XahnRJvejadUmTkki7phLBUXm5MnnyFm0CPpf6ApV7zhLjN5W+nV
0WL17o7v8aDgV/t9nIdi1Y26c3PlCEtiVHZcebDH5F1Deta3oLLg9+g6rWnTqPbY
3knffhp4m0scLD6e33k8MtzxDX/D7vHsg0/X1wIDAQABAoIBAQCnFJpX3lhiuH5G
1uqHmmdVxpRVv9oKn/eJ63cRSzvZfgg0bE/A6Hq0xGtvXqDySttvck4zsGqqHnQr
86G4lfE53D1jnv4qvS5bUKnARwmFKIxU4EHE9s1QM8uMNTaV2nMqIX7TkVP6QHuw
yB70R2inq15dS7EBWVGFKNX6HwAAdj8pFuF6o2vIwmAfee20aFzpWWf81jOH9Ai6
hyJyV3NqrU1JzIwlXaeX67R1VroFdhN/lapp+2b0ZEcJJtFlcYFl99NjkQeVZyik
izNv0GZZNWizc57wU0/8cv+jQ2f26ltvyrPz3QNK61bFfzy+/tfMvLq7sdCmztKJ
tMxCBJOBAoGBAPKnIVQIS2nTvC/qZ8ajw1FP1rkvYblIiixegjgfFhM32HehQ+nu
3TELi3I3LngLYi9o6YSqtNBmdBJB+DUAzIXp0TdOihOweGiv5dAEWwY9rjCzMT5S
GP7dCWiJwoMUHrOs1Po3dwcjj/YsoAW+FC0jSvach2Ln2CvPgr5FP0ARAoGBAMNj
64qUCzgeXiSyPKK69bCCGtHlTYUndwHQAZmABjbmxAXZNYgp/kBezFpKOwmICE8R
kK8YALRrL0VWXl/yj85b0HAZGkquNFHPUDd1e6iiP5TrY+Hy4oqtlYApjH6f85CE
lWjQ1iyUL7aT6fcSgzq65ZWD2hUzvNtWbTt6zQFnAoGAWS/EuDY0QblpOdNWQVR/
vasyqO4ZZRiccKJsCmSioH2uOoozhBAfjJ9JqblOgyDr/bD546E6xD5j+zH0IMci
ZTYDh+h+J659Ez1Topl3O1wAYjX6q4VRWpuzkZDQxYznm/KydSVdwmn3x+uvBW1P
zSdjrjDqMhg1BCVJUNXy4YECgYEAjX1z+dwO68qB3gz7/9NnSzRL+6cTJdNYSIW6
QtAEsAkX9iw+qaXPKgn77X5HljVd3vQXU9QL3pqnloxetxhNrt+p5yMmeOIBnSSF
MEPxEkK7zDlRETPzfP0Kf86WoLNviz2XfFmOXqXIj2w5RuOvB/6DdmwOpr/aiPLj
EulwPw0CgYAMSzsWOt6vU+y/G5NyhUCHvY50TdnGOj2btBk9rYVwWGWxCpg2QF0R
pcKXgGzXEVZKFAqB8V1c/mmCo8ojPgmqGM+GzX2Bj4seVBW7PsTeZUjrHpADshjV
F7o5b7y92NlxO5kwQzRKEAhwS5PbKJdx90iCuG+JlI1YgWlA1VcJMw==
-----END RSA PRIVATE KEY-----
`
testE1KeyPublicJSON = `{
"kty":"EC",
"crv":"P-256",
"x":"FwvSZpu06i3frSk_mz9HcD9nETn4wf3mQ-zDtG21Gao",
"y":"S8rR-0dWa8nAcw1fbunF_ajS3PQZ-QwLps-2adgLgPk"
}`
testE1KeyPrivatePEM = `
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIH+p32RUnqT/iICBEGKrLIWFcyButv0S0lU/BLPOyHn2oAoGCCqGSM49
@ -213,10 +182,6 @@ func (ra *MockRegistrationAuthority) DeactivateAuthorization(ctx context.Context
return nil
}
func (ra *MockRegistrationAuthority) DeactivateRegistration(ctx context.Context, _ core.Registration) error {
return nil
}
type mockPA struct{}
func (pa *mockPA) ChallengesFor(identifier core.AcmeIdentifier) (challenges []core.Challenge, combinations [][]int) {
@ -1851,82 +1816,3 @@ func TestDeactivateAuthorization(t *testing.T) {
]
}`)
}
func TestDeactivateRegistration(t *testing.T) {
responseWriter := httptest.NewRecorder()
wfe, _ := setupWFE(t)
wfe.AllowAccountDeactivation = true
responseWriter.Body.Reset()
wfe.Registration(ctx, newRequestEvent(), responseWriter,
makePostRequestWithPath("1", signRequest(t, `{"resource":"reg","status":"asd"}`, wfe.nonceService)))
assertJSONEquals(t,
responseWriter.Body.String(),
`{"type": "urn:acme:error:malformed","detail": "Invalid value provided for status field","status": 400}`)
responseWriter.Body.Reset()
wfe.Registration(ctx, newRequestEvent(), responseWriter,
makePostRequestWithPath("1", signRequest(t, `{"resource":"reg","status":"deactivated"}`, wfe.nonceService)))
assertJSONEquals(t,
responseWriter.Body.String(),
`{
"id": 1,
"key": {
"kty": "RSA",
"n": "yNWVhtYEKJR21y9xsHV-PD_bYwbXSeNuFal46xYxVfRL5mqha7vttvjB_vc7Xg2RvgCxHPCqoxgMPTzHrZT75LjCwIW2K_klBYN8oYvTwwmeSkAz6ut7ZxPv-nZaT5TJhGk0NT2kh_zSpdriEJ_3vW-mqxYbbBmpvHqsa1_zx9fSuHYctAZJWzxzUZXykbWMWQZpEiE0J4ajj51fInEzVn7VxV-mzfMyboQjujPh7aNJxAWSq4oQEJJDgWwSh9leyoJoPpONHxh5nEE5AjE01FkGICSxjpZsF-w8hOTI3XXohUdu29Se26k2B0PolDSuj0GIQU6-W9TdLXSjBb2SpQ",
"e": "AQAB"
},
"contact": [
"mailto:person@mail.com"
],
"agreement": "http://example.invalid/terms",
"initialIp": "",
"createdAt": "0001-01-01T00:00:00Z",
"Status": "deactivated"
}`)
responseWriter.Body.Reset()
wfe.Registration(ctx, newRequestEvent(), responseWriter,
makePostRequestWithPath("1", signRequest(t, `{"resource":"reg","status":"deactivated","contact":[]}`, wfe.nonceService)))
assertJSONEquals(t,
responseWriter.Body.String(),
`{
"id": 1,
"key": {
"kty": "RSA",
"n": "yNWVhtYEKJR21y9xsHV-PD_bYwbXSeNuFal46xYxVfRL5mqha7vttvjB_vc7Xg2RvgCxHPCqoxgMPTzHrZT75LjCwIW2K_klBYN8oYvTwwmeSkAz6ut7ZxPv-nZaT5TJhGk0NT2kh_zSpdriEJ_3vW-mqxYbbBmpvHqsa1_zx9fSuHYctAZJWzxzUZXykbWMWQZpEiE0J4ajj51fInEzVn7VxV-mzfMyboQjujPh7aNJxAWSq4oQEJJDgWwSh9leyoJoPpONHxh5nEE5AjE01FkGICSxjpZsF-w8hOTI3XXohUdu29Se26k2B0PolDSuj0GIQU6-W9TdLXSjBb2SpQ",
"e": "AQAB"
},
"contact": [
"mailto:person@mail.com"
],
"agreement": "http://example.invalid/terms",
"initialIp": "",
"createdAt": "0001-01-01T00:00:00Z",
"Status": "deactivated"
}`)
key, err := jose.LoadPrivateKey([]byte(test3KeyPrivatePEM))
test.AssertNotError(t, err, "Failed to load key")
rsaKey, ok := key.(*rsa.PrivateKey)
test.Assert(t, ok, "Couldn't load RSA key")
signer, err := jose.NewSigner("RS256", rsaKey)
test.AssertNotError(t, err, "Failed to make signer")
signer.SetNonceSource(wfe.nonceService)
result, err := signer.Sign([]byte(`{"resource":"reg","status":"deactivated"}`))
test.AssertNotError(t, err, "Unable to sign")
wfe.Registration(ctx, newRequestEvent(), responseWriter,
makePostRequestWithPath("2", result.FullSerialize()))
responseWriter.Body.Reset()
wfe.Registration(ctx, newRequestEvent(), responseWriter,
makePostRequestWithPath("2", result.FullSerialize()))
assertJSONEquals(t,
responseWriter.Body.String(),
`{
"type": "urn:acme:error:unauthorized",
"detail": "Registration is not valid, has status 'deactivated'",
"status": 403
}`)
}