This commit is contained in:
parent
fac2ca4278
commit
220caec7cc
9 changed files with 190 additions and 19 deletions
|
|
@ -0,0 +1,28 @@
|
|||
package ru.spcex.clearing.backendapi.controller.request.cud.utilities;
|
||||
|
||||
|
||||
import ru.spcex.clearing.backendapi.domain.actions.IAction;
|
||||
import ru.spcex.clearing.platform.messaging.domain.ActionType;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.UserLogoutRequest;
|
||||
|
||||
public class UserLogoutAction implements IAction<UserLogoutRequest> {
|
||||
private final UserLogoutRequest authRequest;
|
||||
|
||||
public UserLogoutAction() {
|
||||
this.authRequest = new UserLogoutRequest();
|
||||
}
|
||||
|
||||
public UserLogoutRequest getAuthRequest() {
|
||||
return authRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserLogoutRequest toRequest() {
|
||||
return authRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionType getActionType() {
|
||||
return ActionType.SYSTEM;
|
||||
}
|
||||
}
|
||||
|
|
@ -91,7 +91,7 @@ public class KeycloakRestTemplateAuthenticationProvider implements Authenticatio
|
|||
final KeycloakAccount account = new SimpleKeycloakAccount(principal, roles, skSession);
|
||||
KeycloakAuthenticationToken keycloakAuthenticationToken = new KeycloakAuthenticationToken(account, false, realmRoles);
|
||||
keycloakAuthenticationToken.setAuthenticated(true);
|
||||
checkRightsAndCreate(principalName, roles);
|
||||
log.debug("login successful: login {}, roles {}", principalName, String.join(";", roles));
|
||||
return keycloakAuthenticationToken;
|
||||
|
||||
} catch (VerificationException vex) {
|
||||
|
|
@ -101,17 +101,6 @@ public class KeycloakRestTemplateAuthenticationProvider implements Authenticatio
|
|||
}
|
||||
}
|
||||
|
||||
private void checkRightsAndCreate(String username, Set<String> roles) {
|
||||
|
||||
log.debug("login successful: login {}, roles {}", username, String.join(";", roles));
|
||||
//todo remove hardcode
|
||||
if (roles.contains("admin") || roles.contains("default-roles-master")) {
|
||||
String clientIp = currentHttpRequest != null ? currentHttpRequest.getRemoteAddr() : null;
|
||||
String serverIp = currentHttpRequest != null ? currentHttpRequest.getLocalAddr() : null;
|
||||
userAutoCreation.sendUserInfo(username, roles, clientIp, serverIp);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> type) {
|
||||
return UsernamePasswordAuthenticationToken.class.equals(type);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticatio
|
|||
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
|
|
@ -14,19 +13,26 @@ import org.springframework.security.config.annotation.web.configurers.Expression
|
|||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
import ru.spcex.clearing.backendapi.config.element.BackendApiSettings;
|
||||
import ru.spcex.clearing.backendapi.security.handlers.AuthAuditSuccessLoginHandler;
|
||||
import ru.spcex.clearing.backendapi.security.handlers.LogoutAuditSuccessHandler;
|
||||
|
||||
@KeycloakConfiguration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
|
||||
|
||||
private final Boolean securityDisabled;
|
||||
private final AuthAuditSuccessLoginHandler loginSuccessHandler;
|
||||
private final LogoutAuditSuccessHandler logoutSuccessHandler;
|
||||
|
||||
public WebSecurityConfig(BackendApiSettings settings) {
|
||||
public WebSecurityConfig(BackendApiSettings settings,
|
||||
AuthAuditSuccessLoginHandler loginSuccessHandler,
|
||||
LogoutAuditSuccessHandler logoutSuccessHandler) {
|
||||
this.securityDisabled = settings.getSecurity().getAuthorizationDisabled();
|
||||
this.loginSuccessHandler = loginSuccessHandler;
|
||||
this.logoutSuccessHandler = logoutSuccessHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -65,11 +71,11 @@ public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
|
|||
anyReq.hasAnyRole("admin", "default-roles-master")
|
||||
.and()
|
||||
.formLogin()
|
||||
.successHandler((req, res, auth) -> res.setStatus(HttpStatus.OK.value()))
|
||||
.successHandler(loginSuccessHandler)
|
||||
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
|
||||
.and()
|
||||
.logout()
|
||||
.logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK))
|
||||
.logoutSuccessHandler(logoutSuccessHandler)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package ru.spcex.clearing.backendapi.security.handlers;
|
||||
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.adapters.spi.KeycloakAccount;
|
||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.spcex.clearing.backendapi.service.UserAuthProcessor;
|
||||
import ru.spcex.platform.utils.log.ExceptionUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Set;
|
||||
|
||||
@Service
|
||||
public class AuthAuditSuccessLoginHandler implements AuthenticationSuccessHandler {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final UserAuthProcessor userAutoCreation;
|
||||
|
||||
@Autowired
|
||||
public AuthAuditSuccessLoginHandler(UserAuthProcessor userAutoCreation) {
|
||||
this.userAutoCreation = userAutoCreation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
|
||||
try {
|
||||
KeycloakAuthenticationToken auth = (KeycloakAuthenticationToken) authentication;
|
||||
KeycloakAccount details = (KeycloakAccount) auth.getDetails();
|
||||
String username = ((KeycloakPrincipal) details.getPrincipal())
|
||||
.getKeycloakSecurityContext()
|
||||
.getToken()
|
||||
.getPreferredUsername();
|
||||
Set<String> roles = details.getRoles();
|
||||
if (roles.contains("admin") || roles.contains("default-roles-master")) {
|
||||
String clientIp = request != null ? request.getRemoteAddr() : null;
|
||||
String serverIp = request != null ? request.getLocalAddr() : null;
|
||||
userAutoCreation.sendAuthSuccessEvent(username, roles, clientIp, serverIp);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
log.error(ExceptionUtils.getStackTrace(e));
|
||||
}
|
||||
response.setStatus(HttpStatus.OK.value());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package ru.spcex.clearing.backendapi.security.handlers;
|
||||
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.adapters.spi.KeycloakAccount;
|
||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.spcex.clearing.backendapi.service.UserAuthProcessor;
|
||||
import ru.spcex.platform.utils.log.ExceptionUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
@Service
|
||||
public class LogoutAuditSuccessHandler extends HttpStatusReturningLogoutSuccessHandler {
|
||||
private final UserAuthProcessor logoutEventSender;
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Autowired
|
||||
public LogoutAuditSuccessHandler(UserAuthProcessor logoutEventSender) {
|
||||
super(HttpStatus.OK);
|
||||
this.logoutEventSender = logoutEventSender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws IOException {
|
||||
try {
|
||||
KeycloakAuthenticationToken auth = (KeycloakAuthenticationToken) authentication;
|
||||
KeycloakAccount details = (KeycloakAccount) auth.getDetails();
|
||||
String username = ((KeycloakPrincipal) details.getPrincipal())
|
||||
.getKeycloakSecurityContext()
|
||||
.getToken()
|
||||
.getPreferredUsername();
|
||||
this.logoutEventSender.sendLogoutSuccessEvent(username);
|
||||
} catch (Throwable e) {
|
||||
log.error(ExceptionUtils.getStackTrace(e));
|
||||
}
|
||||
super.onLogoutSuccess(request, response, authentication);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -6,8 +6,10 @@ 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.backendapi.controller.request.cud.utilities.UserLogoutAction;
|
||||
import ru.spcex.clearing.platform.messaging.domain.Consts;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.UserAuthRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.UserLogoutRequest;
|
||||
import ru.spcex.platform.utils.log.ExceptionUtils;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
|
@ -31,7 +33,7 @@ public class UserAuthProcessor {
|
|||
this.operator = operator;
|
||||
}
|
||||
|
||||
public void sendUserInfo(String identifier, Collection<String> roles, String userIp, String serverIp) {
|
||||
public void sendAuthSuccessEvent(String identifier, Collection<String> roles, String userIp, String serverIp) {
|
||||
UserAuthAction authEvent = new UserAuthAction();
|
||||
UserAuthRequest requestData = authEvent.getAuthRequest();
|
||||
requestData.setUsername(identifier);
|
||||
|
|
@ -46,6 +48,18 @@ public class UserAuthProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
public void sendLogoutSuccessEvent(String identifier) {
|
||||
UserLogoutAction logoutEvent = new UserLogoutAction();
|
||||
UserLogoutRequest requestData = logoutEvent.getAuthRequest();
|
||||
requestData.setUsername(identifier);
|
||||
requestData.setTime(Instant.now());
|
||||
try {
|
||||
operator.sendRequestToQueue(Consts.USER_LOGOUT_SUCCESS, logoutEvent);
|
||||
} catch (Throwable e) {
|
||||
log.error(ExceptionUtils.getStackTrace(e));
|
||||
}
|
||||
}
|
||||
|
||||
private String getServerAddress() {
|
||||
if (serverAddress != null) {
|
||||
return serverAddress;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ spring.main.web-application-type=servlet
|
|||
|
||||
backend-api.example-setting=test
|
||||
|
||||
backend-api.hazelcast.cluster-members=127.0.0.1
|
||||
backend-api.hazelcast.cluster-members=127.0.0.1:5701
|
||||
backend-api.hazelcast.login=dev
|
||||
backend-api.hazelcast.password=dev-pass
|
||||
|
||||
|
|
|
|||
|
|
@ -24,4 +24,5 @@ public interface Consts {
|
|||
String DESTINATION_SDF02_NEW = "s-df-02-new";
|
||||
|
||||
String USER_AUTH_SUCCESS = "user-auth-success";
|
||||
String USER_LOGOUT_SUCCESS = "user-logout-success";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
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;
|
||||
|
||||
public class UserLogoutRequest {
|
||||
@JsonProperty
|
||||
private String username;
|
||||
@JsonSerialize(using = InstantSerializer.class)
|
||||
@JsonDeserialize(using = InstantDeserializer.class)
|
||||
@JsonProperty
|
||||
private Instant time;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public Instant getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(Instant time) {
|
||||
this.time = time;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue