killbill-memoizeit

account: prevent sensitive fields to be updated We don't

8/6/2012 7:35:51 PM

Details

diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java b/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
index 9f497c6..6704b4d 100644
--- a/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
@@ -20,13 +20,15 @@ import java.util.UUID;
 
 import org.joda.time.DateTimeZone;
 
-import com.google.common.base.Objects;
-import com.google.common.base.Optional;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.junction.api.BlockingState;
 import com.ning.billing.util.entity.EntityBase;
 
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+
 public class DefaultAccount extends EntityBase implements Account {
+
     // Default values. When updating an account object, null values are
     // interpreted as "no change". You can use these defaults to reset
     // some fields
@@ -214,12 +216,23 @@ public class DefaultAccount extends EntityBase implements Account {
     @Override
     public Account mergeWithDelegate(final Account delegate) {
         final DefaultMutableAccountData accountData = new DefaultMutableAccountData(this);
-        accountData.setExternalKey(Objects.firstNonNull(externalKey, delegate.getExternalKey()));
+
+        if (externalKey != null ? !externalKey.equals(delegate.getExternalKey()) : delegate.getExternalKey() != null) {
+            throw new IllegalArgumentException(String.format("Killbill doesn't support updating the account external key yet: this=%s, delegate=%s",
+                                                             externalKey, delegate.getExternalKey()));
+        }
+        if (currency != null ? !currency.equals(delegate.getCurrency()) : delegate.getCurrency() != null) {
+            throw new IllegalArgumentException(String.format("Killbill doesn't support updating the account currency yet: this=%s, delegate=%s",
+                                                             currency, delegate.getCurrency()));
+        }
+        if (billCycleDay != null ? !billCycleDay.equals(delegate.getBillCycleDay()) : delegate.getBillCycleDay() != null) {
+            throw new IllegalArgumentException(String.format("Killbill doesn't support updating the account BCD yet: this=%s, delegate=%s",
+                                                             billCycleDay, delegate.getBillCycleDay()));
+        }
+
         accountData.setEmail(Objects.firstNonNull(email, delegate.getEmail()));
         accountData.setName(Objects.firstNonNull(name, delegate.getName()));
         accountData.setFirstNameLength(Objects.firstNonNull(firstNameLength, delegate.getFirstNameLength()));
-        accountData.setCurrency(Objects.firstNonNull(currency, delegate.getCurrency()));
-        accountData.setBillCycleDay(Objects.firstNonNull(billCycleDay, delegate.getBillCycleDay()));
         accountData.setPaymentMethodId(Optional.<UUID>fromNullable(paymentMethodId)
                                                .or(Optional.<UUID>fromNullable(delegate.getPaymentMethodId())).orNull());
         accountData.setTimeZone(Objects.firstNonNull(timeZone, delegate.getTimeZone()));
@@ -241,23 +254,119 @@ public class DefaultAccount extends EntityBase implements Account {
     @Override
     public String toString() {
         return "DefaultAccount [externalKey=" + externalKey +
-                ", email=" + email +
-                ", name=" + name +
-                ", firstNameLength=" + firstNameLength +
-                ", phone=" + phone +
-                ", currency=" + currency +
-                ", billCycleDay=" + billCycleDay +
-                ", paymentMethodId=" + paymentMethodId +
-                ", timezone=" + timeZone +
-                ", locale=" + locale +
-                ", address1=" + address1 +
-                ", address2=" + address2 +
-                ", companyName=" + companyName +
-                ", city=" + city +
-                ", stateOrProvince=" + stateOrProvince +
-                ", postalCode=" + postalCode +
-                ", country=" + country +
-                "]";
+               ", email=" + email +
+               ", name=" + name +
+               ", firstNameLength=" + firstNameLength +
+               ", phone=" + phone +
+               ", currency=" + currency +
+               ", billCycleDay=" + billCycleDay +
+               ", paymentMethodId=" + paymentMethodId +
+               ", timezone=" + timeZone +
+               ", locale=" + locale +
+               ", address1=" + address1 +
+               ", address2=" + address2 +
+               ", companyName=" + companyName +
+               ", city=" + city +
+               ", stateOrProvince=" + stateOrProvince +
+               ", postalCode=" + postalCode +
+               ", country=" + country +
+               "]";
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final DefaultAccount that = (DefaultAccount) o;
+
+        if (address1 != null ? !address1.equals(that.address1) : that.address1 != null) {
+            return false;
+        }
+        if (address2 != null ? !address2.equals(that.address2) : that.address2 != null) {
+            return false;
+        }
+        if (billCycleDay != null ? !billCycleDay.equals(that.billCycleDay) : that.billCycleDay != null) {
+            return false;
+        }
+        if (city != null ? !city.equals(that.city) : that.city != null) {
+            return false;
+        }
+        if (companyName != null ? !companyName.equals(that.companyName) : that.companyName != null) {
+            return false;
+        }
+        if (country != null ? !country.equals(that.country) : that.country != null) {
+            return false;
+        }
+        if (currency != that.currency) {
+            return false;
+        }
+        if (email != null ? !email.equals(that.email) : that.email != null) {
+            return false;
+        }
+        if (externalKey != null ? !externalKey.equals(that.externalKey) : that.externalKey != null) {
+            return false;
+        }
+        if (firstNameLength != null ? !firstNameLength.equals(that.firstNameLength) : that.firstNameLength != null) {
+            return false;
+        }
+        if (isMigrated != null ? !isMigrated.equals(that.isMigrated) : that.isMigrated != null) {
+            return false;
+        }
+        if (isNotifiedForInvoices != null ? !isNotifiedForInvoices.equals(that.isNotifiedForInvoices) : that.isNotifiedForInvoices != null) {
+            return false;
+        }
+        if (locale != null ? !locale.equals(that.locale) : that.locale != null) {
+            return false;
+        }
+        if (name != null ? !name.equals(that.name) : that.name != null) {
+            return false;
+        }
+        if (paymentMethodId != null ? !paymentMethodId.equals(that.paymentMethodId) : that.paymentMethodId != null) {
+            return false;
+        }
+        if (phone != null ? !phone.equals(that.phone) : that.phone != null) {
+            return false;
+        }
+        if (postalCode != null ? !postalCode.equals(that.postalCode) : that.postalCode != null) {
+            return false;
+        }
+        if (stateOrProvince != null ? !stateOrProvince.equals(that.stateOrProvince) : that.stateOrProvince != null) {
+            return false;
+        }
+        if (timeZone != null ? !timeZone.equals(that.timeZone) : that.timeZone != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = externalKey != null ? externalKey.hashCode() : 0;
+        result = 31 * result + (email != null ? email.hashCode() : 0);
+        result = 31 * result + (name != null ? name.hashCode() : 0);
+        result = 31 * result + (firstNameLength != null ? firstNameLength.hashCode() : 0);
+        result = 31 * result + (currency != null ? currency.hashCode() : 0);
+        result = 31 * result + (billCycleDay != null ? billCycleDay.hashCode() : 0);
+        result = 31 * result + (paymentMethodId != null ? paymentMethodId.hashCode() : 0);
+        result = 31 * result + (timeZone != null ? timeZone.hashCode() : 0);
+        result = 31 * result + (locale != null ? locale.hashCode() : 0);
+        result = 31 * result + (address1 != null ? address1.hashCode() : 0);
+        result = 31 * result + (address2 != null ? address2.hashCode() : 0);
+        result = 31 * result + (companyName != null ? companyName.hashCode() : 0);
+        result = 31 * result + (city != null ? city.hashCode() : 0);
+        result = 31 * result + (stateOrProvince != null ? stateOrProvince.hashCode() : 0);
+        result = 31 * result + (country != null ? country.hashCode() : 0);
+        result = 31 * result + (postalCode != null ? postalCode.hashCode() : 0);
+        result = 31 * result + (phone != null ? phone.hashCode() : 0);
+        result = 31 * result + (isMigrated != null ? isMigrated.hashCode() : 0);
+        result = 31 * result + (isNotifiedForInvoices != null ? isNotifiedForInvoices.hashCode() : 0);
+        return result;
     }
 
     @Override
diff --git a/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java b/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java
index d6c804a..06ea212 100644
--- a/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java
+++ b/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java
@@ -41,6 +41,7 @@ import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextFactory;
 
 public class TestDefaultAccountUserApi extends AccountTestSuite {
+
     private final CallContextFactory factory = Mockito.mock(CallContextFactory.class);
     private final CallContext callContext = Mockito.mock(CallContext.class);
 
diff --git a/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
index 68e6796..fd82926 100644
--- a/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
@@ -30,12 +30,13 @@ import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.AccountData;
 import com.ning.billing.account.api.AccountEmail;
+import com.ning.billing.account.api.BillCycleDay;
 import com.ning.billing.account.api.DefaultAccount;
 import com.ning.billing.account.api.DefaultAccountEmail;
 import com.ning.billing.account.api.DefaultBillCycleDay;
+import com.ning.billing.account.api.MutableAccountData;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.mock.MockAccountBuilder;
-import com.ning.billing.mock.api.MockBillCycleDay;
 import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.customfield.CustomField;
 import com.ning.billing.util.customfield.StringCustomField;
@@ -55,8 +56,12 @@ import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
-@Test(groups = {"slow", "account-dao"})
 public class TestAccountDao extends AccountDaoTestBase {
+
+    private Account createTestAccount() {
+        return createTestAccount(5, UUID.randomUUID().toString().substring(0, 5));
+    }
+
     private Account createTestAccount(final int billCycleDay) {
         return createTestAccount(billCycleDay, "123-456-7890");
     }
@@ -77,7 +82,7 @@ public class TestAccountDao extends AccountDaoTestBase {
                                   phone, false, false);
     }
 
-    @Test
+    @Test(groups = "slow")
     public void testBasic() throws EntityPersistenceException {
         final Account a = createTestAccount(5);
         accountDao.create(a, context);
@@ -97,7 +102,7 @@ public class TestAccountDao extends AccountDaoTestBase {
     }
 
     // simple test to ensure long phone numbers can be stored
-    @Test
+    @Test(groups = "slow")
     public void testLongPhoneNumber() throws EntityPersistenceException {
         final Account account = createTestAccount(1, "123456789012345678901234");
         accountDao.create(account, context);
@@ -107,13 +112,13 @@ public class TestAccountDao extends AccountDaoTestBase {
     }
 
     // simple test to ensure excessively long phone numbers cannot be stored
-    @Test(expectedExceptions = {EntityPersistenceException.class})
+    @Test(groups = "slow", expectedExceptions = EntityPersistenceException.class)
     public void testOverlyLongPhoneNumber() throws EntityPersistenceException {
         final Account account = createTestAccount(1, "12345678901234567890123456");
         accountDao.create(account, context);
     }
 
-    @Test
+    @Test(groups = "slow")
     public void testGetById() throws EntityPersistenceException {
         Account account = createTestAccount(1);
         final UUID id = account.getId();
@@ -131,7 +136,7 @@ public class TestAccountDao extends AccountDaoTestBase {
         assertEquals(account.getFirstNameLength(), firstNameLength);
     }
 
-    @Test
+    @Test(groups = "slow")
     public void testCustomFields() throws EntityPersistenceException {
         final String fieldName = "testField1";
         final String fieldValue = "testField1_value";
@@ -149,7 +154,7 @@ public class TestAccountDao extends AccountDaoTestBase {
         assertEquals(customField.getValue(), fieldValue);
     }
 
-    @Test
+    @Test(groups = "slow")
     public void testTags() throws EntityPersistenceException, TagApiException {
         final Account account = createTestAccount(1);
         final TagDefinition definition = new DefaultTagDefinition("Test Tag", "For testing only", false);
@@ -165,7 +170,7 @@ public class TestAccountDao extends AccountDaoTestBase {
         assertEquals(tagMap.values().iterator().next().getTagDefinitionId(), definition.getId());
     }
 
-    @Test
+    @Test(groups = "slow")
     public void testGetIdFromKey() throws EntityPersistenceException {
         final Account account = createTestAccount(1);
         accountDao.create(account, context);
@@ -178,13 +183,13 @@ public class TestAccountDao extends AccountDaoTestBase {
         }
     }
 
-    @Test(expectedExceptions = AccountApiException.class)
+    @Test(groups = "slow", expectedExceptions = AccountApiException.class)
     public void testGetIdFromKeyForNullKey() throws AccountApiException {
         final String key = null;
         accountDao.getIdFromKey(key);
     }
 
-    @Test
+    @Test(groups = "slow")
     public void testUpdate() throws Exception {
         final Account account = createTestAccount(1);
         accountDao.create(account, context);
@@ -217,7 +222,7 @@ public class TestAccountDao extends AccountDaoTestBase {
         assertEquals(savedAccount.getPhone(), updatedAccount.getPhone());
     }
 
-    @Test
+    @Test(groups = "slow")
     public void testAddingContactInformation() throws Exception {
         final UUID accountId = UUID.randomUUID();
         final DefaultAccount account = new DefaultAccount(accountId, "extKey123456", "myemail123456@glam.com",
@@ -257,27 +262,65 @@ public class TestAccountDao extends AccountDaoTestBase {
         assertEquals(savedAccount.getPhone(), phone);
     }
 
-    @Test
-    public void testExternalKeyCannotBeUpdated() throws Exception {
-        final UUID accountId = UUID.randomUUID();
-        final String originalExternalKey = "extKey1337";
+    @Test(groups = "slow", expectedExceptions = IllegalArgumentException.class)
+    public void testShouldntBeAbleToUpdateExternalKey() throws Exception {
+        final Account account = createTestAccount();
+        accountDao.create(account, context);
 
-        final DefaultAccount account = new DefaultAccount(accountId, originalExternalKey, "myemail1337@glam.com",
-                                                          "John Smith", 4, Currency.USD, new DefaultBillCycleDay(15), null,
-                                                          null, null, null, null, null, null, null, null, null, null,
-                                                          false, false);
+        final MutableAccountData otherAccount = account.toMutableAccountData();
+        otherAccount.setExternalKey(UUID.randomUUID().toString());
+
+        accountDao.update(new DefaultAccount(account.getId(), otherAccount), context);
+    }
+
+    @Test(groups = "slow", expectedExceptions = IllegalArgumentException.class)
+    public void testShouldntBeAbleToUpdateCurrency() throws Exception {
+        final Account account = createTestAccount();
+        accountDao.create(account, context);
+
+        final MutableAccountData otherAccount = account.toMutableAccountData();
+        otherAccount.setCurrency(Currency.GBP);
+
+        accountDao.update(new DefaultAccount(account.getId(), otherAccount), context);
+    }
+
+    @Test(groups = "slow", expectedExceptions = IllegalArgumentException.class)
+    public void testShouldntBeAbleToUpdateBillCycleDay() throws Exception {
+        final Account account = createTestAccount();
         accountDao.create(account, context);
 
-        final String buggyKey = "extKey1338";
-        final DefaultAccount updatedAccountData = new DefaultAccount(accountId, buggyKey, "myemail1337@glam.com",
-                                                                     "John Smith", 4, Currency.USD, new DefaultBillCycleDay(15), null,
-                                                                     null, null, null, null, null, null, null, null, null, null,
-                                                                     false, false);
-        accountDao.update(updatedAccountData, context);
-        Assert.assertNull(accountDao.getAccountByKey(buggyKey));
+        final MutableAccountData otherAccount = account.toMutableAccountData();
+        otherAccount.setBillCycleDay(new BillCycleDay() {
+            @Override
+            public int getDayOfMonthUTC() {
+                return account.getBillCycleDay().getDayOfMonthUTC() + 2;
+            }
+
+            @Override
+            public int getDayOfMonthLocal() {
+                return account.getBillCycleDay().getDayOfMonthLocal() + 2;
+            }
+        });
+
+        accountDao.update(new DefaultAccount(account.getId(), otherAccount), context);
+    }
+
+    @Test(groups = "slow")
+    public void testShouldBeAbleToUpdateSomeFields() throws Exception {
+        final Account account = createTestAccount();
+        accountDao.create(account, context);
+
+        final MutableAccountData otherAccount = account.toMutableAccountData();
+        otherAccount.setAddress1(UUID.randomUUID().toString());
+        otherAccount.setEmail(UUID.randomUUID().toString());
+
+        final DefaultAccount newAccount = new DefaultAccount(account.getId(), otherAccount);
+        accountDao.update(newAccount, context);
+
+        Assert.assertEquals(accountDao.getById(account.getId()), newAccount);
     }
 
-    @Test
+    @Test(groups = "slow")
     public void testAccountEmail() {
         List<AccountEmail> emails = new ArrayList<AccountEmail>();
 
@@ -315,7 +358,7 @@ public class TestAccountDao extends AccountDaoTestBase {
         verifyAccountEmailAuditAndHistoryCount(accountId, 4);
     }
 
-    @Test
+    @Test(groups = "slow")
     public void testAddAndRemoveAccountEmail() {
         final UUID accountId = UUID.randomUUID();
         final String email1 = UUID.randomUUID().toString();