Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: correct device information update during account switch #6483

Merged
merged 1 commit into from
Aug 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class DeviceServiceImpl implements DeviceService {

@Override
public Mono<Void> loginSuccess(ServerWebExchange exchange, Authentication authentication) {
return updateExistingDevice(exchange)
return updateExistingDevice(exchange, authentication)
.switchIfEmpty(createDevice(exchange, authentication)
.flatMap(client::create)
.doOnNext(device -> {
Expand All @@ -61,10 +61,7 @@ public Mono<Void> changeSessionId(ServerWebExchange exchange) {
.map(context -> context.getAuthentication().getName())
.flatMap(username -> {
var deviceId = deviceIdCookie.getValue();
return updateWithRetry(deviceId, device -> {
if (!device.getSpec().getPrincipalName().equals(username)) {
return Mono.empty();
}
return updateWithRetry(deviceId, username, device -> {
var oldSessionId = device.getSpec().getSessionId();
return exchange.getSession()
.filter(session -> !session.getId().equals(oldSessionId))
Expand All @@ -78,48 +75,52 @@ public Mono<Void> changeSessionId(ServerWebExchange exchange) {
});
}

private Mono<Device> updateWithRetry(String deviceId,
private Mono<Device> updateWithRetry(String deviceId, String username,
Function<Device, Mono<Device>> updateFunction) {
return Mono.defer(() -> client.fetch(Device.class, deviceId)
.filter(device -> device.getSpec().getPrincipalName().equals(username))
.flatMap(updateFunction)
.flatMap(client::update)
)
.retryWhen(Retry.backoff(8, Duration.ofMillis(100))
.filter(OptimisticLockingFailureException.class::isInstance));
}

private Mono<Device> updateExistingDevice(ServerWebExchange exchange) {
private Mono<Device> updateExistingDevice(ServerWebExchange exchange,
Authentication authentication) {
var deviceIdCookie = deviceCookieResolver.resolveCookie(exchange);
if (deviceIdCookie == null) {
return Mono.empty();
}
return updateWithRetry(deviceIdCookie.getValue(), (Device existingDevice) -> {
var sessionId = existingDevice.getSpec().getSessionId();
return exchange.getSession()
.flatMap(session -> {
var userAgent =
exchange.getRequest().getHeaders().getFirst(HttpHeaders.USER_AGENT);
var deviceUa = existingDevice.getSpec().getUserAgent();
if (!StringUtils.equals(deviceUa, userAgent)) {
// User agent changed, create a new device
return Mono.empty();
}
return Mono.just(session);
})
.flatMap(session -> {
if (session.getId().equals(sessionId)) {
var principalName = authentication.getName();
return updateWithRetry(deviceIdCookie.getValue(), principalName,
(Device existingDevice) -> {
var sessionId = existingDevice.getSpec().getSessionId();
return exchange.getSession()
.flatMap(session -> {
var userAgent =
exchange.getRequest().getHeaders().getFirst(HttpHeaders.USER_AGENT);
var deviceUa = existingDevice.getSpec().getUserAgent();
if (!StringUtils.equals(deviceUa, userAgent)) {
// User agent changed, create a new device
return Mono.empty();
}
return Mono.just(session);
}
return sessionRepository.deleteById(sessionId).thenReturn(session);
})
.map(session -> {
existingDevice.getSpec().setSessionId(session.getId());
existingDevice.getSpec().setLastAccessedTime(session.getLastAccessTime());
existingDevice.getSpec().setLastAuthenticatedTime(Instant.now());
return existingDevice;
})
.flatMap(this::removeRememberMeToken);
});
})
.flatMap(session -> {
if (session.getId().equals(sessionId)) {
return Mono.just(session);
}
return sessionRepository.deleteById(sessionId).thenReturn(session);
})
.map(session -> {
existingDevice.getSpec().setSessionId(session.getId());
existingDevice.getSpec().setLastAccessedTime(session.getLastAccessTime());
existingDevice.getSpec().setLastAuthenticatedTime(Instant.now());
return existingDevice;
})
.flatMap(this::removeRememberMeToken);
});
}

@Override
Expand Down
Loading