diff --git a/bubble-server/src/main/java/bubble/dao/account/AccountDAO.java b/bubble-server/src/main/java/bubble/dao/account/AccountDAO.java index 9f22eb2b..936198d7 100644 --- a/bubble-server/src/main/java/bubble/dao/account/AccountDAO.java +++ b/bubble-server/src/main/java/bubble/dao/account/AccountDAO.java @@ -319,11 +319,13 @@ public class AccountDAO extends AbstractCRUDDAO implements SqlViewSearc private static final AtomicBoolean unlocked = new AtomicBoolean(false); @Transactional(Transactional.TxType.REQUIRES_NEW) public boolean locked() { - if (unlocked.get()) return false; - // if any admins are unlocked, the bubble is unlocked - final boolean anyAdminUnlocked = !findByFields("admin", true, "locked", false).isEmpty(); - if (anyAdminUnlocked) unlocked.set(true); - return !anyAdminUnlocked; + synchronized (unlocked) { + if (unlocked.get()) return false; + // if any admins are unlocked, the bubble is unlocked + final boolean anyAdminUnlocked = !findByFields("admin", true, "locked", false).isEmpty(); + if (anyAdminUnlocked) unlocked.set(true); + return !anyAdminUnlocked; + } } // The admin with the lowest ctime is 'root' @@ -342,9 +344,17 @@ public class AccountDAO extends AbstractCRUDDAO implements SqlViewSearc return admins.get(0); } + @Transactional public void unlock() { - findAll().forEach(a -> update(a.setLocked(false))); - unlocked.set(true); + synchronized (unlocked) { + final List all = findAll(); + for (Account account : all) { + update(account.setLocked(false)); + } + log.info("unlock: " + all.size() + " accounts unlocked"); + unlocked.set(true); + configuration.refreshPublicSystemConfigs(); + } } } diff --git a/bubble-server/src/main/java/bubble/resources/account/AuthResource.java b/bubble-server/src/main/java/bubble/resources/account/AuthResource.java index c3bbd95b..52fbc903 100644 --- a/bubble-server/src/main/java/bubble/resources/account/AuthResource.java +++ b/bubble-server/src/main/java/bubble/resources/account/AuthResource.java @@ -219,15 +219,23 @@ public class AuthResource { boolean isUnlock = false; if (account.locked()) { - if (empty(unlockKey)) return invalid("err.account.locked"); - if (!unlockKey.equals(configuration.getUnlockKey())) return invalid("err.unlockKey.invalid"); - // unlock all accounts - isUnlock = true; - log.info("Unlock key was valid, unlocking accounts"); - accountDAO.unlock(); - - // refresh system configs, we are now unlocked - configuration.refreshPublicSystemConfigs(); + if (!accountDAO.locked()) { + log.info("login: account "+account.getName()+" was locked, but system is unlocked, unlocking again"); + accountDAO.unlock(); + final Account unlockedAccount = accountDAO.findByUuid(account.getUuid()); + if (unlockedAccount.locked()) { + log.info("login: account "+account.getName()+" was still locked after unlocking system, cannot proceed"); + return invalid("err.account.locked"); + } + + } else { + if (empty(unlockKey)) return invalid("err.account.locked"); + if (!unlockKey.equals(configuration.getUnlockKey())) return invalid("err.unlockKey.invalid"); + // unlock all accounts + isUnlock = true; + log.info("login: Unlock key was valid, unlocking accounts"); + accountDAO.unlock(); + } } if (!isUnlock) { diff --git a/bubble-server/src/main/java/bubble/server/listener/BubbleFirstTimeListener.java b/bubble-server/src/main/java/bubble/server/listener/BubbleFirstTimeListener.java index af520426..115dfb22 100644 --- a/bubble-server/src/main/java/bubble/server/listener/BubbleFirstTimeListener.java +++ b/bubble-server/src/main/java/bubble/server/listener/BubbleFirstTimeListener.java @@ -44,10 +44,10 @@ public class BubbleFirstTimeListener extends RestServerLifecycleListenerBase env = new HashMap<>(configuration.pgEnv()); diff --git a/bubble-web b/bubble-web index 239fdd08..5c987a87 160000 --- a/bubble-web +++ b/bubble-web @@ -1 +1 @@ -Subproject commit 239fdd0878a96e703e338377015a8a174afdfca1 +Subproject commit 5c987a87cbb00e7b750300feeac19e293dbafa3c