Refactoring
This commit is contained in:
parent
215a44b7c7
commit
6d34aa237c
@ -43,6 +43,8 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
|
|||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.security.UserCredentials;
|
import org.thingsboard.server.common.data.security.UserCredentials;
|
||||||
import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent;
|
import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent;
|
||||||
|
import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent;
|
||||||
|
import org.thingsboard.server.common.data.security.event.UserSessionInvalidationEvent;
|
||||||
import org.thingsboard.server.common.data.security.model.SecuritySettings;
|
import org.thingsboard.server.common.data.security.model.SecuritySettings;
|
||||||
import org.thingsboard.server.common.data.security.model.UserPasswordPolicy;
|
import org.thingsboard.server.common.data.security.model.UserPasswordPolicy;
|
||||||
import org.thingsboard.server.dao.audit.AuditLogService;
|
import org.thingsboard.server.dao.audit.AuditLogService;
|
||||||
@ -125,7 +127,7 @@ public class AuthController extends BaseController {
|
|||||||
|
|
||||||
sendEntityNotificationMsg(getTenantId(), userCredentials.getUserId(), EdgeEventActionType.CREDENTIALS_UPDATED);
|
sendEntityNotificationMsg(getTenantId(), userCredentials.getUserId(), EdgeEventActionType.CREDENTIALS_UPDATED);
|
||||||
|
|
||||||
eventPublisher.publishEvent(new UserAuthDataChangedEvent(securityUser.getId(), securityUser.getSessionId(), false));
|
eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(securityUser.getId()));
|
||||||
ObjectNode response = JacksonUtil.newObjectNode();
|
ObjectNode response = JacksonUtil.newObjectNode();
|
||||||
response.put("token", tokenFactory.createAccessJwtToken(securityUser).getToken());
|
response.put("token", tokenFactory.createAccessJwtToken(securityUser).getToken());
|
||||||
response.put("refreshToken", tokenFactory.createRefreshToken(securityUser).getToken());
|
response.put("refreshToken", tokenFactory.createRefreshToken(securityUser).getToken());
|
||||||
@ -303,7 +305,7 @@ public class AuthController extends BaseController {
|
|||||||
String email = user.getEmail();
|
String email = user.getEmail();
|
||||||
mailService.sendPasswordWasResetEmail(loginUrl, email);
|
mailService.sendPasswordWasResetEmail(loginUrl, email);
|
||||||
|
|
||||||
eventPublisher.publishEvent(new UserAuthDataChangedEvent(securityUser.getId(), securityUser.getSessionId(), false));
|
eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(securityUser.getId()));
|
||||||
|
|
||||||
return tokenFactory.createTokenPair(securityUser);
|
return tokenFactory.createTokenPair(securityUser);
|
||||||
} else {
|
} else {
|
||||||
@ -359,7 +361,7 @@ public class AuthController extends BaseController {
|
|||||||
user.getTenantId(), user.getCustomerId(), user.getId(),
|
user.getTenantId(), user.getCustomerId(), user.getId(),
|
||||||
user.getName(), user.getId(), null, ActionType.LOGOUT, null, clientAddress, browser, os, device);
|
user.getName(), user.getId(), null, ActionType.LOGOUT, null, clientAddress, browser, os, device);
|
||||||
|
|
||||||
eventPublisher.publishEvent(new UserAuthDataChangedEvent(user.getId(), user.getSessionId(), false));
|
eventPublisher.publishEvent(new UserSessionInvalidationEvent(user.getSessionId()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw handleException(e);
|
throw handleException(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.page.PageLink;
|
|||||||
import org.thingsboard.server.common.data.security.Authority;
|
import org.thingsboard.server.common.data.security.Authority;
|
||||||
import org.thingsboard.server.common.data.security.UserCredentials;
|
import org.thingsboard.server.common.data.security.UserCredentials;
|
||||||
import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent;
|
import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent;
|
||||||
|
import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent;
|
||||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||||
import org.thingsboard.server.service.entitiy.user.TbUserService;
|
import org.thingsboard.server.service.entitiy.user.TbUserService;
|
||||||
import org.thingsboard.server.service.security.model.JwtTokenPair;
|
import org.thingsboard.server.service.security.model.JwtTokenPair;
|
||||||
@ -371,7 +372,7 @@ public class UserController extends BaseController {
|
|||||||
userService.setUserCredentialsEnabled(tenantId, userId, userCredentialsEnabled);
|
userService.setUserCredentialsEnabled(tenantId, userId, userCredentialsEnabled);
|
||||||
|
|
||||||
if (!userCredentialsEnabled) {
|
if (!userCredentialsEnabled) {
|
||||||
eventPublisher.publishEvent(new UserAuthDataChangedEvent(userId, null, true));
|
eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(userId));
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw handleException(e);
|
throw handleException(e);
|
||||||
|
|||||||
@ -19,16 +19,14 @@ import io.jsonwebtoken.Claims;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.event.TransactionalEventListener;
|
import org.thingsboard.server.cache.TbCacheValueWrapper;
|
||||||
import org.thingsboard.server.cache.usersUpdateTime.UsersUpdateTimeCacheEvictEvent;
|
import org.thingsboard.server.cache.TbTransactionalCache;
|
||||||
import org.thingsboard.server.common.data.id.UserId;
|
import org.thingsboard.server.common.data.id.UserId;
|
||||||
import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent;
|
import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent;
|
||||||
import org.thingsboard.server.common.data.security.model.JwtToken;
|
import org.thingsboard.server.common.data.security.model.JwtToken;
|
||||||
import org.thingsboard.server.config.JwtSettings;
|
import org.thingsboard.server.config.JwtSettings;
|
||||||
import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
|
|
||||||
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
|
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
@ -36,13 +34,14 @@ import static java.util.concurrent.TimeUnit.SECONDS;
|
|||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class TokenOutdatingService extends AbstractCachedEntityService<UserId, HashMap<String, Long>, UsersUpdateTimeCacheEvictEvent> {
|
public class TokenOutdatingService {
|
||||||
|
private final TbTransactionalCache<String, Long> cache;
|
||||||
private final JwtTokenFactory tokenFactory;
|
private final JwtTokenFactory tokenFactory;
|
||||||
private final JwtSettings jwtSettings;
|
private final JwtSettings jwtSettings;
|
||||||
|
|
||||||
@EventListener(classes = UserAuthDataChangedEvent.class)
|
@EventListener(classes = UserAuthDataChangedEvent.class)
|
||||||
public void onUserAuthDataChanged(UserAuthDataChangedEvent event) {
|
public void onUserAuthDataChanged(UserAuthDataChangedEvent event) {
|
||||||
processUserSessions(event);
|
cache.put(event.getId(), event.getTs());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOutdated(JwtToken token, UserId userId) {
|
public boolean isOutdated(JwtToken token, UserId userId) {
|
||||||
@ -50,48 +49,36 @@ public class TokenOutdatingService extends AbstractCachedEntityService<UserId, H
|
|||||||
long issueTime = claims.getIssuedAt().getTime();
|
long issueTime = claims.getIssuedAt().getTime();
|
||||||
|
|
||||||
String sessionId = claims.get("sessionId", String.class);
|
String sessionId = claims.get("sessionId", String.class);
|
||||||
return Optional.ofNullable(cache.get(userId))
|
|
||||||
.map(outdatageTime -> {
|
Boolean isUserIdOutdated = Optional.ofNullable(cache.get(userId.toString()))
|
||||||
if (outdatageTime.get().get(sessionId) != null && System.currentTimeMillis() - outdatageTime.get().get(sessionId) <= SECONDS.toMillis(jwtSettings.getRefreshTokenExpTime())) {
|
.map(outdatageTimeByUserId -> {
|
||||||
return MILLISECONDS.toSeconds(issueTime) < MILLISECONDS.toSeconds(outdatageTime.get().get(sessionId));
|
if (refreshTokenNotExpired(outdatageTimeByUserId.get(), System.currentTimeMillis())) {
|
||||||
|
return accessTokenNotExpired(issueTime, outdatageTimeByUserId.get());
|
||||||
} else {
|
} else {
|
||||||
/*
|
|
||||||
* Means that since the outdating has passed more than
|
|
||||||
* the lifetime of refresh token (the longest lived)
|
|
||||||
* and there is no need to store outdatage time anymore
|
|
||||||
* as all the tokens issued before the outdatage time
|
|
||||||
* are now expired by themselves
|
|
||||||
* */
|
|
||||||
handleEvictEvent(new UsersUpdateTimeCacheEvictEvent(userId, sessionId));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.orElse(false);
|
.orElse(false);
|
||||||
|
|
||||||
|
if (!isUserIdOutdated) {
|
||||||
|
return Optional.ofNullable(cache.get(sessionId)).map(outdatageTimeBySessionId -> {
|
||||||
|
if (refreshTokenNotExpired(outdatageTimeBySessionId.get(), System.currentTimeMillis())) {
|
||||||
|
return accessTokenNotExpired(issueTime, outdatageTimeBySessionId.get());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TransactionalEventListener(classes = UsersUpdateTimeCacheEvictEvent.class)
|
return isUserIdOutdated;
|
||||||
@Override
|
|
||||||
public void handleEvictEvent(UsersUpdateTimeCacheEvictEvent event) {
|
|
||||||
HashMap<String, Long> userSessions = cache.get(event.getUserId()).get();
|
|
||||||
if (userSessions != null) {
|
|
||||||
userSessions.remove(event.getSessionId());
|
|
||||||
cache.put(event.getUserId(), userSessions);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processUserSessions(UserAuthDataChangedEvent event) {
|
private boolean accessTokenNotExpired(long issueTime, Long outdatageTime) {
|
||||||
if (cache.get(event.getUserId()) != null) {
|
return MILLISECONDS.toSeconds(issueTime) < MILLISECONDS.toSeconds(outdatageTime);
|
||||||
HashMap<String, Long> userSessions = cache.get(event.getUserId()).get();
|
|
||||||
if (event.isDropAllSessions()) {
|
|
||||||
userSessions.replaceAll((k, v) -> event.getTs());
|
|
||||||
} else {
|
|
||||||
userSessions.put(event.getSessionId(), event.getTs());
|
|
||||||
}
|
|
||||||
cache.put(event.getUserId(), userSessions);
|
|
||||||
} else {
|
|
||||||
cache.put(event.getUserId(), new HashMap<>() {{
|
|
||||||
put(event.getSessionId(), event.getTs());
|
|
||||||
}});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean refreshTokenNotExpired(Long outdatageTime, long currentTime) {
|
||||||
|
return currentTime - outdatageTime <= SECONDS.toMillis(jwtSettings.getRefreshTokenExpTime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,7 +66,7 @@ public class RefreshTokenAuthenticationProvider implements AuthenticationProvide
|
|||||||
} else {
|
} else {
|
||||||
securityUser = authenticateByPublicId(principal.getValue());
|
securityUser = authenticateByPublicId(principal.getValue());
|
||||||
}
|
}
|
||||||
|
securityUser.setSessionId(unsafeUser.getSessionId());
|
||||||
if (tokenOutdatingService.isOutdated(rawAccessToken, securityUser.getId())) {
|
if (tokenOutdatingService.isOutdated(rawAccessToken, securityUser.getId())) {
|
||||||
throw new CredentialsExpiredException("Token is outdated");
|
throw new CredentialsExpiredException("Token is outdated");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -120,7 +120,9 @@ public class JwtTokenFactory {
|
|||||||
if (customerId != null) {
|
if (customerId != null) {
|
||||||
securityUser.setCustomerId(new CustomerId(UUID.fromString(customerId)));
|
securityUser.setCustomerId(new CustomerId(UUID.fromString(customerId)));
|
||||||
}
|
}
|
||||||
|
if (claims.get(SESSION_ID, String.class) != null) {
|
||||||
securityUser.setSessionId(claims.get(SESSION_ID, String.class));
|
securityUser.setSessionId(claims.get(SESSION_ID, String.class));
|
||||||
|
}
|
||||||
|
|
||||||
UserPrincipal principal;
|
UserPrincipal principal;
|
||||||
if (securityUser.getAuthority() != Authority.PRE_VERIFICATION_TOKEN) {
|
if (securityUser.getAuthority() != Authority.PRE_VERIFICATION_TOKEN) {
|
||||||
@ -163,7 +165,9 @@ public class JwtTokenFactory {
|
|||||||
UserPrincipal principal = new UserPrincipal(isPublic ? UserPrincipal.Type.PUBLIC_ID : UserPrincipal.Type.USER_NAME, subject);
|
UserPrincipal principal = new UserPrincipal(isPublic ? UserPrincipal.Type.PUBLIC_ID : UserPrincipal.Type.USER_NAME, subject);
|
||||||
SecurityUser securityUser = new SecurityUser(new UserId(UUID.fromString(claims.get(USER_ID, String.class))));
|
SecurityUser securityUser = new SecurityUser(new UserId(UUID.fromString(claims.get(USER_ID, String.class))));
|
||||||
securityUser.setUserPrincipal(principal);
|
securityUser.setUserPrincipal(principal);
|
||||||
|
if (claims.get(SESSION_ID, String.class) != null) {
|
||||||
securityUser.setSessionId(claims.get(SESSION_ID, String.class));
|
securityUser.setSessionId(claims.get(SESSION_ID, String.class));
|
||||||
|
}
|
||||||
return securityUser;
|
return securityUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,6 +33,8 @@ import org.thingsboard.server.common.data.id.UserId;
|
|||||||
import org.thingsboard.server.common.data.security.Authority;
|
import org.thingsboard.server.common.data.security.Authority;
|
||||||
import org.thingsboard.server.common.data.security.UserCredentials;
|
import org.thingsboard.server.common.data.security.UserCredentials;
|
||||||
import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent;
|
import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent;
|
||||||
|
import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent;
|
||||||
|
import org.thingsboard.server.common.data.security.event.UserSessionInvalidationEvent;
|
||||||
import org.thingsboard.server.common.data.security.model.JwtToken;
|
import org.thingsboard.server.common.data.security.model.JwtToken;
|
||||||
import org.thingsboard.server.dao.customer.CustomerService;
|
import org.thingsboard.server.dao.customer.CustomerService;
|
||||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||||
@ -106,7 +108,7 @@ public class TokenOutdatingTest {
|
|||||||
JwtToken jwtToken = tokenFactory.createAccessJwtToken(securityUser);
|
JwtToken jwtToken = tokenFactory.createAccessJwtToken(securityUser);
|
||||||
|
|
||||||
SECONDS.sleep(1); // need to wait before outdating so that outdatage time is strictly after token issue time
|
SECONDS.sleep(1); // need to wait before outdating so that outdatage time is strictly after token issue time
|
||||||
tokenOutdatingService.onUserAuthDataChanged(new UserAuthDataChangedEvent(securityUser.getId(), securityUser.getSessionId(), false));
|
tokenOutdatingService.onUserAuthDataChanged(new UserCredentialsInvalidationEvent(securityUser.getId()));
|
||||||
assertTrue(tokenOutdatingService.isOutdated(jwtToken, securityUser.getId()));
|
assertTrue(tokenOutdatingService.isOutdated(jwtToken, securityUser.getId()));
|
||||||
|
|
||||||
SECONDS.sleep(1);
|
SECONDS.sleep(1);
|
||||||
@ -124,7 +126,7 @@ public class TokenOutdatingTest {
|
|||||||
});
|
});
|
||||||
|
|
||||||
SECONDS.sleep(1);
|
SECONDS.sleep(1);
|
||||||
tokenOutdatingService.onUserAuthDataChanged(new UserAuthDataChangedEvent(securityUser.getId(), securityUser.getSessionId(), false));
|
tokenOutdatingService.onUserAuthDataChanged(new UserCredentialsInvalidationEvent(securityUser.getId()));
|
||||||
|
|
||||||
assertThrows(JwtExpiredTokenException.class, () -> {
|
assertThrows(JwtExpiredTokenException.class, () -> {
|
||||||
accessTokenAuthenticationProvider.authenticate(new JwtAuthenticationToken(accessJwtToken));
|
accessTokenAuthenticationProvider.authenticate(new JwtAuthenticationToken(accessJwtToken));
|
||||||
@ -140,7 +142,7 @@ public class TokenOutdatingTest {
|
|||||||
});
|
});
|
||||||
|
|
||||||
SECONDS.sleep(1);
|
SECONDS.sleep(1);
|
||||||
tokenOutdatingService.onUserAuthDataChanged(new UserAuthDataChangedEvent(securityUser.getId(), securityUser.getSessionId(), false));
|
tokenOutdatingService.onUserAuthDataChanged(new UserCredentialsInvalidationEvent(securityUser.getId()));
|
||||||
|
|
||||||
assertThrows(CredentialsExpiredException.class, () -> {
|
assertThrows(CredentialsExpiredException.class, () -> {
|
||||||
refreshTokenAuthenticationProvider.authenticate(new RefreshAuthenticationToken(refreshJwtToken));
|
refreshTokenAuthenticationProvider.authenticate(new RefreshAuthenticationToken(refreshJwtToken));
|
||||||
@ -152,7 +154,7 @@ public class TokenOutdatingTest {
|
|||||||
JwtToken jwtToken = tokenFactory.createAccessJwtToken(securityUser);
|
JwtToken jwtToken = tokenFactory.createAccessJwtToken(securityUser);
|
||||||
|
|
||||||
SECONDS.sleep(1);
|
SECONDS.sleep(1);
|
||||||
tokenOutdatingService.onUserAuthDataChanged(new UserAuthDataChangedEvent(securityUser.getId(), securityUser.getSessionId(), false));
|
tokenOutdatingService.onUserAuthDataChanged(new UserCredentialsInvalidationEvent(securityUser.getId()));
|
||||||
|
|
||||||
SECONDS.sleep(1);
|
SECONDS.sleep(1);
|
||||||
|
|
||||||
@ -175,7 +177,8 @@ public class TokenOutdatingTest {
|
|||||||
});
|
});
|
||||||
|
|
||||||
SECONDS.sleep(1);
|
SECONDS.sleep(1);
|
||||||
tokenOutdatingService.onUserAuthDataChanged(new UserAuthDataChangedEvent(securityUser.getId(), securityUser.getSessionId(), false));
|
|
||||||
|
tokenOutdatingService.onUserAuthDataChanged(new UserSessionInvalidationEvent(securityUser.getSessionId()));
|
||||||
|
|
||||||
assertThrows(JwtExpiredTokenException.class, () -> {
|
assertThrows(JwtExpiredTokenException.class, () -> {
|
||||||
accessTokenAuthenticationProvider.authenticate(new JwtAuthenticationToken(getRawJwtToken(jwtToken)));
|
accessTokenAuthenticationProvider.authenticate(new JwtAuthenticationToken(getRawJwtToken(jwtToken)));
|
||||||
@ -186,6 +189,34 @@ public class TokenOutdatingTest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResetAllSessions() throws InterruptedException {
|
||||||
|
JwtToken jwtToken = tokenFactory.createAccessJwtToken(securityUser);
|
||||||
|
|
||||||
|
SecurityUser anotherSecurityUser = new SecurityUser(securityUser, securityUser.isEnabled(), securityUser.getUserPrincipal());
|
||||||
|
JwtToken anotherJwtToken = tokenFactory.createAccessJwtToken(anotherSecurityUser);
|
||||||
|
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
accessTokenAuthenticationProvider.authenticate(new JwtAuthenticationToken(getRawJwtToken(jwtToken)));
|
||||||
|
});
|
||||||
|
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
accessTokenAuthenticationProvider.authenticate(new JwtAuthenticationToken(getRawJwtToken(anotherJwtToken)));
|
||||||
|
});
|
||||||
|
|
||||||
|
SECONDS.sleep(1);
|
||||||
|
|
||||||
|
tokenOutdatingService.onUserAuthDataChanged(new UserCredentialsInvalidationEvent(securityUser.getId()));
|
||||||
|
|
||||||
|
assertThrows(JwtExpiredTokenException.class, () -> {
|
||||||
|
accessTokenAuthenticationProvider.authenticate(new JwtAuthenticationToken(getRawJwtToken(jwtToken)));
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThrows(JwtExpiredTokenException.class, () -> {
|
||||||
|
accessTokenAuthenticationProvider.authenticate(new JwtAuthenticationToken(getRawJwtToken(anotherJwtToken)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private RawAccessJwtToken getRawJwtToken(JwtToken token) {
|
private RawAccessJwtToken getRawJwtToken(JwtToken token) {
|
||||||
return new RawAccessJwtToken(token.getToken());
|
return new RawAccessJwtToken(token.getToken());
|
||||||
|
|||||||
@ -24,13 +24,10 @@ import org.thingsboard.server.cache.RedisTbTransactionalCache;
|
|||||||
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
|
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
|
||||||
import org.thingsboard.server.cache.TbFSTRedisSerializer;
|
import org.thingsboard.server.cache.TbFSTRedisSerializer;
|
||||||
import org.thingsboard.server.common.data.CacheConstants;
|
import org.thingsboard.server.common.data.CacheConstants;
|
||||||
import org.thingsboard.server.common.data.id.UserId;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
|
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
|
||||||
@Service("UsersUpdateTimeCache")
|
@Service("UsersUpdateTimeCache")
|
||||||
public class UserUpdateTimeRedisCache extends RedisTbTransactionalCache<UserId, HashMap<String, Long>> {
|
public class UserUpdateTimeRedisCache extends RedisTbTransactionalCache<String, Long> {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public UserUpdateTimeRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
|
public UserUpdateTimeRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
|
||||||
|
|||||||
@ -16,10 +16,8 @@
|
|||||||
package org.thingsboard.server.cache.usersUpdateTime;
|
package org.thingsboard.server.cache.usersUpdateTime;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.thingsboard.server.common.data.id.UserId;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class UsersUpdateTimeCacheEvictEvent {
|
public class UsersUpdateTimeCacheEvictEvent {
|
||||||
private final UserId userId;
|
private final String key;
|
||||||
private final String sessionId;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,14 +21,11 @@ import org.springframework.cache.CacheManager;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
|
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
|
||||||
import org.thingsboard.server.common.data.CacheConstants;
|
import org.thingsboard.server.common.data.CacheConstants;
|
||||||
import org.thingsboard.server.common.data.id.UserId;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
|
|
||||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
|
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
|
||||||
@Service("UsersUpdateTimeCache")
|
@Service("UsersUpdateTimeCache")
|
||||||
public class UsersUpdateTimeCaffeineCache extends CaffeineTbTransactionalCache<UserId, HashMap<String, Long>> {
|
public class UsersUpdateTimeCaffeineCache extends CaffeineTbTransactionalCache<String, Long> {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public UsersUpdateTimeCaffeineCache(CacheManager cacheManager) {
|
public UsersUpdateTimeCaffeineCache(CacheManager cacheManager) {
|
||||||
|
|||||||
@ -20,18 +20,7 @@ import org.thingsboard.server.common.data.id.UserId;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
@Data
|
public abstract class UserAuthDataChangedEvent implements Serializable {
|
||||||
public class UserAuthDataChangedEvent implements Serializable {
|
public abstract String getId();
|
||||||
private final UserId userId;
|
public abstract long getTs();
|
||||||
private final String sessionId;
|
|
||||||
private final long ts;
|
|
||||||
private final boolean dropAllSessions;
|
|
||||||
|
|
||||||
public UserAuthDataChangedEvent(UserId userId, String sessionId, boolean dropAllSessions) {
|
|
||||||
this.userId = userId;
|
|
||||||
this.sessionId = sessionId;
|
|
||||||
this.dropAllSessions = dropAllSessions;
|
|
||||||
this.ts = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2022 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.common.data.security.event;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.thingsboard.server.common.data.id.UserId;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class UserCredentialsInvalidationEvent extends UserAuthDataChangedEvent {
|
||||||
|
private final UserId userId;
|
||||||
|
private final long ts;
|
||||||
|
|
||||||
|
public UserCredentialsInvalidationEvent(UserId userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
this.ts = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return userId.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTs() {
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2022 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.common.data.security.event;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class UserSessionInvalidationEvent extends UserAuthDataChangedEvent {
|
||||||
|
private final String sessionId;
|
||||||
|
private final long ts;
|
||||||
|
|
||||||
|
public UserSessionInvalidationEvent(String sessionId) {
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
this.ts = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTs() {
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.page.PageData;
|
|||||||
import org.thingsboard.server.common.data.page.PageLink;
|
import org.thingsboard.server.common.data.page.PageLink;
|
||||||
import org.thingsboard.server.common.data.security.UserCredentials;
|
import org.thingsboard.server.common.data.security.UserCredentials;
|
||||||
import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent;
|
import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent;
|
||||||
|
import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent;
|
||||||
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
||||||
import org.thingsboard.server.dao.exception.IncorrectParameterException;
|
import org.thingsboard.server.dao.exception.IncorrectParameterException;
|
||||||
import org.thingsboard.server.dao.service.DataValidator;
|
import org.thingsboard.server.dao.service.DataValidator;
|
||||||
@ -211,7 +212,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
|
|||||||
userAuthSettingsDao.removeByUserId(userId);
|
userAuthSettingsDao.removeByUserId(userId);
|
||||||
deleteEntityRelations(tenantId, userId);
|
deleteEntityRelations(tenantId, userId);
|
||||||
userDao.removeById(tenantId, userId.getId());
|
userDao.removeById(tenantId, userId.getId());
|
||||||
eventPublisher.publishEvent(new UserAuthDataChangedEvent(userId, null, true));
|
eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user