Reviewed-on: #6tags/v0.10.5
@@ -8,8 +8,7 @@ import bubble.model.account.AccountPolicy; | |||||
import org.cobbzilla.wizard.validation.ValidationResult; | import org.cobbzilla.wizard.validation.ValidationResult; | ||||
import org.springframework.stereotype.Repository; | import org.springframework.stereotype.Repository; | ||||
import java.util.List; | |||||
import static bubble.model.account.AccountDeletionPolicy.full_delete; | |||||
import static org.cobbzilla.util.daemon.ZillaRuntime.die; | import static org.cobbzilla.util.daemon.ZillaRuntime.die; | ||||
import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; | import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; | ||||
@@ -32,8 +31,19 @@ public class AccountPolicyDAO extends AccountOwnedEntityDAO<AccountPolicy> { | |||||
} | } | ||||
public AccountPolicy findSingleByAccount(String accountUuid) { | public AccountPolicy findSingleByAccount(String accountUuid) { | ||||
final List<AccountPolicy> found = findByAccount(accountUuid); | |||||
return found.isEmpty() ? create(new AccountPolicy().setAccount(accountUuid)) : found.size() > 1 ? die("findSingleByAccount: "+found.size()+" found!") : found.get(0); | |||||
final var found = findByAccount(accountUuid); | |||||
if (found.size() == 1) return found.get(0); | |||||
if (found.size() > 1) { | |||||
die("findSingleByAccount: More than 1 policy found for account " + accountUuid + " - " + found.size()); | |||||
} | |||||
// If there's no policy, create one. Note that is account is marked as deleted, the new policy will be with full | |||||
// deletion set in. | |||||
final var newPolicy = new AccountPolicy().setAccount(accountUuid); | |||||
final var account = getConfiguration().getBean(AccountDAO.class).findById(accountUuid); | |||||
if (account.deleted()) newPolicy.setDeletionPolicy(full_delete); | |||||
return create(newPolicy); | |||||
} | } | ||||
} | } |
@@ -306,7 +306,7 @@ public class AuthResource { | |||||
if (!request.hasName()) return invalid("err.name.required", "name is required"); | if (!request.hasName()) return invalid("err.name.required", "name is required"); | ||||
if (!request.hasPassword()) return invalid("err.password.required", "password is required"); | if (!request.hasPassword()) return invalid("err.password.required", "password is required"); | ||||
final Account account = accountDAO.findByName(request.getName()); | final Account account = accountDAO.findByName(request.getName()); | ||||
if (account == null) return notFound(request.getName()); | |||||
if (account == null || account.deleted()) return notFound(request.getName()); | |||||
if (!account.getHashedPassword().isCorrectPassword(request.getPassword())) { | if (!account.getHashedPassword().isCorrectPassword(request.getPassword())) { | ||||
return notFound(request.getName()); | return notFound(request.getName()); | ||||
} | } | ||||
@@ -28,6 +28,7 @@ | |||||
<logger name="org.cobbzilla.util.daemon.ZillaRuntime" level="WARN" /> | <logger name="org.cobbzilla.util.daemon.ZillaRuntime" level="WARN" /> | ||||
<logger name="org.cobbzilla.wizard.server" level="WARN" /> | <logger name="org.cobbzilla.wizard.server" level="WARN" /> | ||||
<logger name="org.cobbzilla.wizard.client" level="WARN" /> | <logger name="org.cobbzilla.wizard.client" level="WARN" /> | ||||
<logger name="org.cobbzilla.wizard.client.script" level="INFO" /> | |||||
<logger name="org.cobbzilla.wizard.model.entityconfig.ModelSetup" level="INFO" /> | <logger name="org.cobbzilla.wizard.model.entityconfig.ModelSetup" level="INFO" /> | ||||
<logger name="org.cobbzilla.wizard.resources.AbstractEntityConfigsResource" level="ERROR" /> | <logger name="org.cobbzilla.wizard.resources.AbstractEntityConfigsResource" level="ERROR" /> | ||||
<logger name="org.cobbzilla.wizard.resources.ResourceUtil" level="ERROR" /> | <logger name="org.cobbzilla.wizard.resources.ResourceUtil" level="ERROR" /> | ||||
@@ -0,0 +1,19 @@ | |||||
/** | |||||
* Copyright (c) 2020 Bubble, Inc. All rights reserved. | |||||
* For personal (non-commercial) use, see license: https://bubblev.com/bubble-license/ | |||||
*/ | |||||
package bubble.test.system; | |||||
import bubble.test.ActivatedBubbleModelTestBase; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.junit.Test; | |||||
@Slf4j | |||||
public class AccountDeletionTest extends ActivatedBubbleModelTestBase { | |||||
@Override protected String getManifest() { return "manifest-test"; } | |||||
@Test public void testFullAccountDeletion() throws Exception { modelTest("account_deletion/full_delete_account"); } | |||||
@Test public void testBlockAccountDeletion() throws Exception { modelTest("account_deletion/block_delete_account"); } | |||||
} |
@@ -24,7 +24,6 @@ public class AuthTest extends ActivatedBubbleModelTestBase { | |||||
accountDAO.update(rootUser.setHashedPassword(new HashedPassword(ROOT_PASSWORD))); | accountDAO.update(rootUser.setHashedPassword(new HashedPassword(ROOT_PASSWORD))); | ||||
} | } | ||||
@Test public void testAccountDeletion () throws Exception { modelTest("auth/delete_account"); } | |||||
@Test public void testBasicAuth () throws Exception { modelTest("auth/basic_auth"); } | @Test public void testBasicAuth () throws Exception { modelTest("auth/basic_auth"); } | ||||
@Test public void testAccountCrud () throws Exception { modelTest("auth/account_crud"); } | @Test public void testAccountCrud () throws Exception { modelTest("auth/account_crud"); } | ||||
@Test public void testDeviceCrud () throws Exception { modelTest("auth/device_crud"); } | @Test public void testDeviceCrud () throws Exception { modelTest("auth/device_crud"); } | ||||
@@ -0,0 +1,97 @@ | |||||
[ | |||||
{ | |||||
"comment": "activate service, create account, login for block_delete", | |||||
"include": "new_account", | |||||
"params": { | |||||
"username": "user-to-partially-delete", | |||||
"password": "foobar1!", | |||||
"email": "user-partially-account-deletion@example.com", | |||||
"verifyEmail": "true" | |||||
} | |||||
}, | |||||
{ | |||||
"comment": "look up account policy for block_delete", | |||||
"request": { "uri": "users/{{user.uuid}}/policy" }, | |||||
"response": { | |||||
"store": "policy", | |||||
"check": [ | |||||
{"condition": "json.getAccountContacts() != null"}, | |||||
{"condition": "json.getAccountContacts().length == 1"} | |||||
] | |||||
} | |||||
}, | |||||
{ | |||||
"comment": "set deletion policy to block_delete", | |||||
"request": { | |||||
"uri": "users/{{user.uuid}}/policy", | |||||
"data": "policy", | |||||
"entity": { | |||||
"deletionPolicy": "block_delete" | |||||
} | |||||
}, | |||||
"response": { | |||||
"store": "policy", | |||||
"check": [ | |||||
{"condition": "json.getDeletionPolicy().name() == 'block_delete'"} | |||||
] | |||||
} | |||||
}, | |||||
{ | |||||
"comment": "as root, block delete account", | |||||
"request": { | |||||
"session": "rootSession", | |||||
"uri": "users/{{user.uuid}}", | |||||
"method": "delete" | |||||
} | |||||
}, | |||||
{ | |||||
"comment": "lookup user, expect that it is still there, just empty", | |||||
"request": { "uri": "users/{{user.uuid}}" }, | |||||
"response": { | |||||
"check": [ | |||||
{ "condition": "json.getUuid() == user.getUuid()" }, | |||||
{ "condition": "json.getName() == user.getName()" }, | |||||
{ "condition": "json.deleted()" } | |||||
] | |||||
} | |||||
}, | |||||
{ | |||||
"comment": "try logging in as deleted user - failing now", | |||||
"request": { | |||||
"session": "new", | |||||
"uri": "auth/login", | |||||
"entity": { | |||||
"name": "{{user.name}}", | |||||
"password": "foobar1!" | |||||
} | |||||
}, | |||||
"response": { "status": 404 } | |||||
}, | |||||
{ | |||||
"comment": "as root, look up account policy again - it should recreated for this object with full deletion policy", | |||||
"request": { "session": "rootSession", "uri": "users/{{user.uuid}}/policy" }, | |||||
"response": { "check": [{ "condition": "json.getDeletionPolicy().name() == 'full_delete'" }] } | |||||
}, | |||||
{ | |||||
"comment": "try deleting the same account again - expect fully deletion this time even without policy", | |||||
"request": { "uri": "users/{{user.uuid}}", "method": "delete" } | |||||
}, | |||||
{ | |||||
"comment": "lookup user, expect there's no such user now", | |||||
"request": { "uri": "users/{{user.uuid}}" }, | |||||
"response": { "status": 404 } | |||||
}, | |||||
{ | |||||
"comment": "as root, look up account policy again - not found, and account uuid reported as not found resource", | |||||
"request": { "session": "rootSession", "uri": "users/{{user.uuid}}/policy" }, | |||||
"response": { "status": 404, "check": [{ "condition": "json.get('resource') == user.getUuid()" }] } | |||||
} | |||||
] |
@@ -12,7 +12,7 @@ | |||||
{ | { | ||||
"comment": "look up account policy", | "comment": "look up account policy", | ||||
"request": { "uri": "users/user-to-delete/policy" }, | |||||
"request": { "uri": "users/{{user.uuid}}/policy" }, | |||||
"response": { | "response": { | ||||
"store": "policy", | "store": "policy", | ||||
"check": [ | "check": [ | ||||
@@ -25,7 +25,7 @@ | |||||
{ | { | ||||
"comment": "set deletion policy to full_delete", | "comment": "set deletion policy to full_delete", | ||||
"request": { | "request": { | ||||
"uri": "users/user-to-delete/policy", | |||||
"uri": "users/{{user.uuid}}/policy", | |||||
"data": "policy", | "data": "policy", | ||||
"entity": { | "entity": { | ||||
"deletionPolicy": "full_delete" | "deletionPolicy": "full_delete" | ||||
@@ -39,11 +39,17 @@ | |||||
} | } | ||||
}, | }, | ||||
{ | |||||
"comment": "lookup user - just checking it is the one for deletion", | |||||
"request": { "uri": "users/{{user.uuid}}" }, | |||||
"response": { "check": [{ "condition": "json.getName() == 'user-to-delete'" }] } | |||||
}, | |||||
{ | { | ||||
"comment": "as root, delete account", | "comment": "as root, delete account", | ||||
"request": { | "request": { | ||||
"session": "rootSession", | "session": "rootSession", | ||||
"uri": "users/user-to-delete", | |||||
"uri": "users/{{user.uuid}}", | |||||
"method": "delete" | "method": "delete" | ||||
} | } | ||||
}, | }, | ||||
@@ -51,8 +57,8 @@ | |||||
{ | { | ||||
"comment": "lookup user, expect not found", | "comment": "lookup user, expect not found", | ||||
"request": { | "request": { | ||||
"uri": "users/user-to-delete" | |||||
"uri": "users/{{user.uuid}}" | |||||
}, | }, | ||||
"response": { "status": 404 } | "response": { "status": 404 } | ||||
} | } | ||||
] | |||||
] |