This commit is contained in:
parent
d124da97b8
commit
cefcd14fda
20 changed files with 663 additions and 11 deletions
|
|
@ -10,6 +10,7 @@ import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.context.request.RequestContextListener;
|
||||||
import org.springframework.web.servlet.config.annotation.*;
|
import org.springframework.web.servlet.config.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -69,4 +70,9 @@ public class WebConfig implements WebMvcConfigurer {
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
registry.addMapping("/**").allowedMethods("*");
|
registry.addMapping("/**").allowedMethods("*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RequestContextListener requestContextListener() {
|
||||||
|
return new RequestContextListener();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package ru.spcex.clearing.backendapi.controller.request.cud.utilities;
|
||||||
|
|
||||||
|
|
||||||
|
import ru.spcex.clearing.backendapi.domain.actions.IAction;
|
||||||
|
import ru.spcex.clearing.backendapi.errors.BackEndError;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.ActionType;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.UserAuthRequest;
|
||||||
|
import ru.spcex.platform.utils.enumeration.EnumMessage;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class UserAuthAction implements IAction<UserAuthRequest> {
|
||||||
|
private final UserAuthRequest authRequest;
|
||||||
|
|
||||||
|
public UserAuthAction() {
|
||||||
|
this.authRequest = new UserAuthRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserAuthRequest getAuthRequest() {
|
||||||
|
return authRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<EnumMessage> validate() {
|
||||||
|
long count = authRequest.getRoles().stream().distinct().count();
|
||||||
|
if (count != authRequest.getRoles().size()) {
|
||||||
|
return List.of(new EnumMessage(BackEndError.KeycloakRepeatedRoles));
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserAuthRequest toRequest() {
|
||||||
|
return authRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionType getActionType() {
|
||||||
|
return ActionType.SYSTEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,8 @@ import ru.spcex.platform.utils.enumeration.IEnumId;
|
||||||
public enum BackEndError implements IEnumId {
|
public enum BackEndError implements IEnumId {
|
||||||
ValidationError(3000L),
|
ValidationError(3000L),
|
||||||
UnknownJsonProperty(3001L),
|
UnknownJsonProperty(3001L),
|
||||||
FailedToReadHttpMessage(3002L);
|
FailedToReadHttpMessage(3002L),
|
||||||
|
KeycloakRepeatedRoles(3003L);
|
||||||
private final Long id;
|
private final Long id;
|
||||||
|
|
||||||
BackEndError(Long id) {
|
BackEndError(Long id) {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount;
|
||||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
import org.keycloak.common.VerificationException;
|
import org.keycloak.common.VerificationException;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.http.*;
|
import org.springframework.http.*;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
|
@ -24,7 +26,7 @@ import org.springframework.util.LinkedMultiValueMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.web.client.HttpClientErrorException;
|
import org.springframework.web.client.HttpClientErrorException;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import ru.spcex.clearing.backendapi.service.UserAutoCreateService;
|
import ru.spcex.clearing.backendapi.service.UserAuthProcessor;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
@ -36,14 +38,15 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Component("keycloakRestAuthenticationProvider")
|
@Component("keycloakRestAuthenticationProvider")
|
||||||
public class KeycloakRestTemplateAuthenticationProvider implements AuthenticationProvider {
|
public class KeycloakRestTemplateAuthenticationProvider implements AuthenticationProvider {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
private final KeycloakConfigResolver resolver;
|
private final KeycloakConfigResolver resolver;
|
||||||
private final HttpServletRequest currentHttpRequest;
|
private final HttpServletRequest currentHttpRequest;
|
||||||
private final HttpServletResponse currentHttpResponse;
|
private final HttpServletResponse currentHttpResponse;
|
||||||
private final RestTemplate restTemplate;
|
private final RestTemplate restTemplate;
|
||||||
private final UserAutoCreateService userAutoCreation;
|
private final UserAuthProcessor userAutoCreation;
|
||||||
|
|
||||||
public KeycloakRestTemplateAuthenticationProvider(KeycloakConfigResolver resolver, HttpServletRequest currentHttpRequest, HttpServletResponse currentHttpResponse,
|
public KeycloakRestTemplateAuthenticationProvider(KeycloakConfigResolver resolver, HttpServletRequest currentHttpRequest, HttpServletResponse currentHttpResponse,
|
||||||
@Qualifier("clearing-rest") RestTemplate restTemplate, UserAutoCreateService userAutoCreation) {
|
@Qualifier("clearing-rest") RestTemplate restTemplate, UserAuthProcessor userAutoCreation) {
|
||||||
this.resolver = resolver;
|
this.resolver = resolver;
|
||||||
this.currentHttpRequest = currentHttpRequest;
|
this.currentHttpRequest = currentHttpRequest;
|
||||||
this.currentHttpResponse = currentHttpResponse;
|
this.currentHttpResponse = currentHttpResponse;
|
||||||
|
|
@ -79,8 +82,6 @@ public class KeycloakRestTemplateAuthenticationProvider implements Authenticatio
|
||||||
AccessToken accessToken = AdapterTokenVerifier.verifyToken(accessTokenString, deployment);
|
AccessToken accessToken = AdapterTokenVerifier.verifyToken(accessTokenString, deployment);
|
||||||
//todo cors settings
|
//todo cors settings
|
||||||
accessToken.setAllowedOrigins(Collections.singleton("*"));
|
accessToken.setAllowedOrigins(Collections.singleton("*"));
|
||||||
|
|
||||||
System.out.println("login successful");
|
|
||||||
List<SimpleGrantedAuthority> realmRoles = accessToken.getRealmAccess().getRoles().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
|
List<SimpleGrantedAuthority> realmRoles = accessToken.getRealmAccess().getRoles().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
|
||||||
|
|
||||||
RefreshableKeycloakSecurityContext skSession = new RefreshableKeycloakSecurityContext(deployment, null, accessTokenString, accessToken, null, null, refreshTokenString);
|
RefreshableKeycloakSecurityContext skSession = new RefreshableKeycloakSecurityContext(deployment, null, accessTokenString, accessToken, null, null, refreshTokenString);
|
||||||
|
|
@ -90,7 +91,7 @@ public class KeycloakRestTemplateAuthenticationProvider implements Authenticatio
|
||||||
final KeycloakAccount account = new SimpleKeycloakAccount(principal, roles, skSession);
|
final KeycloakAccount account = new SimpleKeycloakAccount(principal, roles, skSession);
|
||||||
KeycloakAuthenticationToken keycloakAuthenticationToken = new KeycloakAuthenticationToken(account, false, realmRoles);
|
KeycloakAuthenticationToken keycloakAuthenticationToken = new KeycloakAuthenticationToken(account, false, realmRoles);
|
||||||
keycloakAuthenticationToken.setAuthenticated(true);
|
keycloakAuthenticationToken.setAuthenticated(true);
|
||||||
checkRightsAndCreate(principalName, roles);
|
checkRightsAndCreate(principalName, accessToken.getId(), roles);
|
||||||
return keycloakAuthenticationToken;
|
return keycloakAuthenticationToken;
|
||||||
|
|
||||||
} catch (VerificationException vex) {
|
} catch (VerificationException vex) {
|
||||||
|
|
@ -100,10 +101,14 @@ public class KeycloakRestTemplateAuthenticationProvider implements Authenticatio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkRightsAndCreate(String username, Set<String> roles) {
|
private void checkRightsAndCreate(String username, String id, Set<String> roles) {
|
||||||
|
|
||||||
|
log.debug("login successful: login {}, roles {}", username, String.join(";", roles));
|
||||||
//todo remove hardcode
|
//todo remove hardcode
|
||||||
if (roles.contains("admin") || roles.contains("default-roles-master")) {
|
if (roles.contains("admin") || roles.contains("default-roles-master")) {
|
||||||
userAutoCreation.createUserIfNeeded(username);
|
String clientIp = currentHttpRequest != null ? currentHttpRequest.getRemoteAddr() : null;
|
||||||
|
String serverIp = currentHttpRequest != null ? currentHttpRequest.getLocalAddr() : null;
|
||||||
|
userAutoCreation.sendUserInfo(username, id, roles, clientIp, serverIp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
package ru.spcex.clearing.backendapi.service;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.spcex.clearing.backendapi.controller.request.cud.utilities.UserAuthAction;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.Consts;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.UserAuthRequest;
|
||||||
|
import ru.spcex.platform.utils.log.ExceptionUtils;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class UserAuthProcessor {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
private final IOperator operator;
|
||||||
|
private String serverAddress;
|
||||||
|
|
||||||
|
@Value("${server.port}")
|
||||||
|
private String serverPort;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public UserAuthProcessor(IOperator operator) {
|
||||||
|
this.operator = operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendUserInfo(String username, String identifier, Collection<String> roles, String userIp, String serverIp) {
|
||||||
|
UserAuthAction authEvent = new UserAuthAction();
|
||||||
|
UserAuthRequest requestData = authEvent.getAuthRequest();
|
||||||
|
requestData.setUsername(username);
|
||||||
|
requestData.setIdentifier(identifier);
|
||||||
|
requestData.setTime(Instant.now());
|
||||||
|
requestData.setRoles(new ArrayList<>(roles));
|
||||||
|
requestData.setServerIp(serverIp + ":" + serverPort); //getServerAddress() + ":" + serverPort
|
||||||
|
requestData.setClientIp(userIp);
|
||||||
|
try {
|
||||||
|
operator.sendRequestToQueue(Consts.USER_AUTH_SUCCESS, authEvent);
|
||||||
|
} catch (Throwable e) { //ExecutionException | InterruptedException
|
||||||
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getServerAddress() {
|
||||||
|
if (serverAddress != null) {
|
||||||
|
return serverAddress;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
|
||||||
|
while (networkInterfaces.hasMoreElements()) {
|
||||||
|
NetworkInterface networkInterface = networkInterfaces.nextElement();
|
||||||
|
Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
|
||||||
|
while(inetAddresses.hasMoreElements()) {
|
||||||
|
InetAddress inetAddress = inetAddresses.nextElement();
|
||||||
|
if (inetAddress != null) {
|
||||||
|
serverAddress = inetAddress.getHostAddress();
|
||||||
|
return serverAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serverAddress = "unknown";
|
||||||
|
return serverAddress;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("cannot retrieve server address {}", ExceptionUtils.getStackTrace(e));
|
||||||
|
serverAddress = "unknown";
|
||||||
|
return serverAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,10 @@
|
||||||
<groupId>ru.spcex.platform</groupId>
|
<groupId>ru.spcex.platform</groupId>
|
||||||
<artifactId>platform-messaging</artifactId>
|
<artifactId>platform-messaging</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.spcex.platform</groupId>
|
||||||
|
<artifactId>platform-enum</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ru.spcex.platform</groupId>
|
<groupId>ru.spcex.platform</groupId>
|
||||||
<artifactId>platform-imdg-api-hazelcast-impl</artifactId>
|
<artifactId>platform-imdg-api-hazelcast-impl</artifactId>
|
||||||
|
|
@ -36,6 +40,28 @@
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- TEST -->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.springframework</groupId>-->
|
||||||
|
<!-- <artifactId>spring-test</artifactId>-->
|
||||||
|
<!-- <scope>test</scope>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.mockito</groupId>-->
|
||||||
|
<!-- <artifactId>mockito-core</artifactId>-->
|
||||||
|
<!-- <scope>test</scope>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.assertj</groupId>
|
||||||
|
<artifactId>assertj-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@ package ru.spcex.clearing.utility.config;
|
||||||
|
|
||||||
import org.apache.kafka.clients.consumer.Consumer;
|
import org.apache.kafka.clients.consumer.Consumer;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
import ru.spcex.clearing.platform.messaging.config.KafkaConsumerFactory;
|
import ru.spcex.clearing.platform.messaging.config.KafkaConsumerFactory;
|
||||||
import ru.spcex.clearing.utility.config.settings.UtilityServiceSettings;
|
import ru.spcex.clearing.utility.config.settings.UtilityServiceSettings;
|
||||||
|
|
||||||
|
|
@ -11,6 +13,7 @@ import ru.spcex.clearing.utility.config.settings.UtilityServiceSettings;
|
||||||
public class KafkaConfig {
|
public class KafkaConfig {
|
||||||
@Autowired
|
@Autowired
|
||||||
@Bean
|
@Bean
|
||||||
|
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||||
public Consumer<String, Object> createProducer(UtilityServiceSettings settings) {
|
public Consumer<String, Object> createProducer(UtilityServiceSettings settings) {
|
||||||
return KafkaConsumerFactory.consumer(settings.getKafka());
|
return KafkaConsumerFactory.consumer(settings.getKafka());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
package ru.spcex.clearing.utility.service;
|
||||||
|
|
||||||
|
import org.apache.kafka.clients.consumer.Consumer;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.clearing.classes.statics.data.user.User;
|
||||||
|
import ru.clearing.classes.statics.data.user.UserConnect;
|
||||||
|
import ru.clearing.classes.statics.data.user.UserRoleSession;
|
||||||
|
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.Consts;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.UserAuthRequest;
|
||||||
|
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
|
||||||
|
import ru.spcex.platform.enumeration.ConnectionState;
|
||||||
|
import ru.spcex.platform.enumeration.Status;
|
||||||
|
import ru.spcex.platform.imdg.api.Imdg;
|
||||||
|
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||||
|
import ru.spcex.platform.utils.time.TimeUtil;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class UserService extends QueueConsumer implements InitializingBean {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
private final Imdg<User> userMap;
|
||||||
|
private final Imdg<UserRoleSession> userRoleSessionImdg;
|
||||||
|
private final Imdg<UserConnect> userConnectImdg;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public UserService(Consumer<String, Object> kafkaQueue, ImdgProvider imdgProvider) {
|
||||||
|
super(kafkaQueue);
|
||||||
|
this.userMap = imdgProvider.getImdg(IMDGDistributedNames.Map_User, User.class);
|
||||||
|
this.userRoleSessionImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_UserRoleSession, UserRoleSession.class);
|
||||||
|
this.userConnectImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_UserConnect, UserConnect.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
callback(UserAuthRequest.class)
|
||||||
|
.setConsumer(this::userAuthSuccess)
|
||||||
|
.forDestination(Consts.USER_AUTH_SUCCESS, callbacks::put);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void userAuthSuccess(BaseRequest<UserAuthRequest> authEvent) {
|
||||||
|
UserAuthRequest authInfo = authEvent.getRequestPayload();
|
||||||
|
log.debug("user id={} authenticated", authInfo.getUsername());
|
||||||
|
UserInfo userInfo = createUserIfNeeded(authInfo.getUsername());
|
||||||
|
changeRoles(userInfo.userId, userInfo.isNew, authInfo.getRoles());
|
||||||
|
connected(userInfo.userId, authInfo.getTime(), authInfo.getClientIp(), authInfo.getServerIp());
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserInfo createUserIfNeeded(String username) {
|
||||||
|
User user = userMap.getSingleObjectByFieldValues(Map.of("identifier", username));
|
||||||
|
if (user == null) {
|
||||||
|
user = new User();
|
||||||
|
user.setCreated(Instant.now());
|
||||||
|
user.setIdentifier(username);
|
||||||
|
userMap.insert(user);
|
||||||
|
return new UserInfo(true, user.getId());
|
||||||
|
} else {
|
||||||
|
return new UserInfo(false, user.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeRoles(Long userId, boolean isNew, Collection<String> authRoles) {
|
||||||
|
Collection<UserRoleSession> presentRoles;
|
||||||
|
if (isNew) {
|
||||||
|
presentRoles = Collections.emptyList();
|
||||||
|
} else {
|
||||||
|
presentRoles = userRoleSessionImdg.getCollectionObjectsByFieldValues(Map.of("userId", userId));
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<RoleAction> roleActions = defineAllRoleChanges(presentRoles, authRoles);
|
||||||
|
|
||||||
|
if (roleActions.size() > 0) {
|
||||||
|
for (RoleAction roleAction : roleActions) {
|
||||||
|
UserRoleSession role;
|
||||||
|
if (roleAction.create()) {
|
||||||
|
role = new UserRoleSession();
|
||||||
|
role.setUserRole(roleAction.roleName);
|
||||||
|
role.setUserId(userId);
|
||||||
|
role.setStatus(Status.Active.getKey());
|
||||||
|
userRoleSessionImdg.insert(role);
|
||||||
|
} else {
|
||||||
|
role = roleAction.roleToChange;
|
||||||
|
role.setStatus(roleAction.newStatus.getKey());
|
||||||
|
userRoleSessionImdg.update(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connected(Long userId, Instant time, String clientIp, String serverIp) {
|
||||||
|
UserConnect userConnect = userConnectImdg.getSingleObjectByFieldValues(Map.of("userId", userId));
|
||||||
|
boolean isNew = false;
|
||||||
|
if (userConnect == null) {
|
||||||
|
userConnect = new UserConnect();
|
||||||
|
userConnect.setUserId(userId);
|
||||||
|
isNew = true;
|
||||||
|
}
|
||||||
|
userConnect.setConnectionTime(time);
|
||||||
|
userConnect.setServerIP(serverIp);
|
||||||
|
userConnect.setClientIP(clientIp);
|
||||||
|
userConnect.setConnectionState(ConnectionState.Connected.getKey());
|
||||||
|
userConnect.setClearingDate(TimeUtil.today());
|
||||||
|
if (isNew) {
|
||||||
|
userConnectImdg.insert(userConnect);
|
||||||
|
} else {
|
||||||
|
userConnectImdg.update(userConnect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Collection<RoleAction> defineAllRoleChanges(Collection<UserRoleSession> presentRoles, Collection<String> authRoles) {
|
||||||
|
return Stream.concat(
|
||||||
|
presentRoles
|
||||||
|
.stream()
|
||||||
|
.filter(presentRole -> !(Status.Active.equalsByKey(presentRole.getStatus()) && contain(presentRole, authRoles)))
|
||||||
|
.filter(presentRole -> !(Status.Blocked.equalsByKey(presentRole.getStatus()) && !contain(presentRole, authRoles)))
|
||||||
|
.map(role -> {
|
||||||
|
RoleAction roleAction = new RoleAction();
|
||||||
|
roleAction.roleToChange = role;
|
||||||
|
if (Status.Active.equalsByKey(role.getStatus())) {
|
||||||
|
roleAction.newStatus = Status.Blocked;
|
||||||
|
} else {
|
||||||
|
roleAction.newStatus = Status.Active;
|
||||||
|
}
|
||||||
|
return roleAction;
|
||||||
|
}),
|
||||||
|
authRoles
|
||||||
|
.stream()
|
||||||
|
.filter(authRole -> !contain(authRole, presentRoles))
|
||||||
|
.map(authRole -> {
|
||||||
|
RoleAction action = new RoleAction();
|
||||||
|
action.newStatus = Status.Active;
|
||||||
|
action.roleName = authRole;
|
||||||
|
return action;
|
||||||
|
})
|
||||||
|
).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean contain(UserRoleSession role, Collection<String> authRoles) {
|
||||||
|
return authRoles.stream().anyMatch(authRole -> authRole.equalsIgnoreCase(role.getUserRole()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean contain(String authRole, Collection<UserRoleSession> presentRoles) {
|
||||||
|
return presentRoles.stream().anyMatch(role -> role.getUserRole().equalsIgnoreCase(authRole));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RoleAction {
|
||||||
|
String roleName;
|
||||||
|
//------поля при обновления-----
|
||||||
|
Status newStatus;
|
||||||
|
UserRoleSession roleToChange;
|
||||||
|
boolean create() {
|
||||||
|
return roleToChange == null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UserInfo {
|
||||||
|
boolean isNew;
|
||||||
|
Long userId;
|
||||||
|
|
||||||
|
public UserInfo(boolean isNew, Long userId) {
|
||||||
|
this.isNew = isNew;
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,7 @@ utility-service.hazelcast.login=dev
|
||||||
utility-service.hazelcast.password=dev-pass
|
utility-service.hazelcast.password=dev-pass
|
||||||
|
|
||||||
utility-service.kafka.bootstrap-servers=localhost:9092
|
utility-service.kafka.bootstrap-servers=localhost:9092
|
||||||
utility-service.kafka.group-id=dev-group
|
utility-service.kafka.group-id=dev-group-utility-service
|
||||||
utility-service.kafka.enable-auto-commit=false
|
utility-service.kafka.enable-auto-commit=false
|
||||||
utility-service.kafka.session-timeout-ms=30000
|
utility-service.kafka.session-timeout-ms=30000
|
||||||
utility-service.kafka.auto-offset-reset=latest
|
utility-service.kafka.auto-offset-reset=latest
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
package ru.spcex.clearing.utility.service;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import ru.clearing.classes.statics.data.user.UserRoleSession;
|
||||||
|
import ru.spcex.platform.enumeration.Status;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class UserServiceChangeRolesTest {
|
||||||
|
private static final AtomicLong idGenerator = new AtomicLong();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTwoNewRoles() {
|
||||||
|
Collection<UserRoleSession> userRoles = new ArrayList<>();
|
||||||
|
userRoles.add(generate("admin", Status.Active));
|
||||||
|
userRoles.add(generate("broker", Status.Active));
|
||||||
|
userRoles.add(generate("manager", Status.Blocked));
|
||||||
|
Collection<String> methodsFromAuth = List.of("admin", "broker", "makler", "user");
|
||||||
|
|
||||||
|
Collection<UserService.RoleAction> roleActions = UserService.defineAllRoleChanges(userRoles, methodsFromAuth);
|
||||||
|
assertEquals(2, roleActions.size());
|
||||||
|
assertTrue(roleActions.stream().anyMatch(roleAction -> roleAction.create()
|
||||||
|
&& "makler".equals(roleAction.roleName)));
|
||||||
|
assertTrue(roleActions.stream().anyMatch(roleAction -> roleAction.create()
|
||||||
|
&& "user".equals(roleAction.roleName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOneMissingTwoNew() {
|
||||||
|
Collection<UserRoleSession> userRoles = new ArrayList<>();
|
||||||
|
userRoles.add(generate("admin", Status.Active));
|
||||||
|
userRoles.add(generate("broker", Status.Active));
|
||||||
|
userRoles.add(generate("manager", Status.Active));
|
||||||
|
Collection<String> methodsFromAuth = List.of("admin", "broker", "makler", "user");
|
||||||
|
|
||||||
|
Collection<UserService.RoleAction> roleActions = UserService.defineAllRoleChanges(userRoles, methodsFromAuth);
|
||||||
|
assertEquals(3, roleActions.size());
|
||||||
|
assertTrue(roleActions.stream().anyMatch(roleAction -> !roleAction.create()
|
||||||
|
&& roleAction.roleToChange.getUserRole().equals("manager")
|
||||||
|
&& roleAction.newStatus.equals(Status.Blocked)));
|
||||||
|
assertTrue(roleActions.stream().anyMatch(roleAction -> roleAction.create()
|
||||||
|
&& "makler".equals(roleAction.roleName)));
|
||||||
|
assertTrue(roleActions.stream().anyMatch(roleAction -> roleAction.create()
|
||||||
|
&& "user".equals(roleAction.roleName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllNew() {
|
||||||
|
Collection<UserRoleSession> userRoles = new ArrayList<>();
|
||||||
|
Collection<String> methodsFromAuth = List.of("admin", "broker", "makler", "user");
|
||||||
|
|
||||||
|
Collection<UserService.RoleAction> roleActions = UserService.defineAllRoleChanges(userRoles, methodsFromAuth);
|
||||||
|
assertEquals(4, roleActions.size());
|
||||||
|
assertTrue(roleActions.stream().anyMatch(roleAction -> roleAction.create()
|
||||||
|
&& "admin".equals(roleAction.roleName)));
|
||||||
|
assertTrue(roleActions.stream().anyMatch(roleAction -> roleAction.create()
|
||||||
|
&& "broker".equals(roleAction.roleName)));
|
||||||
|
assertTrue(roleActions.stream().anyMatch(roleAction -> roleAction.create()
|
||||||
|
&& "makler".equals(roleAction.roleName)));
|
||||||
|
assertTrue(roleActions.stream().anyMatch(roleAction -> roleAction.create()
|
||||||
|
&& "user".equals(roleAction.roleName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTwoNewRolesDifferentCase() {
|
||||||
|
Collection<UserRoleSession> userRoles = new ArrayList<>();
|
||||||
|
userRoles.add(generate("AdMin", Status.Active));
|
||||||
|
userRoles.add(generate("broKer", Status.Active));
|
||||||
|
userRoles.add(generate("MANAGER", Status.Blocked));
|
||||||
|
Collection<String> methodsFromAuth = List.of("admin", "broker", "makler", "user");
|
||||||
|
|
||||||
|
Collection<UserService.RoleAction> roleActions = UserService.defineAllRoleChanges(userRoles, methodsFromAuth);
|
||||||
|
assertEquals(2, roleActions.size());
|
||||||
|
assertTrue(roleActions.stream().anyMatch(roleAction -> roleAction.create()
|
||||||
|
&& "makler".equalsIgnoreCase(roleAction.roleName)));
|
||||||
|
assertTrue(roleActions.stream().anyMatch(roleAction -> roleAction.create()
|
||||||
|
&& "user".equalsIgnoreCase(roleAction.roleName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UserRoleSession generate(String roleName, Status roleStatus) {
|
||||||
|
UserRoleSession userRoleSession = new UserRoleSession();
|
||||||
|
userRoleSession.setId(idGenerator.incrementAndGet());
|
||||||
|
userRoleSession.setUserId(1L);
|
||||||
|
userRoleSession.setUserRole(roleName);
|
||||||
|
userRoleSession.setStatus(roleStatus.getKey());
|
||||||
|
return userRoleSession;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
platform-parent/platform-enum/pom.xml
Normal file
29
platform-parent/platform-enum/pom.xml
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>platform-enum</artifactId>
|
||||||
|
<name>Platform enumerations</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>platform-parent</artifactId>
|
||||||
|
<groupId>ru.spcex.platform</groupId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.spcex.platform</groupId>
|
||||||
|
<artifactId>platform-utils</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package ru.spcex.platform.enumeration;
|
||||||
|
|
||||||
|
import ru.spcex.platform.utils.enumeration.IEnumKey;
|
||||||
|
|
||||||
|
public enum ConnectionState implements IEnumKey {
|
||||||
|
Connected("CNCT"), Disconnected("DSBL");
|
||||||
|
|
||||||
|
private final String key;
|
||||||
|
|
||||||
|
ConnectionState(String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package ru.spcex.platform.enumeration;
|
||||||
|
|
||||||
|
import ru.spcex.platform.utils.enumeration.IEnumKey;
|
||||||
|
|
||||||
|
public enum Status implements IEnumKey {
|
||||||
|
Active("ACTV"), Blocked("BLKD");
|
||||||
|
|
||||||
|
private final String key;
|
||||||
|
|
||||||
|
Status(String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package ru.spcex.clearing.platform.messaging.domain;
|
package ru.spcex.clearing.platform.messaging.domain;
|
||||||
|
|
||||||
public enum ActionType {
|
public enum ActionType {
|
||||||
NEW, UPDATE, DELETE;
|
NEW, UPDATE, DELETE,
|
||||||
|
SYSTEM;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,4 +22,6 @@ public interface Consts {
|
||||||
|
|
||||||
String DESTINATION_SDF08_NEW = "s-df-08-new";
|
String DESTINATION_SDF08_NEW = "s-df-08-new";
|
||||||
String DESTINATION_SDF02_NEW = "s-df-02-new";
|
String DESTINATION_SDF02_NEW = "s-df-02-new";
|
||||||
|
|
||||||
|
String USER_AUTH_SUCCESS = "user-auth-success";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
package ru.spcex.clearing.platform.messaging.domain.cud.utilities;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.InstantDeserializer;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.json.serialize.InstantSerializer;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class UserAuthRequest {
|
||||||
|
@JsonProperty
|
||||||
|
private String username;
|
||||||
|
@JsonProperty
|
||||||
|
private String identifier;
|
||||||
|
@JsonProperty
|
||||||
|
private List<String> roles = new ArrayList<>();
|
||||||
|
@JsonSerialize(using = InstantSerializer.class)
|
||||||
|
@JsonDeserialize(using = InstantDeserializer.class)
|
||||||
|
@JsonProperty
|
||||||
|
private Instant time;
|
||||||
|
@JsonProperty
|
||||||
|
private String serverIp;
|
||||||
|
@JsonProperty
|
||||||
|
private String clientIp;
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIdentifier() {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIdentifier(String identifier) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getRoles() {
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoles(List<String> roles) {
|
||||||
|
this.roles = roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instant getTime() {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTime(Instant time) {
|
||||||
|
this.time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerIp() {
|
||||||
|
return serverIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerIp(String serverIp) {
|
||||||
|
this.serverIp = serverIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientIp() {
|
||||||
|
return clientIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientIp(String clientIp) {
|
||||||
|
this.clientIp = clientIp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
package ru.spcex.platform.utils.enumeration;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public interface IEnumKey extends Serializable {
|
||||||
|
String getKey();
|
||||||
|
|
||||||
|
default boolean equalsByKey(String key) {
|
||||||
|
return key != null && getKey().equalsIgnoreCase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет что среди данного набора Enum, присутствует элемент с данным id
|
||||||
|
* id может быть null
|
||||||
|
*/
|
||||||
|
static <T extends Enum<T> & IEnumKey> boolean contains(String id, T... enumSet) {
|
||||||
|
for (T e : enumSet) {
|
||||||
|
if (Objects.equals(id, e.getKey()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T extends Enum<T> & IEnumKey> boolean contains(T e, T... enumSet) {
|
||||||
|
for (T enumEl : enumSet) {
|
||||||
|
if (enumEl.equals(e))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет что среди всех Enum данного класса, присутствует элемент с данным id
|
||||||
|
* id может быть null
|
||||||
|
*/
|
||||||
|
static <T extends Enum<T> & IEnumKey> boolean contains(Class<T> enumClass, String key) {
|
||||||
|
for (T e : enumClass.getEnumConstants()) {
|
||||||
|
if (Objects.equals(key, e.getKey()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает Enum по id, если в заданном классе такой определен
|
||||||
|
* id может быть null
|
||||||
|
*
|
||||||
|
* @return Enum если нашел, иначе <tt>null</tt>
|
||||||
|
*/
|
||||||
|
static <T extends Enum<T> & IEnumKey> T getEnumByKey(Class<T> enumClass, String key) {
|
||||||
|
for (T e : enumClass.getEnumConstants()) {
|
||||||
|
if (Objects.equals(key, e.getKey()))
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getKeyOrNull(IEnumKey enumVal) {
|
||||||
|
return enumVal == null ? null : enumVal.getKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
String UNDEFINED_VALUE = "_Undefined";
|
||||||
|
}
|
||||||
|
|
@ -19,4 +19,12 @@ public class TimeUtil {
|
||||||
if (date == null) return null;
|
if (date == null) return null;
|
||||||
return formatter.format(date.atZone(zone));
|
return formatter.format(date.atZone(zone));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Instant today() {
|
||||||
|
return localDateToInstant(LocalDate.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Instant localDateToInstant(LocalDate date) {
|
||||||
|
return date.atStartOfDay(zone).toInstant();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
<module>platform-classes-base</module>
|
<module>platform-classes-base</module>
|
||||||
<module>platform-imdg-api-hazelcast-impl</module>
|
<module>platform-imdg-api-hazelcast-impl</module>
|
||||||
<module>platform-utils</module>
|
<module>platform-utils</module>
|
||||||
|
<module>platform-enum</module>
|
||||||
<module>platform-messaging</module>
|
<module>platform-messaging</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
||||||
6
pom.xml
6
pom.xml
|
|
@ -103,6 +103,12 @@
|
||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.spcex.platform</groupId>
|
||||||
|
<artifactId>platform-enum</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ru.spcex.platform</groupId>
|
<groupId>ru.spcex.platform</groupId>
|
||||||
<artifactId>platform-imdg-api</artifactId>
|
<artifactId>platform-imdg-api</artifactId>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue