@@ -25,7 +25,7 @@ import bubble.resources.driver.DriversResource; | |||
import bubble.resources.notify.ReceivedNotificationsResource; | |||
import bubble.resources.notify.SentNotificationsResource; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.account.AuthenticatorService; | |||
import bubble.service.account.StandardAuthenticatorService; | |||
import bubble.service.account.MitmControlService; | |||
import bubble.service.account.download.AccountDownloadService; | |||
import bubble.service.boot.SelfNodeService; | |||
@@ -66,7 +66,7 @@ public class AccountsResource { | |||
@Autowired private AccountPolicyDAO policyDAO; | |||
@Autowired private AccountMessageDAO messageDAO; | |||
@Autowired private AccountDownloadService downloadService; | |||
@Autowired private AuthenticatorService authenticatorService; | |||
@Autowired private StandardAuthenticatorService authenticatorService; | |||
@Autowired private SelfNodeService selfNodeService; | |||
@Autowired private SessionDAO sessionDAO; | |||
@@ -19,7 +19,7 @@ import bubble.model.cloud.BubbleNode; | |||
import bubble.model.cloud.NetworkKeys; | |||
import bubble.model.cloud.notify.NotificationReceipt; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.account.AuthenticatorService; | |||
import bubble.service.account.StandardAuthenticatorService; | |||
import bubble.service.account.StandardAccountMessageService; | |||
import bubble.service.backup.RestoreService; | |||
import bubble.service.bill.PromotionService; | |||
@@ -80,7 +80,7 @@ public class AuthResource { | |||
@Autowired private BubblePlanDAO planDAO; | |||
@Autowired private BubbleNodeDAO nodeDAO; | |||
@Autowired private BubbleConfiguration configuration; | |||
@Autowired private AuthenticatorService authenticatorService; | |||
@Autowired private StandardAuthenticatorService authenticatorService; | |||
@Autowired private PromotionService promoService; | |||
public Account updateLastLogin(Account account) { return accountDAO.update(account.setLastLogin()); } | |||
@@ -25,7 +25,7 @@ import bubble.resources.driver.DriversResource; | |||
import bubble.resources.notify.ReceivedNotificationsResource; | |||
import bubble.resources.notify.SentNotificationsResource; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.account.AuthenticatorService; | |||
import bubble.service.account.StandardAuthenticatorService; | |||
import bubble.service.account.StandardAccountMessageService; | |||
import bubble.service.account.download.AccountDownloadService; | |||
import bubble.service.boot.BubbleModelSetupService; | |||
@@ -80,7 +80,7 @@ public class MeResource { | |||
@Autowired private SessionDAO sessionDAO; | |||
@Autowired private AccountDownloadService downloadService; | |||
@Autowired private BubbleConfiguration configuration; | |||
@Autowired private AuthenticatorService authenticatorService; | |||
@Autowired private StandardAuthenticatorService authenticatorService; | |||
@Autowired private AccountMessageDAO messageDAO; | |||
@GET | |||
@@ -26,7 +26,7 @@ import bubble.model.cloud.BubbleNetwork; | |||
import bubble.model.cloud.CloudService; | |||
import bubble.resources.account.AccountOwnedResource; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.account.AuthenticatorService; | |||
import bubble.service.account.StandardAuthenticatorService; | |||
import bubble.service.cloud.GeoService; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.wizard.validation.ValidationResult; | |||
@@ -60,7 +60,7 @@ public class AccountPlansResource extends AccountOwnedResource<AccountPlan, Acco | |||
@Autowired private CloudServiceDAO cloudDAO; | |||
@Autowired private AccountPaymentMethodDAO paymentMethodDAO; | |||
@Autowired private BubbleConfiguration configuration; | |||
@Autowired private AuthenticatorService authenticatorService; | |||
@Autowired private StandardAuthenticatorService authenticatorService; | |||
@Autowired private GeoService geoService; | |||
public AccountPlansResource(Account account) { super(account); } | |||
@@ -19,7 +19,7 @@ import bubble.model.account.message.ActionTarget; | |||
import bubble.model.bill.AccountPlan; | |||
import bubble.model.cloud.*; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.account.AuthenticatorService; | |||
import bubble.service.account.StandardAuthenticatorService; | |||
import bubble.service.backup.NetworkKeysService; | |||
import bubble.service.cloud.NodeProgressMeterTick; | |||
import bubble.service.cloud.StandardNetworkService; | |||
@@ -56,7 +56,7 @@ public class NetworkActionsResource { | |||
@Autowired private BubbleNetworkDAO networkDAO; | |||
@Autowired private AccountPlanDAO accountPlanDAO; | |||
@Autowired private BubbleConfiguration configuration; | |||
@Autowired private AuthenticatorService authenticatorService; | |||
@Autowired private StandardAuthenticatorService authenticatorService; | |||
private Account account; | |||
private BubbleNetwork network; | |||
@@ -1,101 +1,9 @@ | |||
/** | |||
* Copyright (c) 2020 Bubble, Inc. All rights reserved. | |||
* For personal (non-commercial) use, see license: https://bubblev.com/bubble-license/ | |||
*/ | |||
package bubble.service.account; | |||
import bubble.dao.SessionDAO; | |||
import bubble.dao.account.AccountPolicyDAO; | |||
import bubble.model.account.Account; | |||
import bubble.model.account.AccountContact; | |||
import bubble.model.account.AccountPolicy; | |||
import bubble.model.account.AuthenticatorRequest; | |||
import bubble.model.account.message.ActionTarget; | |||
import lombok.Getter; | |||
import org.cobbzilla.wizard.cache.redis.RedisService; | |||
import org.glassfish.jersey.server.ContainerRequest; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.stereotype.Service; | |||
import static bubble.ApiConstants.G_AUTH; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.now; | |||
import static org.cobbzilla.wizard.cache.redis.RedisService.EX; | |||
import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; | |||
import static org.cobbzilla.wizard.resources.ResourceUtil.userPrincipal; | |||
@Service | |||
public class AuthenticatorService { | |||
@Autowired private SessionDAO sessionDAO; | |||
@Autowired private AccountPolicyDAO policyDAO; | |||
@Autowired private RedisService redis; | |||
@Getter(lazy=true) private final RedisService authenticatorTimes = redis.prefixNamespace(getClass().getSimpleName()+"_authentications"); | |||
public String authenticate (Account account, AccountPolicy policy, AuthenticatorRequest request) { | |||
final AccountContact authenticator = policy.getAuthenticator(); | |||
if (authenticator == null) throw invalidEx("err.authenticator.notConfigured"); | |||
final Integer code = request.intToken(); | |||
if (code == null) throw invalidEx("err.totpToken.invalid"); | |||
final String secret = authenticator.totpInfo().getKey(); | |||
if (G_AUTH.authorize(secret, code)) { | |||
final String sessionToken = request.startSession() ? sessionDAO.create(account) : account.getToken(); | |||
if (sessionToken == null && request.startSession()) throw invalidEx("err.totpToken.noSession"); | |||
if (sessionToken != null) { | |||
markAsAuthenticated(sessionToken, policy); | |||
return sessionToken; | |||
} | |||
return null; | |||
} else { | |||
throw invalidEx("err.totpToken.invalid"); | |||
} | |||
} | |||
public void markAsAuthenticated(String sessionToken, AccountPolicy policy) { | |||
getAuthenticatorTimes().set(sessionToken, String.valueOf(now()), EX, policy.getAuthenticatorTimeout()/1000); | |||
} | |||
public boolean isAuthenticated (String sessionToken) { return getAuthenticatorTimes().get(sessionToken) != null; } | |||
public void ensureAuthenticated(ContainerRequest ctx) { ensureAuthenticated(ctx, null); } | |||
public void ensureAuthenticated(ContainerRequest ctx, ActionTarget target) { | |||
final Account account = userPrincipal(ctx); | |||
final AccountPolicy policy = policyDAO.findSingleByAccount(account.getUuid()); | |||
ensureAuthenticated(account, policy, target); | |||
} | |||
public void ensureAuthenticated(ContainerRequest ctx, AccountPolicy policy, ActionTarget target) { | |||
final Account account = userPrincipal(ctx); | |||
ensureAuthenticated(account, policy, target); | |||
} | |||
public void ensureAuthenticated(Account account, AccountPolicy policy, ActionTarget target) { | |||
if (policy == null || !policy.hasVerifiedAuthenticator()) return; | |||
if (target != null) { | |||
final AccountContact authenticator = policy.getAuthenticator(); | |||
switch (target) { | |||
case account: if (!authenticator.requiredForAccountOperations()) return; break; | |||
case network: if (!authenticator.requiredForNetworkOperations()) return; break; | |||
default: throw invalidEx("err.actionTarget.invalid"); | |||
} | |||
} | |||
if (!isAuthenticated(account.getToken())) throw invalidEx("err.totpToken.invalid"); | |||
} | |||
public boolean flush(String sessionToken) { | |||
final String exists = getAuthenticatorTimes().get(sessionToken); | |||
getAuthenticatorTimes().del(sessionToken); | |||
return exists != null; | |||
} | |||
public void updateExpiration(ContainerRequest ctx, AccountPolicy policy) { | |||
final Account account = userPrincipal(ctx); | |||
final String sessionToken = account.getToken(); | |||
if (flush(sessionToken)) { | |||
markAsAuthenticated(sessionToken, policy); | |||
} | |||
} | |||
public interface AuthenticatorService { | |||
String authenticate(Account account, AccountPolicy policy, AuthenticatorRequest setToken); | |||
} |
@@ -0,0 +1,101 @@ | |||
/** | |||
* Copyright (c) 2020 Bubble, Inc. All rights reserved. | |||
* For personal (non-commercial) use, see license: https://bubblev.com/bubble-license/ | |||
*/ | |||
package bubble.service.account; | |||
import bubble.dao.SessionDAO; | |||
import bubble.dao.account.AccountPolicyDAO; | |||
import bubble.model.account.Account; | |||
import bubble.model.account.AccountContact; | |||
import bubble.model.account.AccountPolicy; | |||
import bubble.model.account.AuthenticatorRequest; | |||
import bubble.model.account.message.ActionTarget; | |||
import lombok.Getter; | |||
import org.cobbzilla.wizard.cache.redis.RedisService; | |||
import org.glassfish.jersey.server.ContainerRequest; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.stereotype.Service; | |||
import static bubble.ApiConstants.G_AUTH; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.now; | |||
import static org.cobbzilla.wizard.cache.redis.RedisService.EX; | |||
import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; | |||
import static org.cobbzilla.wizard.resources.ResourceUtil.userPrincipal; | |||
@Service | |||
public class StandardAuthenticatorService implements AuthenticatorService { | |||
@Autowired private SessionDAO sessionDAO; | |||
@Autowired private AccountPolicyDAO policyDAO; | |||
@Autowired private RedisService redis; | |||
@Getter(lazy=true) private final RedisService authenticatorTimes = redis.prefixNamespace(getClass().getSimpleName()+"_authentications"); | |||
public String authenticate (Account account, AccountPolicy policy, AuthenticatorRequest request) { | |||
final AccountContact authenticator = policy.getAuthenticator(); | |||
if (authenticator == null) throw invalidEx("err.authenticator.notConfigured"); | |||
final Integer code = request.intToken(); | |||
if (code == null) throw invalidEx("err.totpToken.invalid"); | |||
final String secret = authenticator.totpInfo().getKey(); | |||
if (G_AUTH.authorize(secret, code)) { | |||
final String sessionToken = request.startSession() ? sessionDAO.create(account) : account.getToken(); | |||
if (sessionToken == null && request.startSession()) throw invalidEx("err.totpToken.noSession"); | |||
if (sessionToken != null) { | |||
markAsAuthenticated(sessionToken, policy); | |||
return sessionToken; | |||
} | |||
return null; | |||
} else { | |||
throw invalidEx("err.totpToken.invalid"); | |||
} | |||
} | |||
public void markAsAuthenticated(String sessionToken, AccountPolicy policy) { | |||
getAuthenticatorTimes().set(sessionToken, String.valueOf(now()), EX, policy.getAuthenticatorTimeout()/1000); | |||
} | |||
public boolean isAuthenticated (String sessionToken) { return getAuthenticatorTimes().get(sessionToken) != null; } | |||
public void ensureAuthenticated(ContainerRequest ctx) { ensureAuthenticated(ctx, null); } | |||
public void ensureAuthenticated(ContainerRequest ctx, ActionTarget target) { | |||
final Account account = userPrincipal(ctx); | |||
final AccountPolicy policy = policyDAO.findSingleByAccount(account.getUuid()); | |||
ensureAuthenticated(account, policy, target); | |||
} | |||
public void ensureAuthenticated(ContainerRequest ctx, AccountPolicy policy, ActionTarget target) { | |||
final Account account = userPrincipal(ctx); | |||
ensureAuthenticated(account, policy, target); | |||
} | |||
public void ensureAuthenticated(Account account, AccountPolicy policy, ActionTarget target) { | |||
if (policy == null || !policy.hasVerifiedAuthenticator()) return; | |||
if (target != null) { | |||
final AccountContact authenticator = policy.getAuthenticator(); | |||
switch (target) { | |||
case account: if (!authenticator.requiredForAccountOperations()) return; break; | |||
case network: if (!authenticator.requiredForNetworkOperations()) return; break; | |||
default: throw invalidEx("err.actionTarget.invalid"); | |||
} | |||
} | |||
if (!isAuthenticated(account.getToken())) throw invalidEx("err.totpToken.invalid"); | |||
} | |||
public boolean flush(String sessionToken) { | |||
final String exists = getAuthenticatorTimes().get(sessionToken); | |||
getAuthenticatorTimes().del(sessionToken); | |||
return exists != null; | |||
} | |||
public void updateExpiration(ContainerRequest ctx, AccountPolicy policy) { | |||
final Account account = userPrincipal(ctx); | |||
final String sessionToken = account.getToken(); | |||
if (flush(sessionToken)) { | |||
markAsAuthenticated(sessionToken, policy); | |||
} | |||
} | |||
} |
@@ -0,0 +1,18 @@ | |||
package bubble.service_dbfilter; | |||
import bubble.model.account.Account; | |||
import bubble.model.account.AccountPolicy; | |||
import bubble.model.account.AuthenticatorRequest; | |||
import bubble.service.account.AuthenticatorService; | |||
import org.springframework.stereotype.Service; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.notSupported; | |||
@Service | |||
public class DbFilterAuthenticatorService implements AuthenticatorService { | |||
@Override public String authenticate(Account account, AccountPolicy policy, AuthenticatorRequest setToken) { | |||
return notSupported("authenticate"); | |||
} | |||
} |