From c40b273a2896ca30ae535842faf664bae73dc24c Mon Sep 17 00:00:00 2001 From: krishnaBaile Date: Fri, 3 Jan 2025 16:14:01 +0530 Subject: [PATCH 1/9] security implementation --- pom.xml | 61 ++- .../openAi/application/OpenAiApplication.java | 9 + .../openAi/security/AuthenticationFilter.java | 132 ++++++ .../com/openAi/security/ConfigController.java | 25 ++ .../openAi/security/PasswordEncryptor.java | 15 + .../openAi/security/WebSecurityConfig.java | 138 ++++++ .../security/controller/AuthController.java | 242 +++++++++++ .../openAi/security/entity/AllowedDomain.java | 34 ++ .../openAi/security/entity/Attendance.java | 79 ++++ .../com/openAi/security/entity/Customer.java | 54 +++ .../security/entity/CustomerCredentials.java | 27 ++ .../com/openAi/security/entity/Roles.java | 24 ++ .../java/com/openAi/security/entity/Team.java | 144 +++++++ .../java/com/openAi/security/entity/User.java | 121 ++++++ .../com/openAi/security/entity/UserLog.java | 25 ++ .../openAi/security/entity/UserTeamRoles.java | 31 ++ .../openAi/security/enums/EntityStatus.java | 14 + .../com/openAi/security/enums/TeamType.java | 27 ++ .../com/openAi/security/enums/UserRole.java | 35 ++ .../exceptions/CustomRuntimeException.java | 12 + .../exceptions/EntityNotFoundException.java | 51 +++ .../openAi/security/exceptions/ErrorCode.java | 65 +++ .../InvalidAuthenticationException.java | 20 + .../security/exceptions/RAGException.java | 28 ++ .../openAi/security/mapper/UserMapper.java | 16 + .../com/openAi/security/model/JwtRequest.java | 10 + .../com/openAi/security/model/MonthValue.java | 10 + .../com/openAi/security/model/TeamModel.java | 43 ++ .../com/openAi/security/model/UserModel.java | 32 ++ .../openAi/security/model/UserRequest.java | 10 + .../com/openAi/security/model/UserRole.java | 35 ++ .../security/model/UserTeamRolesModel.java | 23 + .../security/model/WebClientResponse.java | 23 + .../repository/AllowedDomainRepository.java | 17 + .../repository/AttendanceRepository.java | 394 ++++++++++++++++++ .../CustomerCredentialRepository.java | 15 + .../repository/UserLogRepository.java | 11 + .../security/repository/UserRepository.java | 36 ++ .../repository/UserTeamRoleRepository.java | 31 ++ .../openAi/security/service/UserService.java | 23 + .../security/service/UserServiceImpl.java | 111 +++++ .../com/openAi/security/utils/JpaConfig.java | 22 + .../com/openAi/security/utils/JwtUtils.java | 73 ++++ src/main/resources/application.yml | 21 + 44 files changed, 2367 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/openAi/security/AuthenticationFilter.java create mode 100644 src/main/java/com/openAi/security/ConfigController.java create mode 100644 src/main/java/com/openAi/security/PasswordEncryptor.java create mode 100644 src/main/java/com/openAi/security/WebSecurityConfig.java create mode 100644 src/main/java/com/openAi/security/controller/AuthController.java create mode 100644 src/main/java/com/openAi/security/entity/AllowedDomain.java create mode 100644 src/main/java/com/openAi/security/entity/Attendance.java create mode 100644 src/main/java/com/openAi/security/entity/Customer.java create mode 100644 src/main/java/com/openAi/security/entity/CustomerCredentials.java create mode 100644 src/main/java/com/openAi/security/entity/Roles.java create mode 100644 src/main/java/com/openAi/security/entity/Team.java create mode 100644 src/main/java/com/openAi/security/entity/User.java create mode 100644 src/main/java/com/openAi/security/entity/UserLog.java create mode 100644 src/main/java/com/openAi/security/entity/UserTeamRoles.java create mode 100644 src/main/java/com/openAi/security/enums/EntityStatus.java create mode 100644 src/main/java/com/openAi/security/enums/TeamType.java create mode 100644 src/main/java/com/openAi/security/enums/UserRole.java create mode 100644 src/main/java/com/openAi/security/exceptions/CustomRuntimeException.java create mode 100644 src/main/java/com/openAi/security/exceptions/EntityNotFoundException.java create mode 100644 src/main/java/com/openAi/security/exceptions/ErrorCode.java create mode 100644 src/main/java/com/openAi/security/exceptions/InvalidAuthenticationException.java create mode 100644 src/main/java/com/openAi/security/exceptions/RAGException.java create mode 100644 src/main/java/com/openAi/security/mapper/UserMapper.java create mode 100644 src/main/java/com/openAi/security/model/JwtRequest.java create mode 100644 src/main/java/com/openAi/security/model/MonthValue.java create mode 100644 src/main/java/com/openAi/security/model/TeamModel.java create mode 100644 src/main/java/com/openAi/security/model/UserModel.java create mode 100644 src/main/java/com/openAi/security/model/UserRequest.java create mode 100644 src/main/java/com/openAi/security/model/UserRole.java create mode 100644 src/main/java/com/openAi/security/model/UserTeamRolesModel.java create mode 100644 src/main/java/com/openAi/security/model/WebClientResponse.java create mode 100644 src/main/java/com/openAi/security/repository/AllowedDomainRepository.java create mode 100644 src/main/java/com/openAi/security/repository/AttendanceRepository.java create mode 100644 src/main/java/com/openAi/security/repository/CustomerCredentialRepository.java create mode 100644 src/main/java/com/openAi/security/repository/UserLogRepository.java create mode 100644 src/main/java/com/openAi/security/repository/UserRepository.java create mode 100644 src/main/java/com/openAi/security/repository/UserTeamRoleRepository.java create mode 100644 src/main/java/com/openAi/security/service/UserService.java create mode 100644 src/main/java/com/openAi/security/service/UserServiceImpl.java create mode 100644 src/main/java/com/openAi/security/utils/JpaConfig.java create mode 100644 src/main/java/com/openAi/security/utils/JwtUtils.java diff --git a/pom.xml b/pom.xml index a908f28..55fe9be 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.3.5 + 2.6.4 com.openAi @@ -62,7 +62,7 @@ redis.clients jedis - 5.2.0 + 4.2.3 org.springframework.boot @@ -74,6 +74,54 @@ reactor-test test + + + spring-boot-starter-security + org.springframework.boot + + + org.projectlombok + lombok + 1.18.34 + provided + + + org.springframework.data + spring-data-jpa + 2.6.2 + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.hibernate + hibernate-core + 5.6.5.Final + + + + mysql-connector-java + mysql + 8.0.30 + + + + jjwt + io.jsonwebtoken + 0.9.1 + + + mapstruct + org.mapstruct + 1.5.2.Final + + + org.mapstruct + mapstruct-processor + 1.5.2.Final + provided + @@ -93,6 +141,15 @@ org.springframework.boot spring-boot-maven-plugin + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + 17 + 17 + + diff --git a/src/main/java/com/openAi/application/OpenAiApplication.java b/src/main/java/com/openAi/application/OpenAiApplication.java index 4a008f4..f40c0bb 100644 --- a/src/main/java/com/openAi/application/OpenAiApplication.java +++ b/src/main/java/com/openAi/application/OpenAiApplication.java @@ -1,13 +1,22 @@ package com.openAi.application; +import com.openAi.security.AuthenticationFilter; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @SpringBootApplication(scanBasePackages = "com.openAi") +@EnableJpaRepositories(basePackages = "com.openAi.security.repository") +@EntityScan(basePackages = "com.openAi.security.entity") public class OpenAiApplication { + public static void main(String[] args) { SpringApplication.run(OpenAiApplication.class, args); } + } diff --git a/src/main/java/com/openAi/security/AuthenticationFilter.java b/src/main/java/com/openAi/security/AuthenticationFilter.java new file mode 100644 index 0000000..1f1cf4f --- /dev/null +++ b/src/main/java/com/openAi/security/AuthenticationFilter.java @@ -0,0 +1,132 @@ +package com.openAi.security; + +import com.openAi.security.exceptions.InvalidAuthenticationException; +import com.openAi.security.model.UserModel; +import com.openAi.security.service.UserService; +import com.openAi.security.utils.JwtUtils; +import io.jsonwebtoken.Claims; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.context.support.SpringBeanAutowiringSupport; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Collections; +import java.util.Date; +import java.util.Objects; +import java.util.UUID; + +import static com.openAi.security.enums.EntityStatus.ACTIVE; + +@Slf4j +@Component + +public class AuthenticationFilter extends OncePerRequestFilter { + + @Autowired + private JwtUtils jwtUtils; + @Autowired + private UserService userService; + @Autowired + private HttpServletRequest httpServletRequest; + + @Value("${security.apiKey}") + private String apiKey; + + public AuthenticationFilter() { + SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); + } + + @Override + @SneakyThrows + protected void doFilterInternal( + HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) { + + String path = request.getRequestURI(); + log.info( + String.format("Requested path: %s at %s by %s", path, new Date(), request.getRemoteHost())); + if ( + new AntPathMatcher().match("/getToken", path) + || new AntPathMatcher().match("/getTokenGoogleAuth", path) + || new AntPathMatcher().match("/getTokenUserAuth", path) + || new AntPathMatcher().match("/user/generatePassword", path) + || new AntPathMatcher().match("/resetPassword", path) + || HttpMethod.OPTIONS.name().equalsIgnoreCase(request.getMethod()) + || new AntPathMatcher().match("/", path) + && apiKey.equals(request.getHeader("Api-Key"))) { + filterChain.doFilter(request, response); + return; + } + + String jwt; + try { + jwt = parseJwt(); + jwtUtils.validateJwtToken(jwt); + } catch (Exception e) { + log.error( + String.format( + "%s | AUTHORIZATION Header: %s", + e.getMessage(), request.getHeader(HttpHeaders.AUTHORIZATION))); + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + return; + } + + Claims claims = jwtUtils.getAllClaimsFromToken(jwt); + String email = claims.getSubject(); + UserModel userModel; + try { + userModel = userService.findUserByEmailOrAttendance(email); + } catch (Exception e) { + log.error("User not found for email {}", email); + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + return; + } + + boolean enabled = ACTIVE.equals(userModel.getStatus()); + User user = + new User( + userModel.getEmail(), + UUID.randomUUID().toString(), + enabled, + true, + true, + true, + Collections.singletonList(new SimpleGrantedAuthority(userModel.getRole().name()))); + + final UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authentication); + + filterChain.doFilter(request, response); + } + + public String parseJwt() { + + Cookie[] cookieAuth = httpServletRequest.getCookies(); + if (Objects.nonNull(cookieAuth)) { + for (Cookie cookie : cookieAuth) { + if (cookie.getName().equals("auth-token")) { + return cookie.getValue(); + } + } + } + + throw InvalidAuthenticationException.invalidToken("Failed to parse JWT Token"); + } +} + + diff --git a/src/main/java/com/openAi/security/ConfigController.java b/src/main/java/com/openAi/security/ConfigController.java new file mode 100644 index 0000000..e622ced --- /dev/null +++ b/src/main/java/com/openAi/security/ConfigController.java @@ -0,0 +1,25 @@ +package com.openAi.security; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/security-config") +@EnableCaching +@Slf4j +@RequiredArgsConstructor +public class ConfigController { + + private final WebSecurityConfig webSecurityConfig; + + @PostMapping("/refresh-cors-config") + public ResponseEntity refreshCorsConfig() { + webSecurityConfig.updateCorsConfiguration(); + return ResponseEntity.ok("CORS configuration updated successfully"); + } +} diff --git a/src/main/java/com/openAi/security/PasswordEncryptor.java b/src/main/java/com/openAi/security/PasswordEncryptor.java new file mode 100644 index 0000000..000b9f9 --- /dev/null +++ b/src/main/java/com/openAi/security/PasswordEncryptor.java @@ -0,0 +1,15 @@ +package com.openAi.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class PasswordEncryptor { + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } +} diff --git a/src/main/java/com/openAi/security/WebSecurityConfig.java b/src/main/java/com/openAi/security/WebSecurityConfig.java new file mode 100644 index 0000000..1b7edd7 --- /dev/null +++ b/src/main/java/com/openAi/security/WebSecurityConfig.java @@ -0,0 +1,138 @@ +package com.openAi.security; + +import com.openAi.security.entity.AllowedDomain; +import com.openAi.security.repository.AllowedDomainRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.http.HttpStatus; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.authentication.AuthenticationFilter; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.authentication.HttpStatusEntryPoint; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +import java.util.Arrays; +import java.util.List; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +@RequiredArgsConstructor +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + private final AuthenticationFilter filter; + + private final AllowedDomainRepository allowedDomainRepository; + + private CorsConfiguration configuration = new CorsConfiguration(); + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.cors() + .and() + .csrf() + .disable() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + .antMatchers("/getToken", + "/getTokenUserAuth", + "/user/generatePassword", + "/resetPassword", + "/getTokenGoogleAuth" + ) + .permitAll() + .anyRequest() + .authenticated() + .and() + .exceptionHandling() + .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) + .and() + .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class); + } + + @Bean + @Profile({"dev","staging","prod"}) + public CorsConfigurationSource corsConfigurationSource() { + updateCorsConfiguration(); + configuration.addExposedHeader("Set-Cookie"); + configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); + // setAllowCredentials(true) is important, otherwise: + // The value of the 'Access-Control-Allow-Origin' header in the response must not be the + // wildcard '*' when the request's credentials mode is 'include'. + // setAllowedHeaders is important! Without it, OPTIONS preflight request + // will fail with 403 Invalid CORS request + configuration.setAllowedHeaders( + List.of( + "Api-Key", + "Authorization", + "Cache-Control", + "Content-Type", + "Access-Control-Allow-Origin", + "Access-Control-Allow-Credentials")); + configuration.setAllowCredentials(true); + + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } + + @Bean + @Profile("test") + public CorsConfigurationSource corsConfigurationSourceTest() { + final CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOrigins( + List.of( + "https://playbook.talentica.com/", + "https://orion.talentica.com/", + "https://prod-orion.talentica.com/", + "http://localhost:3000/", + "http://localhost/", + "https://stagingplaybook.talentica.com", + "https://dev-orion.talentica.com/", + "https://stagingorion.talentica.com", + "https://staging-orion.talentica.com/", + "http://localhost:3001/", + "https://stagingknowledgebase.talentica.com/", + "https://stagingknowledgebase-sales.talentica.com/", + "https://staging.kb.talentica.com/", + "https://stagingknowledgebase.talentica.com/", + "https://nexus.talentica.com/", + "https://kb.talentica.com/")); + configuration.addExposedHeader("Set-Cookie"); + configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); + // setAllowCredentials(true) is important, otherwise: + // The value of the 'Access-Control-Allow-Origin' header in the response must not be the + // wildcard '*' when the request's credentials mode is 'include'. + // setAllowedHeaders is important! Without it, OPTIONS preflight request + // will fail with 403 Invalid CORS request + configuration.setAllowedHeaders( + List.of( + "Api-Key", + "Authorization", + "Cache-Control", + "Content-Type", + "Access-Control-Allow-Origin", + "Access-Control-Allow-Credentials")); + configuration.setAllowCredentials(true); + + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } + + public void updateCorsConfiguration() { + List origins = allowedDomainRepository.findAll() + .stream().map(AllowedDomain::getDomainName).toList(); + configuration.setAllowedOrigins(origins); + } +} diff --git a/src/main/java/com/openAi/security/controller/AuthController.java b/src/main/java/com/openAi/security/controller/AuthController.java new file mode 100644 index 0000000..52a7b44 --- /dev/null +++ b/src/main/java/com/openAi/security/controller/AuthController.java @@ -0,0 +1,242 @@ +package com.openAi.security.controller; + +import com.fasterxml.jackson.databind.JsonNode; +import com.openAi.security.exceptions.CustomRuntimeException; +import com.openAi.security.model.JwtRequest; +import com.openAi.security.model.UserRequest; +import com.openAi.security.model.WebClientResponse; +import com.openAi.security.repository.CustomerCredentialRepository; +import com.openAi.security.entity.CustomerCredentials; +import com.openAi.security.service.UserService; +import com.openAi.security.utils.JwtUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseCookie; +import org.springframework.http.ResponseEntity; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.reactive.function.client.WebClient; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class AuthController { + + private static final String ERROR_DUE_TO_INVALID_EMAIL = "Bad/Unauthorised Request error due to Invalid email"; + private static final String COOKIE = "Set-Cookie"; + private static final String BEARER = "Bearer "; + private final JwtUtils jwtUtils; + private final HttpServletResponse httpServletResponse; + private final HttpServletRequest httpServletRequest; + private final UserService userService; + private final CustomerCredentialRepository customerCredentialRepository; + + @Value("${security.jwtExpirationMs}") + private Long jwtExpirationMs; + private final PasswordEncoder passwordEncoder; + + @PostMapping("/getTokenUserAuth") + public ResponseEntity authenticateCustomer(@RequestBody UserRequest userRequest){ + String user = userRequest.getUser(); + List credentialsList = customerCredentialRepository.findAllByUserNameOrUserEmail(user,user); + if(credentialsList.isEmpty()){ + log.error(ERROR_DUE_TO_INVALID_EMAIL); + return ResponseEntity.status(HttpStatus.NON_AUTHORITATIVE_INFORMATION).body(WebClientResponse.builder() + .reason("Incorrect Username") + .build()); + } + CustomerCredentials customerCredentials = credentialsList.get(0); + if(!passwordEncoder.matches(userRequest.getPassword(),customerCredentials.getPassword())){ + return ResponseEntity.status(HttpStatus.NON_AUTHORITATIVE_INFORMATION).body(WebClientResponse.builder() + .reason("Incorrect Password") + .build()); + } + + else{ + String jwt = jwtUtils.getJWTToken(customerCredentials.getUserEmail()); + userService.saveUserLog(customerCredentials.getUserEmail()); + + + var cookie = getAuthCookie(jwt); + httpServletResponse.addHeader(COOKIE, cookie.toString()); + + customerCredentials.setLoginCount(Optional.ofNullable(customerCredentials.getLoginCount()).orElse(0) + 1); + customerCredentialRepository.save(customerCredentials); + + return ResponseEntity.ok(WebClientResponse.builder() + .givenName(customerCredentials.getUserName()) + .displayName(customerCredentials.getUserName()) + .mail(customerCredentials.getUserEmail()) + .isResetRequired(!customerCredentials.getIsReset()) + .token(BEARER + jwt).build()); + } + } + + @PostMapping("/resetPassword") + public ResponseEntity resetPassword(@RequestBody UserRequest userRequest){ + String user = userRequest.getUser(); + List credentialsList = customerCredentialRepository.findAllByUserNameOrUserEmail(user,user); + if(credentialsList.isEmpty()){ + log.error(ERROR_DUE_TO_INVALID_EMAIL); + return ResponseEntity.status(HttpStatus.NON_AUTHORITATIVE_INFORMATION).body(WebClientResponse.builder() + .reason("Incorrect Username") + .build()); + } + String actualPwd = credentialsList.get(0).getPassword(); + String password = userRequest.getOldPassword(); + + if(!passwordEncoder.matches(password,actualPwd)){ + return ResponseEntity.status(HttpStatus.NON_AUTHORITATIVE_INFORMATION).body(WebClientResponse.builder() + .reason("Incorrect Password") + .build()); + } + + if(userRequest.getPassword().isBlank()){ + return ResponseEntity.status(HttpStatus.NON_AUTHORITATIVE_INFORMATION).body(WebClientResponse.builder() + .reason("Enter New Password") + .build()); + } + + credentialsList.get(0).setPassword(passwordEncoder.encode(userRequest.getPassword())); + credentialsList.get(0).setPwdGeneratedDate(new Date()); + credentialsList.get(0).setIsReset(true); + + customerCredentialRepository.save(credentialsList.get(0)); + + String jwt = jwtUtils.getJWTToken(credentialsList.get(0).getUserEmail()); + userService.saveUserLog(credentialsList.get(0).getUserEmail()); + + if(Boolean.TRUE.equals(credentialsList.get(0).getIsReset())) { + var cookie = getAuthCookie(jwt); + httpServletResponse.addHeader(COOKIE, cookie.toString()); + } + + return ResponseEntity.ok(WebClientResponse.builder() + .givenName(credentialsList.get(0).getUserName()) + .displayName(credentialsList.get(0).getUserName()) + .mail(credentialsList.get(0).getUserEmail()) + .isResetRequired(!credentialsList.get(0).getIsReset()) + .token(BEARER + jwt).build()); + } + + @GetMapping("/initialLogin") + public ResponseEntity ifInitialLogin(@RequestParam String email) { + List credentialsList = customerCredentialRepository.findAllByUserEmail(email); + if(credentialsList.isEmpty()){ + throw new IllegalArgumentException(ERROR_DUE_TO_INVALID_EMAIL); + } + return ResponseEntity.ok(credentialsList.get(0).getLoginCount() == 1); + } + + @PostMapping("/getTokenGoogleAuth") + public ResponseEntity authenticateGoogleUser(@RequestBody JwtRequest jwtRequest) { + WebClient client = WebClient.create(); + JsonNode response = client.get() + .uri("https://www.googleapis.com/oauth2/v3/userinfo") + .headers(headers -> { + headers.setBearerAuth(jwtRequest.getToken()); + headers.setContentType(MediaType.APPLICATION_JSON); + }) + .retrieve() + .bodyToMono(JsonNode.class) + .block(); + + log.info( + "Profile successfully validated from google against user {}", + Objects.requireNonNull(response).get("email").asText()); + + String mail = response.get("email").asText(); + if (mail == null) { + log.error(ERROR_DUE_TO_INVALID_EMAIL); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + + String jwt = jwtUtils.getJWTToken(mail); + + log.info("JWT token fetched successfully for valid email: {}", mail); + + userService.saveUserLog(mail); + + var cookie = getAuthCookie(jwt); + httpServletResponse.addHeader(COOKIE, cookie.toString()); + + return ResponseEntity.ok(WebClientResponse.builder() + .id(response.get("sub").asText()) + .givenName(response.get("given_name").asText()) + .displayName(response.get("name").asText()) + .mail(mail) + .token(BEARER + jwt).build()); + } + + @PostMapping("/getToken") + public ResponseEntity authenticateUser(@RequestBody JwtRequest jwtRequest) { + WebClient client = WebClient.create(); + WebClientResponse response = + client + .get() + .uri("https://graph.microsoft.com/v1.0/me") + .headers( + headers -> { + headers.setBearerAuth(jwtRequest.getToken()); + headers.setContentType(MediaType.APPLICATION_JSON); + }) + .retrieve() + .bodyToMono(WebClientResponse.class) + .block(); + log.info( + "Me profile successfully validated from microsoft against user {}", + Objects.requireNonNull(response).getMail()); + + String mail = response.getMail(); + if (StringUtils.isEmpty(response.getMail())) { + log.error(ERROR_DUE_TO_INVALID_EMAIL); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + + String jwt = jwtUtils.getJWTToken(mail); + response.setToken(BEARER + jwt); + log.info("JWT token fetched successfully for valid email: {}", response.getMail()); + + userService.saveUserLog(mail); + + + var cookie = getAuthCookie(jwt); + httpServletResponse.addHeader(COOKIE, cookie.toString()); + + return ResponseEntity.ok(response); + } + + private ResponseCookie getAuthCookie(String authToken) { + URL url = null; + try { + url = new URL(httpServletRequest.getRequestURL().toString()); + } catch (MalformedURLException e) { + throw new CustomRuntimeException(e.getMessage()); + } + final String cookieName = "auth-token"; + final int expiryTime = Math.toIntExact(jwtExpirationMs / 1000); // millis in seconds + return ResponseCookie + .from(cookieName,authToken) + .secure(true) + .httpOnly(false) + .path("/") + .maxAge(expiryTime) + .domain(url.getHost().equalsIgnoreCase("localhost")?"localhost":".talentica.com") + .sameSite("None") + .build(); + + } +} diff --git a/src/main/java/com/openAi/security/entity/AllowedDomain.java b/src/main/java/com/openAi/security/entity/AllowedDomain.java new file mode 100644 index 0000000..4c569cc --- /dev/null +++ b/src/main/java/com/openAi/security/entity/AllowedDomain.java @@ -0,0 +1,34 @@ +package com.openAi.security.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.time.LocalDate; + +@Entity +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AllowedDomain { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(columnDefinition = "INT(11) UNSIGNED") + private Integer id; + + private String domainName; + + private Integer customerId; + + private String teamIds; + + private Boolean isOnBoarded; + + private LocalDate onBoardedDate; + + private LocalDate dataFrom; +} diff --git a/src/main/java/com/openAi/security/entity/Attendance.java b/src/main/java/com/openAi/security/entity/Attendance.java new file mode 100644 index 0000000..a3d2747 --- /dev/null +++ b/src/main/java/com/openAi/security/entity/Attendance.java @@ -0,0 +1,79 @@ +package com.openAi.security.entity; + +import lombok.*; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + +@Entity +@Data +@Table(name = "attendance") +public class Attendance { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + private String employeeCode; + + private String employeeName; + + private String firstName; + + private String lastName; + + private String projectName; + + private String employeeGrade; + + private String reportingManager; + + private String emailId; + + private Integer presentDays; + + private Integer year; + + private Integer month; + + private Date assignmentStartDate; + + private Date assignmentEndDate; + + private Date dateOfJoining; + + private String employeeFunction; + + private Integer billingPercentage; + + private String businessUnit; + + public Attendance(Attendance att) { + this.id = att.id; + this.employeeCode = att.employeeCode; + this.employeeName = att.employeeName; + this.firstName = att.firstName; + this.lastName = att.lastName; + this.projectName = att.projectName; + this.employeeGrade = att.employeeGrade; + this.reportingManager = att.reportingManager; + this.emailId = att.emailId; + this.presentDays = att.presentDays; + this.year = att.year; + this.month = att.month; + this.assignmentStartDate = att.assignmentStartDate; + this.assignmentEndDate = att.assignmentEndDate; + this.employeeFunction = att.employeeFunction; + this.billingPercentage = att.billingPercentage; + this.businessUnit = att.businessUnit; + this.dateOfJoining = att.dateOfJoining; + + } + +} diff --git a/src/main/java/com/openAi/security/entity/Customer.java b/src/main/java/com/openAi/security/entity/Customer.java new file mode 100644 index 0000000..519a969 --- /dev/null +++ b/src/main/java/com/openAi/security/entity/Customer.java @@ -0,0 +1,54 @@ +package com.openAi.security.entity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.openAi.security.enums.EntityStatus; +import lombok.*; +import lombok.experimental.Accessors; + +import javax.persistence.*; +import java.time.LocalDate; +import java.util.List; + +@Entity +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +@Table(name = "customers") +public class Customer { + + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + private String customerName; + private String projectName; + + @Enumerated(EnumType.STRING) + private EntityStatus status = EntityStatus.ACTIVE; + + private String currentStage; + + private String engagementType; + + @OneToMany(mappedBy = "customer", cascade = CascadeType.MERGE, fetch = FetchType.LAZY) + @JsonIgnoreProperties("teamLeads") + private List teams; + + + @Column(columnDefinition = "DATE") + private LocalDate startDate; + + @Column(columnDefinition = "DATE") + private LocalDate endDate; + + private Boolean isCicero; + + private Boolean isTeg; + + private String link; + +} diff --git a/src/main/java/com/openAi/security/entity/CustomerCredentials.java b/src/main/java/com/openAi/security/entity/CustomerCredentials.java new file mode 100644 index 0000000..6056490 --- /dev/null +++ b/src/main/java/com/openAi/security/entity/CustomerCredentials.java @@ -0,0 +1,27 @@ +package com.openAi.security.entity; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import javax.persistence.*; +import java.util.Date; + +@Entity +@Getter +@Setter +@Accessors(chain = true) +public class CustomerCredentials { + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + private String userName; + private String userEmail; + private String password; + private Boolean isReset; + private Date pwdGeneratedDate; + private Integer loginCount; + private Boolean tourClosed; +} diff --git a/src/main/java/com/openAi/security/entity/Roles.java b/src/main/java/com/openAi/security/entity/Roles.java new file mode 100644 index 0000000..132490a --- /dev/null +++ b/src/main/java/com/openAi/security/entity/Roles.java @@ -0,0 +1,24 @@ +package com.openAi.security.entity; + +import com.openAi.security.enums.UserRole; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import javax.persistence.*; + +@Entity +@Getter +@Setter +@Accessors(chain = true) +public class Roles { + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @Enumerated(EnumType.STRING) + private UserRole role = UserRole.LEAD; + + private float priority; +} diff --git a/src/main/java/com/openAi/security/entity/Team.java b/src/main/java/com/openAi/security/entity/Team.java new file mode 100644 index 0000000..5ec20b0 --- /dev/null +++ b/src/main/java/com/openAi/security/entity/Team.java @@ -0,0 +1,144 @@ +package com.openAi.security.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.openAi.security.enums.EntityStatus; +import com.openAi.security.enums.TeamType; +import lombok.*; +import lombok.experimental.Accessors; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.jpa.domain.Specification; + +import javax.persistence.*; +import javax.persistence.criteria.JoinType; +import java.time.LocalDate; +import java.util.List; + +/** + * Team Entity. + */ +@Entity +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +public class Team { + + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + private String teamName; + + private String teamShortName; + + private String teamJiraName; + + private String teamJiraLink; + + @Enumerated(EnumType.STRING) + private TeamType teamType; + + private Double noOfHoursPerSP; + + @ManyToMany(fetch = FetchType.LAZY) + @JsonIgnoreProperties("teams") + @JoinTable( + name = "user_teams", + joinColumns = @JoinColumn(name = "teams_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id")) + private List teamLeads; + + @Column(columnDefinition = "DATE") + private LocalDate activeSince; + + @Column(columnDefinition = "DATE") + private LocalDate endDate; + + @Enumerated(EnumType.STRING) + private EntityStatus status = EntityStatus.ACTIVE; + + private Boolean isTeg; + private Boolean excludeCompliance; + + private Boolean complianceByStory; + + @JsonIgnore + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "customer_id") + @JsonIgnoreProperties("teams") + private Customer customer; + + private String doneStatuses; + + private String onTimeIssueTypes; +/* + public static Specification idSpec(int id) { + return (team, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(team.get("id"), id); + } + + public static Specification statusSpec(EntityStatus status) { + return (team, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.equal((team.get("status")), status); + } + + public static Specification teamTypeSpec(TeamType teamType) { + return (team, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.equal((team.get("teamType")), teamType); + } + + public static Specification teamNameSpec(String teamName) { + return (team, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.like(team.get("teamName"), "%" + teamName + "%"); + } + + public static Specification teamLeadNameSpec(String teamLeadName) { + return (team, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.like( + team.join("teamLeads", JoinType.LEFT).get("name"), "%" + teamLeadName + "%"); + } + + public static Specification teamLeadEmailSpec(String teamLeadEmail) { + return (team, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.like( + team.join("teamLeads", JoinType.LEFT).get("email"), "%" + teamLeadEmail + "%"); + } + + public static Specification isTegSpec(Boolean isTeg) { + return (team, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.equal((team.get("isTeg")), isTeg); + } + + public static Specification distinct() { + return (root, query, cb) -> { + query.distinct(true); + return null; + }; + } + + public static Specification teamSearchFieldSpec(String searchField) { + Specification teamSpecification = Specification.where(null); + if (StringUtils.isNumeric(searchField)) { + int id = Integer.parseInt(searchField); + teamSpecification = teamSpecification.or(Team.idSpec(id)); + } + try { + var entityStatus = EntityStatus.valueOf(searchField.toUpperCase()); + teamSpecification = teamSpecification.or(Team.statusSpec(entityStatus)); + } catch (IllegalArgumentException e) { + // Not Entity Status + } + try { + var teamType = TeamType.valueOf(searchField.toUpperCase()); + teamSpecification = teamSpecification.or(Team.teamTypeSpec(teamType)); + } catch (IllegalArgumentException e) { + // Not Team Type + } + teamSpecification = + teamSpecification.or(Team.teamLeadNameSpec(searchField)).or(Team.teamNameSpec(searchField)); + return teamSpecification; + }*/ +} diff --git a/src/main/java/com/openAi/security/entity/User.java b/src/main/java/com/openAi/security/entity/User.java new file mode 100644 index 0000000..07ccad0 --- /dev/null +++ b/src/main/java/com/openAi/security/entity/User.java @@ -0,0 +1,121 @@ +package com.openAi.security.entity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.openAi.security.entity.Team; +import com.openAi.security.entity.UserTeamRoles; +import com.openAi.security.enums.EntityStatus; +import com.openAi.security.enums.UserRole; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.jpa.domain.Specification; + +import javax.persistence.*; +import javax.persistence.criteria.JoinType; +import java.util.List; + +/** + * User Entity. + */ +@Entity +@Getter +@Setter +@Accessors(chain = true) +public class User { + + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + private String name; + + @Enumerated(EnumType.STRING) + private UserRole role = UserRole.LEAD; + + @JsonIgnoreProperties("user") + @OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL) + private List userTeamRoles; + + private String email; + private Boolean isTeg; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "user_teams", + joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "teams_id", referencedColumnName = "id")) + @JsonIgnoreProperties("teamLeads") + private List teams; + + @Enumerated(EnumType.STRING) + private EntityStatus status = EntityStatus.ACTIVE; + + + public static Specification idSpec(int id) { + return (user, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(user.get("id"), id); + } + + public static Specification nameSpec(String name) { + return (user, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.like(user.get("name"), "%" + name + "%"); + } + + public static Specification emailSpec(String email) { + return (user, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.like(user.get("email"), "%" + email + "%"); + } + + public static Specification roleSpec(UserRole role) { + return (user, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(user.get("role"), role); + } + + public static Specification teamSpec(String teamName) { + return (user, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.like( + user.join("teams", JoinType.LEFT).get("teamName"), "%" + teamName + "%"); + } + + public static Specification statusSpec(EntityStatus status) { + return (user, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.equal(user.get("status"), status); + } + + public static Specification isTegSpec(Boolean isTeg) { + return (user, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.equal((user.get("isTeg")), isTeg); + } + + public static Specification distinct() { + return (root, query, cb) -> { + query.distinct(true); + return null; + }; + } + + public static Specification userSearchFieldSpec(String searchField) { + Specification userSpecification = Specification.where(null); + if (StringUtils.isNumeric(searchField)) { + int id = Integer.parseInt(searchField); + userSpecification = userSpecification.or(User.idSpec(id)); + } + try { + var entityStatus = EntityStatus.valueOf(searchField.toUpperCase()); + userSpecification = userSpecification.or(User.statusSpec(entityStatus)); + } catch (IllegalArgumentException e) { + // Not Entity Status + } + try { + var userRole = UserRole.valueOf(searchField.toUpperCase()); + userSpecification = userSpecification.or(User.roleSpec(userRole)); + } catch (IllegalArgumentException e) { + // Not User Role + } + userSpecification = + userSpecification + .or(User.nameSpec(searchField).or(User.emailSpec(searchField))) + .or(User.teamSpec(searchField)); + return userSpecification; + } +} diff --git a/src/main/java/com/openAi/security/entity/UserLog.java b/src/main/java/com/openAi/security/entity/UserLog.java new file mode 100644 index 0000000..6427dd8 --- /dev/null +++ b/src/main/java/com/openAi/security/entity/UserLog.java @@ -0,0 +1,25 @@ +package com.openAi.security.entity; + +import lombok.*; +import lombok.experimental.Accessors; + +import javax.persistence.*; +import java.util.Date; + +@Entity +@Getter +@Setter +@Builder +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class UserLog { + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + private Integer userId; + + private Date logInDate; +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/entity/UserTeamRoles.java b/src/main/java/com/openAi/security/entity/UserTeamRoles.java new file mode 100644 index 0000000..a1664a4 --- /dev/null +++ b/src/main/java/com/openAi/security/entity/UserTeamRoles.java @@ -0,0 +1,31 @@ +package com.openAi.security.entity; + +import lombok.*; +import lombok.experimental.Accessors; + +import javax.persistence.*; + +@Entity +@Getter +@Setter +@Accessors(chain = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserTeamRoles{ + + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "user_id", referencedColumnName = "id") + private User user; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "role_id") + private Roles userRole; + + +} diff --git a/src/main/java/com/openAi/security/enums/EntityStatus.java b/src/main/java/com/openAi/security/enums/EntityStatus.java new file mode 100644 index 0000000..7d8ae22 --- /dev/null +++ b/src/main/java/com/openAi/security/enums/EntityStatus.java @@ -0,0 +1,14 @@ +package com.openAi.security.enums; + +import lombok.Getter; + +public enum EntityStatus { + INACTIVE(0), + ACTIVE(1); + + @Getter private final int value; + + EntityStatus(int value) { + this.value = value; + } +} diff --git a/src/main/java/com/openAi/security/enums/TeamType.java b/src/main/java/com/openAi/security/enums/TeamType.java new file mode 100644 index 0000000..31acc17 --- /dev/null +++ b/src/main/java/com/openAi/security/enums/TeamType.java @@ -0,0 +1,27 @@ +package com.openAi.security.enums; + +import java.util.EnumMap; +import java.util.List; + +/** TeamType consisting multiple team types. */ +public enum TeamType { + BIG_TECH, + EARLY, + GROWTH, + PROFITABLE; + private static final EnumMap> CORRESPONDING_TYPES = + new EnumMap<>(TeamType.class); + + static { + CORRESPONDING_TYPES.put(BIG_TECH, List.of(BIG_TECH)); + CORRESPONDING_TYPES.put(EARLY, List.of(EARLY)); + CORRESPONDING_TYPES.put(GROWTH, List.of(GROWTH)); + CORRESPONDING_TYPES.put(PROFITABLE, List.of(PROFITABLE)); + } + + public static List getCorrespondingTypeList(TeamType teamType) { + return CORRESPONDING_TYPES.get(teamType); + } + + +} diff --git a/src/main/java/com/openAi/security/enums/UserRole.java b/src/main/java/com/openAi/security/enums/UserRole.java new file mode 100644 index 0000000..a24cb91 --- /dev/null +++ b/src/main/java/com/openAi/security/enums/UserRole.java @@ -0,0 +1,35 @@ +package com.openAi.security.enums; + +import lombok.Getter; + +public enum UserRole { + ADMIN(0), + MANAGER(1), + LEAD(2), + M4(3), + CSO(4), + RO(5), + TO(6), + I3(7), + I2(8), + I1(9), + WATCHER(10), + PEOPLE_GROUP(11), + M1(12), + M2(13), + I4(14), + A1(15), + A2(16), + A3(17), + M3(18), + CUSTOMER(19), + E1(20), + E2(21); + + @Getter + private final int value; + + UserRole(int value) { + this.value = value; + } +} diff --git a/src/main/java/com/openAi/security/exceptions/CustomRuntimeException.java b/src/main/java/com/openAi/security/exceptions/CustomRuntimeException.java new file mode 100644 index 0000000..69221dc --- /dev/null +++ b/src/main/java/com/openAi/security/exceptions/CustomRuntimeException.java @@ -0,0 +1,12 @@ +package com.openAi.security.exceptions; + +public class CustomRuntimeException extends RuntimeException { + public CustomRuntimeException(String message) { + super(message); + } + + public CustomRuntimeException(String message,Exception e) { + super(message+ "::" +e.getMessage()); + } + +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/exceptions/EntityNotFoundException.java b/src/main/java/com/openAi/security/exceptions/EntityNotFoundException.java new file mode 100644 index 0000000..105d56a --- /dev/null +++ b/src/main/java/com/openAi/security/exceptions/EntityNotFoundException.java @@ -0,0 +1,51 @@ +package com.openAi.security.exceptions; + + +import static com.openAi.security.exceptions.ErrorCode.*; + +/** + * EntityNotFoundException. + */ +public class EntityNotFoundException extends RAGException { + + private EntityNotFoundException(String message, Integer code) { + super(message); + setCode(code); + } + + public static EntityNotFoundException user(String message) { + return new EntityNotFoundException(message, USER_NOT_FOUND); + } + + public static EntityNotFoundException team(String message) { + return new EntityNotFoundException(message, TEAM_NOT_FOUND); + } + + public static EntityNotFoundException cycleConfig(String message) { + return new EntityNotFoundException(message, CYCLE_CONFIG_NOT_FOUND); + } + + public static EntityNotFoundException survey(String message) { + return new EntityNotFoundException(message, SURVEY_NOT_FOUND); + } + + public static EntityNotFoundException customer(String message) { + return new EntityNotFoundException(message, CUSTOMER_NOT_FOUND); + } + + public static EntityNotFoundException section(String message) { + return new EntityNotFoundException(message, SECTION_NOT_FOUND); + } + + public static EntityNotFoundException employee(String message) { + return new EntityNotFoundException(message, EMPLOYEE_NOT_FOUND); + } + + public static EntityNotFoundException dataForEmployee(String message) { + return new EntityNotFoundException(message, NO_DATA_FOUND_FOR_EMPLOYEE); + } + + public static RuntimeException techDigest(String s) { + return new EntityNotFoundException(s,TECH_DIGEST_NOT_FOUND); + } +} diff --git a/src/main/java/com/openAi/security/exceptions/ErrorCode.java b/src/main/java/com/openAi/security/exceptions/ErrorCode.java new file mode 100644 index 0000000..96b852a --- /dev/null +++ b/src/main/java/com/openAi/security/exceptions/ErrorCode.java @@ -0,0 +1,65 @@ +package com.openAi.security.exceptions; + +public class ErrorCode { + + public static final Integer INTERNAL_SERVER_ERROR = 500; + public static final Integer NULL_POINTER_EXCEPTION = 500; + public static final Integer INVALID_ACCESS = 401; + + // Authentication and Authorization + public static final Integer INVALID_TOKEN = 1; + public static final Integer UNAUTHORISED_USER = 2; + + // User + public static final Integer USER_NOT_FOUND = 11; + + // Team + public static final Integer TEAM_NOT_FOUND = 21; + + // ConfigCycle + public static final Integer CYCLE_EXPIRED = 31; + public static final Integer CYCLE_CONFIG_NOT_FOUND = 32; + + // Survey + public static final Integer SURVEY_NOT_FOUND = 41; + public static final Integer NOT_ENOUGH_SURVEY = 42; + + // File + public static final Integer INVALID_FILE_EXTENSION = 51; + public static final Integer INVALID_FILE_FORMAT = 52; + + // Csat + public static final Integer NOT_ENOUGH_SURVEYS = 61; + public static final Integer CATEGORY_NOT_FOUND = 62; + public static final Integer QUESTION_NOT_FOUND = 63; + public static final Integer SUB_QUESTION_NOT_FOUND = 64; + public static final Integer SURVEY_ALREADY_EXISTS = 65; + public static final Integer PLACEHOLDER_NOT_FOUND = 66; + + // Customer + public static final Integer CUSTOMER_NOT_FOUND = 71; + + // Product Roadmap + public static final Integer EMPTY_STORY_NAME = 81; + public static final Integer INVALID_END_DATE = 82; + public static final Integer EMPTY_START_DATE = 83; + public static final Integer INCORRECT_DATA = 84; + public static final Integer NO_DATA_FOUND = 85; + + // Http Connection + public static final Integer HTTP_CONNECTION_FAILED = 91; + + // Section + public static final Integer SECTION_NOT_FOUND = 101; + + // TouchPoint + public static final Integer INVALID_FILE = 1101; + + // Teams + public static final Integer EMPLOYEE_NOT_FOUND = 1201; + public static final Integer NO_DATA_FOUND_FOR_EMPLOYEE = 1202; + + public static final Integer TECH_DIGEST_NOT_FOUND = 1301; + private ErrorCode() { + } +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/exceptions/InvalidAuthenticationException.java b/src/main/java/com/openAi/security/exceptions/InvalidAuthenticationException.java new file mode 100644 index 0000000..b8ab3ef --- /dev/null +++ b/src/main/java/com/openAi/security/exceptions/InvalidAuthenticationException.java @@ -0,0 +1,20 @@ +package com.openAi.security.exceptions; + +import static com.openAi.security.exceptions.ErrorCode.INVALID_TOKEN; +import static com.openAi.security.exceptions.ErrorCode.UNAUTHORISED_USER; + +public class InvalidAuthenticationException extends RAGException { + + private InvalidAuthenticationException(String message, Integer code) { + super(message); + setCode(code); + } + + public static InvalidAuthenticationException invalidToken(String message) { + return new InvalidAuthenticationException(message, INVALID_TOKEN); + } + + public static InvalidAuthenticationException unauthorisedUser(String message) { + return new InvalidAuthenticationException(message, UNAUTHORISED_USER); + } +} diff --git a/src/main/java/com/openAi/security/exceptions/RAGException.java b/src/main/java/com/openAi/security/exceptions/RAGException.java new file mode 100644 index 0000000..744ddc6 --- /dev/null +++ b/src/main/java/com/openAi/security/exceptions/RAGException.java @@ -0,0 +1,28 @@ +package com.openAi.security.exceptions; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + + + +@Setter +@Getter +public abstract class RAGException extends RuntimeException { + + private Integer code = ErrorCode.INTERNAL_SERVER_ERROR; + + protected RAGException(String message) { + super(message); + } + + protected RAGException(String message, Throwable cause) { + super(message, cause); + } + + protected RAGException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/com/openAi/security/mapper/UserMapper.java b/src/main/java/com/openAi/security/mapper/UserMapper.java new file mode 100644 index 0000000..d7289b6 --- /dev/null +++ b/src/main/java/com/openAi/security/mapper/UserMapper.java @@ -0,0 +1,16 @@ +package com.openAi.security.mapper; + + +import com.openAi.security.entity.User; +import com.openAi.security.model.UserModel; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** Entity-Model mapper for User. */ +@Mapper +public interface UserMapper { + @Mapping(source = "userTeamRoles", target = "teamRoles") + UserModel entityToModel(User user); + + User modelToEntity(UserModel user); +} diff --git a/src/main/java/com/openAi/security/model/JwtRequest.java b/src/main/java/com/openAi/security/model/JwtRequest.java new file mode 100644 index 0000000..3d277be --- /dev/null +++ b/src/main/java/com/openAi/security/model/JwtRequest.java @@ -0,0 +1,10 @@ +package com.openAi.security.model; + +import lombok.Data; + +@Data +public class JwtRequest { + + private String token; + private String email; +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/model/MonthValue.java b/src/main/java/com/openAi/security/model/MonthValue.java new file mode 100644 index 0000000..aae7072 --- /dev/null +++ b/src/main/java/com/openAi/security/model/MonthValue.java @@ -0,0 +1,10 @@ +package com.openAi.security.model; + +import lombok.Getter; + +public interface MonthValue { + String getMonth(); + String getYear(); + String getValue(); + +} diff --git a/src/main/java/com/openAi/security/model/TeamModel.java b/src/main/java/com/openAi/security/model/TeamModel.java new file mode 100644 index 0000000..e3c50da --- /dev/null +++ b/src/main/java/com/openAi/security/model/TeamModel.java @@ -0,0 +1,43 @@ +package com.openAi.security.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.openAi.security.entity.Customer; +import com.openAi.security.entity.User; +import com.openAi.security.enums.EntityStatus; +import com.openAi.security.enums.TeamType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TeamModel { + + private Integer id; + private String teamName; + private TeamType teamType; + private LocalDate activeSince; + private LocalDate endDate; + private String teamShortName; + private String teamJiraName; + private Boolean isTeg; + private Boolean excludeCompliance; + private Boolean complianceByStory; + + @JsonIgnoreProperties("teams") + private List teamLeads; + + @JsonIgnoreProperties("team") + private List userRoles; + + private EntityStatus status; + + @JsonIgnoreProperties(value = {"epics", "customerUserRoles"}, allowSetters = true) + private Customer customer; +} diff --git a/src/main/java/com/openAi/security/model/UserModel.java b/src/main/java/com/openAi/security/model/UserModel.java new file mode 100644 index 0000000..43542bb --- /dev/null +++ b/src/main/java/com/openAi/security/model/UserModel.java @@ -0,0 +1,32 @@ +package com.openAi.security.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.openAi.security.entity.Customer; +import com.openAi.security.enums.EntityStatus; +import com.openAi.security.enums.UserRole; +import lombok.*; + +import java.util.List; + +/** + * User Model. + */ +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class UserModel { + + private Integer id; + private String name; + private UserRole role; + private String email; + @JsonIgnoreProperties(value = {"teamLeads", "userTeamRoles"}, allowSetters = true) + private List teams; + private List teamRoles; + private boolean isCustomerRole; + private EntityStatus status; + private List customers; + private boolean isTeg; +} diff --git a/src/main/java/com/openAi/security/model/UserRequest.java b/src/main/java/com/openAi/security/model/UserRequest.java new file mode 100644 index 0000000..e1433ef --- /dev/null +++ b/src/main/java/com/openAi/security/model/UserRequest.java @@ -0,0 +1,10 @@ +package com.openAi.security.model; + +import lombok.Data; + +@Data +public class UserRequest { + private String user; + private String password; + private String oldPassword; +} diff --git a/src/main/java/com/openAi/security/model/UserRole.java b/src/main/java/com/openAi/security/model/UserRole.java new file mode 100644 index 0000000..38fac0b --- /dev/null +++ b/src/main/java/com/openAi/security/model/UserRole.java @@ -0,0 +1,35 @@ +package com.openAi.security.model; + +import lombok.Getter; + +public enum UserRole { + ADMIN(0), + MANAGER(1), + LEAD(2), + M4(3), + CSO(4), + RO(5), + TO(6), + I3(7), + I2(8), + I1(9), + WATCHER(10), + PEOPLE_GROUP(11), + M1(12), + M2(13), + I4(14), + A1(15), + A2(16), + A3(17), + M3(18), + CUSTOMER(19), + E1(20), + E2(21); + + @Getter + private final int value; + + UserRole(int value) { + this.value = value; + } +} diff --git a/src/main/java/com/openAi/security/model/UserTeamRolesModel.java b/src/main/java/com/openAi/security/model/UserTeamRolesModel.java new file mode 100644 index 0000000..dcfea87 --- /dev/null +++ b/src/main/java/com/openAi/security/model/UserTeamRolesModel.java @@ -0,0 +1,23 @@ +package com.openAi.security.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.openAi.security.entity.Roles; +import com.openAi.security.entity.Team; +import com.openAi.security.entity.User; +import lombok.*; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserTeamRolesModel { + private int id; + private User user; + private Roles userRole; + + @JsonIgnoreProperties( + value = {"teamLeads"}, + allowSetters = true) + private Team team; +} diff --git a/src/main/java/com/openAi/security/model/WebClientResponse.java b/src/main/java/com/openAi/security/model/WebClientResponse.java new file mode 100644 index 0000000..15e2316 --- /dev/null +++ b/src/main/java/com/openAi/security/model/WebClientResponse.java @@ -0,0 +1,23 @@ +package com.openAi.security.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class WebClientResponse { + private String displayName; + private String givenName; + private String mail; + private String mobilePhone; + private String id; + private String userPrincipalName; + private String type = "Bearer"; + private String token; + private Boolean isResetRequired; + private String reason; +} diff --git a/src/main/java/com/openAi/security/repository/AllowedDomainRepository.java b/src/main/java/com/openAi/security/repository/AllowedDomainRepository.java new file mode 100644 index 0000000..1c7b2e6 --- /dev/null +++ b/src/main/java/com/openAi/security/repository/AllowedDomainRepository.java @@ -0,0 +1,17 @@ +package com.openAi.security.repository; + +import com.drew.lang.annotations.NotNull; +import com.openAi.security.entity.AllowedDomain; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface AllowedDomainRepository extends JpaRepository { + + @NotNull + List findAll(); + @NotNull List findAllByDomainName(String domainName); + List findByTeamIdsContains(String teamId); +} diff --git a/src/main/java/com/openAi/security/repository/AttendanceRepository.java b/src/main/java/com/openAi/security/repository/AttendanceRepository.java new file mode 100644 index 0000000..5fc7d09 --- /dev/null +++ b/src/main/java/com/openAi/security/repository/AttendanceRepository.java @@ -0,0 +1,394 @@ +package com.openAi.security.repository; + + +import com.openAi.security.entity.Attendance; +import com.openAi.security.model.MonthValue; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +public interface AttendanceRepository extends JpaRepository { + + @Query(value = """ + select distinct concat(a.year,"-",a.month) from playbook.attendance a + order by a.year desc,a.month desc limit 1 + """, nativeQuery = true) + String getLatestMonthAndYear(); + + @Query(value = """ + SELECT * FROM attendance where + month in :month AND year=:year AND + (project_name like %:projectName% or project_name = :customerName) + AND employee_grade != 'Contract' """, nativeQuery = true) + List findAllByProjectName(Integer year, List month, String projectName, String customerName); + + @Query(value = """ + SELECT * FROM attendance a where + STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') <=:endDate + and (a.project_name like %:projectName% or a.project_name = :customerName) + AND a.employee_grade != 'Contract' """, nativeQuery = true) + List findAllByProjectNameAndDate(LocalDate startDate,LocalDate endDate, String projectName, String customerName); + + + @Query(value = """ + select distinct a.* FROM playbook.attendance a + where a.month = :month and a.year = :year + and a.employee_function not in ('IT','Administration','Account','Accounts','Account Management') + AND a.email_id NOT IN (SELECT user_email_id FROM playbook.kra_user_survey WHERE kra_cycle_id= :configId) + """, nativeQuery = true) + List findAllAttendanceSurvey(Integer year, Integer month,Integer configId); + @Query(value = """ + SELECT * FROM attendance where + month in :month AND year=:year + AND employee_grade != 'Contract' """, nativeQuery = true) + List findAllByYearAndMonth(Integer year, List month); + + + @Query(value = """ + SELECT * FROM attendance where + (project_name like %:projectName% or project_name = :customerName) + AND employee_grade != 'Contract' """, nativeQuery = true) + List findAllByProjectName(String projectName, String customerName); + + + @Query(value = """ + SELECT * FROM attendance where + month in :month AND year=:year AND + (employee_function like %:function%) + AND employee_grade != 'Contract' """, nativeQuery = true) + List findAllByEmployeeFunction(Integer year, List month, String function); + + @Query(value = """ + select a2.* FROM attendance a1 join attendance a2 + on a1.employee_name = a2.reporting_manager and a1.month = a2.month and a1.year = a2.year + join (select * from attendance where employee_grade = 'M2' and employee_function like %:function% and month in (:month) and year=:year) as a3 + on a1.reporting_manager = a3.employee_name and a1.month = a3.month and a1.year = a3.year + where a1.month in (:month) AND a1.year=:year + union + select a1.* FROM attendance a1 + join (select * from attendance where employee_grade = 'M2' and employee_function like %:function% and month in (:month) and year=:year) a2 + on a1.reporting_manager = a2.employee_name and a1.month = a2.month and a1.year = a2.year + where a1.month in (:month) AND a1.year=:year + """, nativeQuery = true) + List findAllByReportingManager(Integer year, List month, String function); + + + @Query(value= """ + select( + (select sum(story_points) from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id= :email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') <=:endDate and at.team_id in :teamId) + / + (select sum(story_points) from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') <=:endDate and at.team_id in :teamId and a.employee_function + in (select a.employee_function from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id=:email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') <=:endDate )))*100 as Result + """,nativeQuery = true) + Double getOwnerShipByEffort(List teamId, String email, LocalDate startDate, LocalDate endDate); + + + @Query(value = """ + select sum(present_days) from attendance a + where STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') <=:endDate\s + and a.email_id =:email + """,nativeQuery = true) + Double getDevelopmentDays(String email, LocalDate startDate, LocalDate endDate); + + @Query(value= """ + select sum(logged_hours)/avg(working_hours)*100 from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id= :email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')<=:endDate and at.team_id in (:teamId) + group by a.month,a.year + """,nativeQuery = true) + List getProductivity(List teamId,String email, LocalDate startDate,LocalDate endDate); + + + @Query(value= """ + select sum(logged_hours)/(8) from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id= :email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')<=:endDate and at.team_id in (:teamId) + group by a.month,a.year + """,nativeQuery = true) + List getProductivityInDays(List teamId,String email, LocalDate startDate,LocalDate endDate); + + @Query(value= """ + select sum(logged_hours)/avg(working_hours)*100 as value,a.month,a.year from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id= :email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')<=:endDate and at.team_id in (:teamId) + group by a.month,a.year + """,nativeQuery = true) + List getProductivityValues(List teamId, String email, LocalDate startDate, LocalDate endDate); + + + @Query(value= """ + select sum(story_points) * 22 /sum(a.present_days) from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id= :email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')<=:endDate and at.team_id in (:teamId) + group by a.month,a.year + """,nativeQuery = true) + List getStoryPoints(List teamId,String email, LocalDate startDate,LocalDate endDate); + + + @Query(value= """ + select sum(story_points) from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id= :email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')<=:endDate and at.team_id in (:teamId) + group by a.month,a.year + """,nativeQuery = true) + List getTotalStoryPoints(List teamId,String email, LocalDate startDate,LocalDate endDate); + + @Query(value= """ + select (sum(COALESCE(bug_fixes_story_points, 0) + COALESCE(enhancements_story_points, 0) + COALESCE(new_features_story_points, 0))/(sum(at.working_hours)/8))*22 sp + from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + and a.month = :month and a.year = :year and at.team_id = :teamId + """,nativeQuery = true) + Double getVelocityByTeamAndMonthAndYear(Integer teamId, Integer month, Integer year); + + @Query(value = """ + SELECT * FROM attendance where + month in :month AND year=:year AND + (employee_grade like 'A%') + AND employee_grade != 'Contract' """, nativeQuery = true) + List findAllByEmployeeGrade(Integer year, List month); + + @Query(value = "SELECT at FROM Attendance at where at.month=:month AND at.year=:year AND at.employeeName IN :employeeNames") + List getByMonthAndYearAndEmployeeNameIn(Integer month, Integer year, List employeeNames); + + @Query(value = "select * from attendance where email_id= :emailId and ((month >= :startMonth and year= :startYear) or (month <= :endMonth and year= :endYear)) order by year,month desc", nativeQuery = true) + List findByEmployeeEmailAndYearMonth(String emailId, Integer startMonth, Integer startYear, Integer endMonth, Integer endYear); + + @Query(value = "select * from attendance where email_id= :emailId and month >= :startMonth and month <= :endMonth and year= :year order by year,month desc", nativeQuery = true) + List findByEmployeeEmailAndYearMonth(String emailId, Integer startMonth, Integer endMonth, Integer year); + + List findByMonthAndYearAndFirstNameAndLastName(Integer month, Integer year, String firstName, String lastName); + + @Query(value = """ + SELECT * FROM attendance where + (project_name like %:projectName% or project_name = :customerName) + AND first_name = :firstName + AND last_name = :lastName + AND employee_grade != 'Contract' + """, nativeQuery = true) + List findByProjectNameAndFirstNameAndLastName(String projectName, String customerName, String firstName, String lastName); + + List findByMonthAndYearAndLastName(Integer month, Integer year, String lastName); + + List findByMonthAndYearAndLastNameAndProjectName(Integer month, Integer year, String lastName,String projectName); + + List findByMonthAndYearAndFirstNameAndProjectName(Integer month, Integer year, String firstName,String projectName); + + + List findByEmailIdOrderByYearDescMonthDesc(String email); + + @Query(value = "select * from attendance where reporting_manager= :name and month = :month and year= :year", nativeQuery = true) + List findByReportingManagerOrderByYearDescMonthDesc(String name,Integer year,Integer month); + + @Query(value = "select * from attendance where email_id= :email and month = :month and year= :year Limit 1", nativeQuery = true) + Attendance findByEmailAndYearAndMonth(String email, Integer year, Integer month); + + @Query(value = "select * from attendance where month = :month and year= :year Limit 5", nativeQuery = true) + List findByYearAndMonth(Integer year, Integer month); + + @Modifying + @Transactional + @Query(value = "delete FROM attendance where month = :month and year = :year", nativeQuery = true) + void deleteByMonthAndYear(Integer month, Integer year); + + @Modifying + @Transactional + @Query(value = "delete FROM attendance_team where attendance_id in (select id from attendance where month = :month and year = :year)", nativeQuery = true) + void deleteByMonthAndYearAttendanceTeam(Integer month, Integer year); + + @Query(value = "SELECT DISTINCT a.* FROM attendance AS a JOIN customers AS c ON a.project_name LIKE CONCAT('%', SUBSTRING(c.project_name, 1, LENGTH(a.project_name)), '%') WHERE c.id = :customerId AND ((a.year = :startYear AND a.month >= :startMonth) AND (a.year = :endYear AND a.month <= :endMonth));", nativeQuery = true) + List findByCustomerIdAndDateRanges(Long customerId, int startYear, int startMonth, int endYear, + int endMonth); + + @Query(value = "SELECT DISTINCT a.* FROM attendance AS a WHERE a.id IN( SELECT attendance_id FROM attendance_team WHERE team_id in :teamId ) AND ((month >= :startMonth and year= :startYear) or (month <= :endMonth and year= :endYear));", nativeQuery = true) + List findByTeamIdAndDateRanges(List teamId, int startYear, int startMonth, int endYear, int endMonth); + + @Query(value = "SELECT DISTINCT a.* FROM attendance AS a WHERE a.id IN( SELECT attendance_id FROM attendance_team WHERE team_id in :teamId ) AND (month >= :startMonth and year= :startYear and month <= :endMonth);", nativeQuery = true) + List findByTeamIdAndDateRanges(List teamId, int startYear, int startMonth, int endMonth); + + @Query(value = "SELECT DISTINCT a.employee_code,a.employee_name, a.employee_grade, a.employee_function ,at.team_id FROM attendance a join attendance_team at on a.id = at.attendance_id join team t on at.team_id = t.id WHERE ((month >= :startMonth and year= :startYear) or (month <= :endMonth and year= :endYear));", nativeQuery = true) + List> findByDateRanges(int startYear, int startMonth, int endYear, int endMonth); + + @Query(value = "SELECT DISTINCT a.employee_code,a.employee_name, a.employee_grade, a.employee_function ,at.team_id FROM attendance a join attendance_team at on a.id = at.attendance_id join team t on at.team_id = t.id WHERE (month >= :startMonth and year= :startYear and month <= :endMonth);", nativeQuery = true) + List> findByDateRanges(int startYear, int startMonth, int endMonth); + + @Query(value = "SELECT COALESCE(SUM(new_features),0) FROM attendance_team at JOIN attendance a ON at.attendance_id = a.id WHERE at.team_id = :teamId AND ((a.year = :year AND a.month = :month))", nativeQuery = true) + Integer findNewsFeaturesCountForDate(Long teamId, int year, int month); + + @Query(value = "SELECT COALESCE(SUM(enhancements),0) FROM attendance_team at JOIN attendance a ON at.attendance_id = a.id WHERE at.team_id = :teamId and ((a.year = :year AND a.month = :month))", nativeQuery = true) + Integer findEnhancementCountForDate(Long teamId, int year, int month); + + @Query(value = "SELECT COALESCE(SUM(bug_fixes),0) FROM attendance_team at JOIN attendance a ON at.attendance_id = a.id WHERE at.team_id = :teamId AND ((a.year = :year AND a.month = :month))", nativeQuery = true) + Integer findBugsFixesCountForDate(Long teamId, int year, int month); + + @Query(value = """ + select + (select sum(bug_fixes+enhancements+new_features) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where a.month >= :startMonth and a.month < :endMonth and year = :year)/ + ((select count(distinct(a.month)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where a.month >= :startMonth and a.month < :endMonth and year = :year)* + (select count(distinct(at.team_id)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where a.month >= :startMonth and a.month < :endMonth and year = :year) + ) as talenticaAvg + """, nativeQuery = true) + Double findAverageTrendCount(int year, int startMonth, int endMonth); + + @Query(value = """ + select + (select avg(story_points) from (select sum(bug_fixes_story_points + enhancements_story_points + new_features_story_points) as story_points from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where ((a.month >= :startMonth and year= :startYear) or (a.month < :endMonth and year = :endYear))) as storyPoints)/ + ((select count(distinct(a.month)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where ((a.month >= :startMonth and year= :startYear) or (a.month < :endMonth and year = :endYear)) + )*(select count(distinct(at.team_id)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where ((a.month >= :startMonth and year= :startYear) or (a.month < :endMonth and year = :endYear)))) as teamAvg + """, nativeQuery = true) + Double findAverageTrendCount(int startYear, int endYear, int startMonth, int endMonth); + + @Query(value = """ + select + (select avg(story_points) from (select sum(bug_fixes_story_points + enhancements_story_points + new_features_story_points) as story_points from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where a.month >= :startMonth and a.month < :endMonth and year = :year and at.team_id in :teamIds + ) as storyPoints )/ + ((select count(distinct(a.month)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where a.month >= :startMonth and a.month < :endMonth and year = :year and at.team_id in :teamIds + )*(select count(distinct(a.email_id)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where a.month >= :startMonth and a.month < :endMonth and year = :year and at.team_id in :teamIds)) as teamAvg + """, nativeQuery = true) + Double findAverageTrendCountByTeam(int year, int startMonth, int endMonth, List teamIds); + + @Query(value = """ + select + (select sum(bug_fixes_story_points+enhancements_story_points+new_features_story_points) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where ((a.month >= :startMonth and year= :startYear) or (a.month < :endMonth and year = :endYear)) and at.team_id in :teamIds + )/ + ((select count(distinct(a.month)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where ((a.month >= :startMonth and year= :startYear) or (a.month < :endMonth and year = :endYear)) and at.team_id in :teamIds + )*(select count(distinct(a.email_id)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where ((a.month >= :startMonth and year= :startYear) or (a.month < :endMonth and year = :endYear)) and at.team_id in :teamIds)) as teamAvg + """, nativeQuery = true) + Double findAverageTrendCountByTeam(int startYear, int endYear, int startMonth, int endMonth, List teamIds); + + @Query(value = """ + SELECT DISTINCT a.* FROM attendance AS a + where a.project_name = :projectName and month >= :startMonth and month<= :endMonth and year = :year + and employee_name in :employee + """, nativeQuery = true) + List findByProjectNameAndDateRangesAndEmployee(String projectName, Integer startMonth, Integer endMonth, Integer year, List employee); + + @Query(value = """ + SELECT DISTINCT a.* FROM attendance AS a + where month >= :startMonth and month<= :endMonth and year = :year + and email_id in :email and (employee_grade in ('M1','M2','M3') or employee_grade like 'A%') + """, nativeQuery = true) + List findByProjectNameAndDateRangesAndEmail(Integer startMonth, Integer endMonth, Integer year, List email); + + List findByMonthAndYearAndEmailIdIn(Integer month, Integer year, List emailIds); + + @Query(value = """ + SELECT a.year, a.month, COALESCE(SUM(new_features_story_points), 0) AS new_features, + COALESCE(SUM(enhancements_story_points), 0) AS enhancements, + COALESCE(SUM(bug_fixes_story_points), 0) AS bug_fixes, + Avg(new_features_story_points+enhancements_story_points+bug_fixes_story_points) as normalizedCount + FROM attendance_team at JOIN attendance a + ON at.attendance_id = a.id WHERE at.team_id in (:teamId) + AND STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') >= STR_TO_DATE(CONCAT(:startYear,'-',:startMonth,'-',1), '%Y-%m-%d')\s + AND STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') <= STR_TO_DATE(CONCAT(:endYear,'-',:endMonth,'-',1), '%Y-%m-%d') + GROUP BY a.year, a.month + """ + , nativeQuery = true) + List findCountsForDateRange(List teamId, int startYear, int startMonth, int endYear, int endMonth); + + + @Query(value = """ + SELECT a.year, a.month, COALESCE(SUM(new_features_story_points), 0) AS new_features, + COALESCE(SUM(enhancements_story_points), 0) AS enhancements, + COALESCE(SUM(bug_fixes_story_points), 0) AS bug_fixes, + Avg(new_features_story_points+enhancements_story_points+bug_fixes_story_points) as normalizedCount + FROM attendance_team at JOIN attendance a + ON at.attendance_id = a.id WHERE a.employee_function like %:customerName% + AND (((:startYear = :endYear) AND ((a.month >= :startMonth AND a.month <= :endMonth) + AND a.year = :startYear)) OR ((:startYear != :endYear) AND ((a.year >= :startYear AND a.month >= :startMonth) OR (a.year <= :endYear AND a.month <= :endMonth)))) GROUP BY a.year, a.month;""" + , nativeQuery = true) + List findCountsForDateRangeTegCustomer(String customerName, int startYear, int startMonth, int endYear, int endMonth); + @Query(value = """ + SELECT a.year, a.month, COALESCE(SUM(new_features_story_points), 0) AS new_features, + COALESCE(SUM(enhancements_story_points), 0) AS enhancements, + COALESCE(SUM(bug_fixes_story_points), 0) AS bug_fixes FROM attendance_team at\s + JOIN + (select a2.* FROM attendance a1 join attendance a2 + on a1.employee_name = a2.reporting_manager + and a1.reporting_manager in (select distinct employee_name from attendance where employee_grade = 'M2' and employee_function like %:customerName%) + where STR_TO_DATE(CONCAT('01-', a1.month,'-',a1.year), '%d-%m-%Y') >= STR_TO_DATE(CONCAT('01-', :startMonth,'-',:startYear), '%d-%m-%Y') + AND STR_TO_DATE(CONCAT('01-', a1.month,'-',a1.year), '%d-%m-%Y') <= STR_TO_DATE(CONCAT('01-', :endMonth,'-',:endYear), '%d-%m-%Y') + AND STR_TO_DATE(CONCAT('01-', a2.month,'-',a2.year), '%d-%m-%Y') >= STR_TO_DATE(CONCAT('01-', :startMonth,'-',:startYear), '%d-%m-%Y') + AND STR_TO_DATE(CONCAT('01-', a2.month,'-',a2.year), '%d-%m-%Y') <= STR_TO_DATE(CONCAT('01-', :endMonth,'-',:endYear), '%d-%m-%Y') \s + union + select a1.* FROM attendance a1 + where STR_TO_DATE(CONCAT('01-', a1.month,'-',a1.year), '%d-%m-%Y') >= STR_TO_DATE(CONCAT('01-', :startMonth,'-',:startYear), '%d-%m-%Y') + AND STR_TO_DATE(CONCAT('01-', a1.month,'-',a1.year), '%d-%m-%Y') <= STR_TO_DATE(CONCAT('01-', :endMonth,'-',:endYear), '%d-%m-%Y') + AND a1.reporting_manager in (select distinct employee_name from attendance where employee_grade = 'M2' and employee_function like %:customerName%))as a \s + ON at.attendance_id = a.id + GROUP BY a.year, a.month ; + """ + , nativeQuery = true) + List findCountsForDateRangeTegOpsCustomer(String customerName, int startYear, int startMonth, int endYear, int endMonth); + + @Query(value = """ + SELECT a.year, a.month, COALESCE(SUM(new_features_story_points), 0) AS new_features, + COALESCE(SUM(enhancements_story_points), 0) AS enhancements, + COALESCE(SUM(bug_fixes_story_points), 0) AS bug_fixes, + Avg(new_features_story_points+enhancements_story_points+bug_fixes_story_points) as normalizedCount + FROM attendance_team at JOIN attendance a + ON at.attendance_id = a.id WHERE a.employee_grade like 'A%' + AND (((:startYear = :endYear) AND ((a.month >= :startMonth AND a.month <= :endMonth) + AND a.year = :startYear)) OR ((:startYear != :endYear) AND ((a.year >= :startYear AND a.month >= :startMonth) OR (a.year <= :endYear AND a.month <= :endMonth)))) GROUP BY a.year, a.month;""" + , nativeQuery = true) + List findCountsForDateRangeTegCustomerArchitects(int startYear, int startMonth, int endYear, int endMonth); + + @Query(value = "select a.year, a.month, at.team_id from attendance a join attendance_team at on at.attendance_id = a.id", nativeQuery = true) + List> getRecentRecord(); + + + @Query(value = """ + SELECT SUM(bug_fixes_story_points+enhancements_story_points+new_features_story_points) + FROM attendance_team atm JOIN attendance a + ON atm.attendance_id = a.id + WHERE atm.team_id in :teamId AND month = :month AND year = :year + GROUP BY a.month, a.year + """ + , nativeQuery = true) + Double getAvgStoryPoints(List teamId, int month, int year); + + @Query(value = """ + SELECT distinct t.team_name + FROM attendance_team atm JOIN attendance a + ON atm.attendance_id = a.id + JOIN team t on atm.team_id = t.id + WHERE a.email_id = :email and (year, month) >= (:startYear, :startMonth) + and (year, month) <= (:endYear, :endMonth) + """ + , nativeQuery = true) + List getTeamHistory(String email, int startMonth, int startYear, int endMonth, int endYear); +} diff --git a/src/main/java/com/openAi/security/repository/CustomerCredentialRepository.java b/src/main/java/com/openAi/security/repository/CustomerCredentialRepository.java new file mode 100644 index 0000000..d58dfe1 --- /dev/null +++ b/src/main/java/com/openAi/security/repository/CustomerCredentialRepository.java @@ -0,0 +1,15 @@ +package com.openAi.security.repository; + +import com.openAi.security.entity.CustomerCredentials; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface CustomerCredentialRepository extends JpaRepository, JpaSpecificationExecutor { + List findAllByUserNameOrUserEmail(String userName,String userEmail); + List findAllByUserEmail(String userEmail); + +} diff --git a/src/main/java/com/openAi/security/repository/UserLogRepository.java b/src/main/java/com/openAi/security/repository/UserLogRepository.java new file mode 100644 index 0000000..371408b --- /dev/null +++ b/src/main/java/com/openAi/security/repository/UserLogRepository.java @@ -0,0 +1,11 @@ +package com.openAi.security.repository; + +import com.openAi.security.entity.UserLog; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Date; +import java.util.List; + +public interface UserLogRepository extends JpaRepository { + List findAllByUserIdAndLogInDate(Integer userId, Date logInDate); +} diff --git a/src/main/java/com/openAi/security/repository/UserRepository.java b/src/main/java/com/openAi/security/repository/UserRepository.java new file mode 100644 index 0000000..de04346 --- /dev/null +++ b/src/main/java/com/openAi/security/repository/UserRepository.java @@ -0,0 +1,36 @@ +package com.openAi.security.repository; + +import com.openAi.security.entity.User; +import com.openAi.security.enums.EntityStatus; +import com.openAi.security.enums.UserRole; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +/** User Repository. */ +@Repository +public interface UserRepository + extends JpaRepository, JpaSpecificationExecutor { + + Optional findByEmailIgnoreCaseAndStatus(String email, EntityStatus status); + + Optional findByEmailIgnoreCase(String email); + + Page findByStatusInAndRoleIn( + List statusList, + List role, + Specification specification, + Pageable paging); + + Optional findUserByEmail(String email); + + Optional findByNameIgnoreCase(String name); + + List findByStatusAndRoleNotIn(EntityStatus status, List roles); +} diff --git a/src/main/java/com/openAi/security/repository/UserTeamRoleRepository.java b/src/main/java/com/openAi/security/repository/UserTeamRoleRepository.java new file mode 100644 index 0000000..b9bceca --- /dev/null +++ b/src/main/java/com/openAi/security/repository/UserTeamRoleRepository.java @@ -0,0 +1,31 @@ +package com.openAi.security.repository; + +import com.openAi.security.entity.Roles; +import com.openAi.security.entity.UserTeamRoles; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + + +import java.util.List; + +@Repository +public interface UserTeamRoleRepository extends JpaRepository { + List findByUserRole(Roles userRoles); + + UserTeamRoles findByUserIdAndTeamId(Integer user, Integer team); + + List findAllByTeam_Id(Integer team); + + @Modifying + @Transactional + @Query(value = "delete from playbook.user_team_roles where team_id = :team", nativeQuery = true) + void deleteByTeam_Id(Integer team); + + @Modifying + @Transactional + @Query(value = "delete from playbook.user_team_roles where user_id = :user", nativeQuery = true) + void deleteByUser_Id(Integer user); +} diff --git a/src/main/java/com/openAi/security/service/UserService.java b/src/main/java/com/openAi/security/service/UserService.java new file mode 100644 index 0000000..5a11824 --- /dev/null +++ b/src/main/java/com/openAi/security/service/UserService.java @@ -0,0 +1,23 @@ +package com.openAi.security.service; + +import com.openAi.security.entity.User; +import com.openAi.security.model.UserModel; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.Map; + +/** + * UserService. + */ +public interface UserService { + + + UserModel findUserByEmailOrAttendance(String email); + + UserModel findUserByEmail(String email); + + void saveUserLog(String userEmail); +} diff --git a/src/main/java/com/openAi/security/service/UserServiceImpl.java b/src/main/java/com/openAi/security/service/UserServiceImpl.java new file mode 100644 index 0000000..0ea3d63 --- /dev/null +++ b/src/main/java/com/openAi/security/service/UserServiceImpl.java @@ -0,0 +1,111 @@ +package com.openAi.security.service; + +import com.openAi.security.repository.AttendanceRepository; +import com.openAi.security.repository.CustomerCredentialRepository; +import com.openAi.security.repository.UserLogRepository; +import com.openAi.security.repository.UserTeamRoleRepository; +import com.openAi.security.entity.Attendance; +import com.openAi.security.enums.UserRole; +import com.openAi.security.mapper.UserMapper; +import com.openAi.security.model.UserModel; +import lombok.extern.slf4j.Slf4j; +import org.mapstruct.factory.Mappers; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +import static com.openAi.security.enums.EntityStatus.ACTIVE; + +/** + * UserService Implementation. + */ +@Slf4j +@Service +public class UserServiceImpl implements UserService { + + private final UserMapper userMapper = Mappers.getMapper(UserMapper.class); + private final String LOGIN = "login"; + +/* @Autowired + UserRepository userRepository;*/ + @Autowired +UserTeamRoleRepository userTeamRoleRepository; + @Autowired + AttendanceRepository attendanceRepository; + @Autowired + CustomerCredentialRepository customerCredentialRepository; + @Autowired + PasswordEncoder passwordEncoder; + + @Value("${customer-login.site-url}") + private String siteURL; + + @Value("${customer-login.login-endpoint}") + private String loginEndPoint; + @Autowired + private UserLogRepository userLogRepository; + + @Override + public UserModel findUserByEmailOrAttendance(String email) { + UserModel userModel = null; + try { + userModel = findUserByEmail(email); + } catch (Exception e) { + List attendanceList = attendanceRepository.findByEmailIdOrderByYearDescMonthDesc(email); + if (attendanceList == null || attendanceList.isEmpty()) { + throw new javax.persistence.EntityNotFoundException("User not found with email " + email); + } + UserRole role = UserRole.valueOf("People Group".equals(attendanceList.get(0).getEmployeeFunction()) + ? "PEOPLE_GROUP" : attendanceList.get(0).getEmployeeGrade()); + userModel = new UserModel( + null, attendanceList.get(0).getEmployeeName(), role, email, new ArrayList<>(), new ArrayList<>(), false, ACTIVE, new ArrayList<>(), false + ); + } + return userModel; + } + + @Override + public UserModel findUserByEmail(String email) { + /*log.debug("Finding user with email: {}", email); + User user = + userRepository + .findByEmailIgnoreCaseAndStatus(email, ACTIVE) + .orElseThrow(() -> EntityNotFoundException.user("User not found with email " + email)); + UserModel userModel = userMapper.entityToModel(user); + userModel.setCustomers(user.getTeams().stream().map(Team::getCustomer).toList()); + return userModel;*/ + return null; + } + + @Override + public void saveUserLog(String email) { +/* + try { + Optional optionalUser = userRepository.findUserByEmail(email); + if (optionalUser.isPresent()) { + User user = optionalUser.get(); + Date date = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()); + List logs = userLogRepository.findAllByUserIdAndLogInDate(user.getId(), date); + var userLogBuilder = UserLog.builder(); + if (!logs.isEmpty()) { + userLogBuilder.id(logs.get(0).getId()); + } + + UserLog log = userLogBuilder + .userId(user.getId()) + .logInDate(date) + .build(); + userLogRepository.save(log); + } + } catch (Exception e) { + log.error(e.getMessage()); + } +*/ + + } + +} diff --git a/src/main/java/com/openAi/security/utils/JpaConfig.java b/src/main/java/com/openAi/security/utils/JpaConfig.java new file mode 100644 index 0000000..edb9b1f --- /dev/null +++ b/src/main/java/com/openAi/security/utils/JpaConfig.java @@ -0,0 +1,22 @@ +//package com.openAi.security.utils; +// +//import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +// +//import javax.sql.DataSource; +// +//@Configuration +//public class JpaConfig { +// +// @Bean +// public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, +// DataSource dataSource) { +// return builder +// .dataSource(dataSource) +// .packages("com.openAi.security.entity") +// .persistenceUnit("default") +// .build(); +// } +//} diff --git a/src/main/java/com/openAi/security/utils/JwtUtils.java b/src/main/java/com/openAi/security/utils/JwtUtils.java new file mode 100644 index 0000000..7baac6e --- /dev/null +++ b/src/main/java/com/openAi/security/utils/JwtUtils.java @@ -0,0 +1,73 @@ +package com.openAi.security.utils; + +import com.openAi.security.exceptions.InvalidAuthenticationException; +import io.jsonwebtoken.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; + +@Component +public class JwtUtils { + + private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class); + + @Value("${security.jwtSecret}") + private String jwtSecret; + + @Value("${security.jwtExpirationMs}") + private int jwtExpirationMs; + + public String getJWTToken(String username) { + List grantedAuthorities = + AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"); + + String token = + Jwts.builder() + .setId("softtekJWT") + .setSubject(username) + .claim( + "authorities", + grantedAuthorities.stream() + .map(GrantedAuthority::getAuthority) + .toList()) + .setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + jwtExpirationMs)) + .signWith(SignatureAlgorithm.HS512, jwtSecret) + .compact(); + logger.info("Token successfully generated for user: {}", username); + return token; + } + + public void validateJwtToken(String authToken) { + try { + Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken).getBody(); + } + catch (SignatureException|MalformedJwtException|UnsupportedJwtException|IllegalArgumentException e) { + throw e; + } catch (ExpiredJwtException e) { + final String errorMessage = String.format("JWT token is expired | %s", e.getMessage()); + throw InvalidAuthenticationException.invalidToken(errorMessage); + } + } + + public String getSubject(String jwt) { + return getAllClaimsFromToken(jwt).getSubject(); + } + + public Claims getAllClaimsFromToken(String token) { + Claims claims; + try { + claims = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody(); + } catch (Exception e) { + logger.error("Could not get all claims Token from passed token"); + claims = null; + } + return claims; + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1fd37ae..c1e2606 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,6 +1,23 @@ spring: application: name: demo + jpa: + properties: + hibernate: + jdbc: + time_zone: Asia/Kolkata + enable_lazy_load_no_trans: true + hibernate: + ddl-auto: update + datasource: + hikari: + minimumIdle: 2 + maximumPoolSize: 10 + url: jdbc:mysql://localhost:3306/playbook + username: root + password: password + driver-class-name: com.mysql.cj.jdbc.Driver + ddl-auto: update ai: vectorstore: redis: @@ -15,3 +32,7 @@ spring: temperature: 0.3 api-key: ${OPEN-AI-KEY} model: gpt-3.5-turbo +security: + jwtSecret: cdfe45gfbcnhf + jwtExpirationMs: 604800000 + apiKey: 53e72eed-6f0b-4d5b-9cc5-088487d969b9 From 86ca11abd69777ec118f266a2300c96ce5e2ef13 Mon Sep 17 00:00:00 2001 From: krishnaBaile Date: Fri, 3 Jan 2025 16:46:56 +0530 Subject: [PATCH 2/9] unnecessary redis implementation removed --- src/main/java/com/openAi/ai/RedisConfig.java | 25 --------- src/main/java/com/openAi/ai/RedisService.java | 53 ------------------- .../com/openAi/security/utils/JpaConfig.java | 44 +++++++-------- 3 files changed, 22 insertions(+), 100 deletions(-) delete mode 100644 src/main/java/com/openAi/ai/RedisConfig.java delete mode 100644 src/main/java/com/openAi/ai/RedisService.java diff --git a/src/main/java/com/openAi/ai/RedisConfig.java b/src/main/java/com/openAi/ai/RedisConfig.java deleted file mode 100644 index c92d643..0000000 --- a/src/main/java/com/openAi/ai/RedisConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.openAi.ai; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -@Configuration -public class RedisConfig { - - @Bean - public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { - RedisTemplate template = new RedisTemplate<>(); - template.setConnectionFactory(connectionFactory); - - // Key serializer - template.setKeySerializer(new StringRedisSerializer()); - // Value serializer - //template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); - - return template; - } -} \ No newline at end of file diff --git a/src/main/java/com/openAi/ai/RedisService.java b/src/main/java/com/openAi/ai/RedisService.java deleted file mode 100644 index 51469a7..0000000 --- a/src/main/java/com/openAi/ai/RedisService.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.openAi.ai; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.connection.DataType; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -@Service -public class RedisService { - - @Autowired - private RedisTemplate redisTemplate; - - @Autowired - private ObjectMapper objectMapper; - - public List getKeysByJsonNodeValue(String nodeName, String nodeValue) { - List matchingKeys = new ArrayList<>(); - Set keys = redisTemplate.keys("*"); - - if (keys != null) { - for (String key : keys) { - System.out.println("key: " + key); - - Object value = redisTemplate.opsForValue().get(key); - if (value != null) { - try { - JsonNode jsonNode = objectMapper.readTree(value.toString()); - if (jsonNode.has(nodeName) && jsonNode.get(nodeName).asText().equals(nodeValue)) { - matchingKeys.add(key); - } - } catch (Exception e) { - System.err.println("Error parsing JSON for key: " + key + " - " + e.getMessage()); - } - } - } - - - } - - - return matchingKeys; - } - /* public List getKeysByJsonNodeValue(String nodeName, String nodeValue) { - return new ArrayList<>(); - }*/ -} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/utils/JpaConfig.java b/src/main/java/com/openAi/security/utils/JpaConfig.java index edb9b1f..f132e6c 100644 --- a/src/main/java/com/openAi/security/utils/JpaConfig.java +++ b/src/main/java/com/openAi/security/utils/JpaConfig.java @@ -1,22 +1,22 @@ -//package com.openAi.security.utils; -// -//import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; -//import org.springframework.context.annotation.Bean; -//import org.springframework.context.annotation.Configuration; -//import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; -// -//import javax.sql.DataSource; -// -//@Configuration -//public class JpaConfig { -// -// @Bean -// public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, -// DataSource dataSource) { -// return builder -// .dataSource(dataSource) -// .packages("com.openAi.security.entity") -// .persistenceUnit("default") -// .build(); -// } -//} +package com.openAi.security.utils; + +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; + +import javax.sql.DataSource; + +@Configuration +public class JpaConfig { + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, + DataSource dataSource) { + return builder + .dataSource(dataSource) + .packages("com.openAi.security.entity") + .persistenceUnit("default") + .build(); + } +} From 03c0959c0e198cc03f512672d0b3f4999bfa8a30 Mon Sep 17 00:00:00 2001 From: krishnaBaile Date: Mon, 6 Jan 2025 13:15:17 +0530 Subject: [PATCH 3/9] spring boot 3 upgrade --- pom.xml | 100 +++++++++++------- src/main/java/com/openAi/ai/OpenAiApi.java | 22 ++++ .../openAi/application/OpenAiApplication.java | 9 +- .../openAi/security/AuthenticationFilter.java | 8 +- .../openAi/security/WebSecurityConfig.java | 99 ++++++++--------- .../security/controller/AuthController.java | 4 +- .../openAi/security/entity/AllowedDomain.java | 2 +- .../openAi/security/entity/Attendance.java | 12 +-- .../com/openAi/security/entity/Customer.java | 2 +- .../security/entity/CustomerCredentials.java | 2 +- .../com/openAi/security/entity/Roles.java | 2 +- .../java/com/openAi/security/entity/Team.java | 4 +- .../java/com/openAi/security/entity/User.java | 4 +- .../com/openAi/security/entity/UserLog.java | 2 +- .../openAi/security/entity/UserTeamRoles.java | 8 +- .../openAi/security/service/UserService.java | 2 +- .../security/service/UserServiceImpl.java | 2 +- .../com/openAi/security/utils/JpaConfig.java | 8 +- src/main/resources/application.yml | 18 ++-- 19 files changed, 182 insertions(+), 128 deletions(-) create mode 100644 src/main/java/com/openAi/ai/OpenAiApi.java diff --git a/pom.xml b/pom.xml index 55fe9be..73c973c 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.6.4 + 3.3.5 com.openAi @@ -31,6 +31,13 @@ 1.0.0-M3 + + + io.micrometer + micrometer-core + + + org.springframework.boot spring-boot-starter-web @@ -39,6 +46,17 @@ org.springframework.boot spring-boot-starter-webflux + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.ai spring-ai-openai-spring-boot-starter @@ -55,74 +73,76 @@ org.springframework.ai spring-ai-redis-store-spring-boot-starter - - org.springframework.ai - spring-ai-transformers-spring-boot-starter - + + + + + + redis.clients jedis - 4.2.3 - - - org.springframework.boot - spring-boot-starter-test - test - - - io.projectreactor - reactor-test - test - - - - spring-boot-starter-security - org.springframework.boot + + org.projectlombok lombok - 1.18.34 provided - - org.springframework.data - spring-data-jpa - 2.6.2 - + + org.springframework.boot spring-boot-starter-data-jpa + + - org.hibernate - hibernate-core - 5.6.5.Final + com.mysql + mysql-connector-j - + + - mysql-connector-java - mysql - 8.0.30 + io.jsonwebtoken + jjwt-api + 0.11.5 - - jjwt io.jsonwebtoken - 0.9.1 + jjwt-impl + 0.11.5 + runtime - mapstruct + io.jsonwebtoken + jjwt-jackson + 0.11.5 + runtime + + + + org.mapstruct - 1.5.2.Final + mapstruct + 1.5.5.Final org.mapstruct mapstruct-processor - 1.5.2.Final + 1.5.5.Final provided + + + + jakarta.annotation + jakarta.annotation-api + + + diff --git a/src/main/java/com/openAi/ai/OpenAiApi.java b/src/main/java/com/openAi/ai/OpenAiApi.java new file mode 100644 index 0000000..a91238b --- /dev/null +++ b/src/main/java/com/openAi/ai/OpenAiApi.java @@ -0,0 +1,22 @@ +package com.openAi.ai; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +public class OpenAiApi { + @Data public static class EmbeddingList { + @JsonProperty("data") + private List data; + + // Getters and setters + } + + @Data public static class Embedding { + @JsonProperty("embedding") + private List embedding; + + // Getters and setters + } +} \ No newline at end of file diff --git a/src/main/java/com/openAi/application/OpenAiApplication.java b/src/main/java/com/openAi/application/OpenAiApplication.java index f40c0bb..f114958 100644 --- a/src/main/java/com/openAi/application/OpenAiApplication.java +++ b/src/main/java/com/openAi/application/OpenAiApplication.java @@ -2,6 +2,10 @@ import com.openAi.security.AuthenticationFilter; +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.openai.OpenAiChatModel; +import org.springframework.ai.openai.api.OpenAiApi; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; @@ -18,5 +22,8 @@ public class OpenAiApplication { public static void main(String[] args) { SpringApplication.run(OpenAiApplication.class, args); } - + @Bean + ChatModel chatModel(@Value("${spring.ai.openai.api-key}") String apiKey) { + return new OpenAiChatModel(new OpenAiApi(apiKey)); + } } diff --git a/src/main/java/com/openAi/security/AuthenticationFilter.java b/src/main/java/com/openAi/security/AuthenticationFilter.java index 1f1cf4f..0764ae2 100644 --- a/src/main/java/com/openAi/security/AuthenticationFilter.java +++ b/src/main/java/com/openAi/security/AuthenticationFilter.java @@ -21,10 +21,10 @@ import org.springframework.web.context.support.SpringBeanAutowiringSupport; import org.springframework.web.filter.OncePerRequestFilter; -import javax.servlet.FilterChain; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.FilterChain; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.util.Collections; import java.util.Date; import java.util.Objects; diff --git a/src/main/java/com/openAi/security/WebSecurityConfig.java b/src/main/java/com/openAi/security/WebSecurityConfig.java index 1b7edd7..564d18e 100644 --- a/src/main/java/com/openAi/security/WebSecurityConfig.java +++ b/src/main/java/com/openAi/security/WebSecurityConfig.java @@ -7,14 +7,13 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.http.HttpStatus; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.authentication.HttpStatusEntryPoint; +import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @@ -23,62 +22,57 @@ import java.util.List; @Configuration -@EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true) +@EnableMethodSecurity(prePostEnabled = true) @RequiredArgsConstructor -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { +public class WebSecurityConfig { private final AuthenticationFilter filter; - private final AllowedDomainRepository allowedDomainRepository; - private CorsConfiguration configuration = new CorsConfiguration(); + private final CorsConfiguration configuration = new CorsConfiguration(); - @Override - protected void configure(HttpSecurity http) throws Exception { + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.cors() - .and() - .csrf() - .disable() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .and() - .authorizeRequests() - .antMatchers("/getToken", - "/getTokenUserAuth", - "/user/generatePassword", - "/resetPassword", - "/getTokenGoogleAuth" - ) - .permitAll() - .anyRequest() - .authenticated() - .and() - .exceptionHandling() - .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) - .and() - .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class); + .and() + .csrf().disable() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeHttpRequests(authorize -> authorize + .requestMatchers( + "/getToken", + "/getTokenUserAuth", + "/user/generatePassword", + "/resetPassword", + "/getTokenGoogleAuth" + ).permitAll() + .anyRequest().authenticated() + ) + .exceptionHandling() + .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) + .and() + .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class); + + return http.build(); } @Bean - @Profile({"dev","staging","prod"}) + @Profile({"dev", "staging", "prod"}) public CorsConfigurationSource corsConfigurationSource() { updateCorsConfiguration(); configuration.addExposedHeader("Set-Cookie"); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); - // setAllowCredentials(true) is important, otherwise: - // The value of the 'Access-Control-Allow-Origin' header in the response must not be the - // wildcard '*' when the request's credentials mode is 'include'. - // setAllowedHeaders is important! Without it, OPTIONS preflight request - // will fail with 403 Invalid CORS request configuration.setAllowedHeaders( - List.of( - "Api-Key", - "Authorization", - "Cache-Control", - "Content-Type", - "Access-Control-Allow-Origin", - "Access-Control-Allow-Credentials")); + List.of( + "Api-Key", + "Authorization", + "Cache-Control", + "Content-Type", + "Access-Control-Allow-Origin", + "Access-Control-Allow-Credentials" + ) + ); configuration.setAllowCredentials(true); final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); @@ -107,14 +101,11 @@ public CorsConfigurationSource corsConfigurationSourceTest() { "https://staging.kb.talentica.com/", "https://stagingknowledgebase.talentica.com/", "https://nexus.talentica.com/", - "https://kb.talentica.com/")); + "https://kb.talentica.com/" + ) + ); configuration.addExposedHeader("Set-Cookie"); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); - // setAllowCredentials(true) is important, otherwise: - // The value of the 'Access-Control-Allow-Origin' header in the response must not be the - // wildcard '*' when the request's credentials mode is 'include'. - // setAllowedHeaders is important! Without it, OPTIONS preflight request - // will fail with 403 Invalid CORS request configuration.setAllowedHeaders( List.of( "Api-Key", @@ -122,7 +113,9 @@ public CorsConfigurationSource corsConfigurationSourceTest() { "Cache-Control", "Content-Type", "Access-Control-Allow-Origin", - "Access-Control-Allow-Credentials")); + "Access-Control-Allow-Credentials" + ) + ); configuration.setAllowCredentials(true); final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); @@ -130,7 +123,7 @@ public CorsConfigurationSource corsConfigurationSourceTest() { return source; } - public void updateCorsConfiguration() { + void updateCorsConfiguration() { List origins = allowedDomainRepository.findAll() .stream().map(AllowedDomain::getDomainName).toList(); configuration.setAllowedOrigins(origins); diff --git a/src/main/java/com/openAi/security/controller/AuthController.java b/src/main/java/com/openAi/security/controller/AuthController.java index 52a7b44..fe07fe9 100644 --- a/src/main/java/com/openAi/security/controller/AuthController.java +++ b/src/main/java/com/openAi/security/controller/AuthController.java @@ -21,8 +21,8 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.reactive.function.client.WebClient; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.net.MalformedURLException; import java.net.URL; import java.util.Date; diff --git a/src/main/java/com/openAi/security/entity/AllowedDomain.java b/src/main/java/com/openAi/security/entity/AllowedDomain.java index 4c569cc..3f92251 100644 --- a/src/main/java/com/openAi/security/entity/AllowedDomain.java +++ b/src/main/java/com/openAi/security/entity/AllowedDomain.java @@ -5,7 +5,7 @@ import lombok.Data; import lombok.NoArgsConstructor; -import javax.persistence.*; +import jakarta.persistence.*; import java.time.LocalDate; @Entity diff --git a/src/main/java/com/openAi/security/entity/Attendance.java b/src/main/java/com/openAi/security/entity/Attendance.java index a3d2747..01bbe4c 100644 --- a/src/main/java/com/openAi/security/entity/Attendance.java +++ b/src/main/java/com/openAi/security/entity/Attendance.java @@ -2,12 +2,12 @@ import lombok.*; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import java.util.Date; @Entity diff --git a/src/main/java/com/openAi/security/entity/Customer.java b/src/main/java/com/openAi/security/entity/Customer.java index 519a969..add4481 100644 --- a/src/main/java/com/openAi/security/entity/Customer.java +++ b/src/main/java/com/openAi/security/entity/Customer.java @@ -5,7 +5,7 @@ import lombok.*; import lombok.experimental.Accessors; -import javax.persistence.*; +import jakarta.persistence.*; import java.time.LocalDate; import java.util.List; diff --git a/src/main/java/com/openAi/security/entity/CustomerCredentials.java b/src/main/java/com/openAi/security/entity/CustomerCredentials.java index 6056490..5d871c2 100644 --- a/src/main/java/com/openAi/security/entity/CustomerCredentials.java +++ b/src/main/java/com/openAi/security/entity/CustomerCredentials.java @@ -4,7 +4,7 @@ import lombok.Setter; import lombok.experimental.Accessors; -import javax.persistence.*; +import jakarta.persistence.*; import java.util.Date; @Entity diff --git a/src/main/java/com/openAi/security/entity/Roles.java b/src/main/java/com/openAi/security/entity/Roles.java index 132490a..e303a13 100644 --- a/src/main/java/com/openAi/security/entity/Roles.java +++ b/src/main/java/com/openAi/security/entity/Roles.java @@ -5,7 +5,7 @@ import lombok.Setter; import lombok.experimental.Accessors; -import javax.persistence.*; +import jakarta.persistence.*; @Entity @Getter diff --git a/src/main/java/com/openAi/security/entity/Team.java b/src/main/java/com/openAi/security/entity/Team.java index 5ec20b0..85a0910 100644 --- a/src/main/java/com/openAi/security/entity/Team.java +++ b/src/main/java/com/openAi/security/entity/Team.java @@ -9,8 +9,8 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.data.jpa.domain.Specification; -import javax.persistence.*; -import javax.persistence.criteria.JoinType; +import jakarta.persistence.*; +import jakarta.persistence.criteria.JoinType; import java.time.LocalDate; import java.util.List; diff --git a/src/main/java/com/openAi/security/entity/User.java b/src/main/java/com/openAi/security/entity/User.java index 07ccad0..c3a1b3b 100644 --- a/src/main/java/com/openAi/security/entity/User.java +++ b/src/main/java/com/openAi/security/entity/User.java @@ -11,8 +11,8 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.data.jpa.domain.Specification; -import javax.persistence.*; -import javax.persistence.criteria.JoinType; +import jakarta.persistence.*; +import jakarta.persistence.criteria.JoinType; import java.util.List; /** diff --git a/src/main/java/com/openAi/security/entity/UserLog.java b/src/main/java/com/openAi/security/entity/UserLog.java index 6427dd8..e85cc7f 100644 --- a/src/main/java/com/openAi/security/entity/UserLog.java +++ b/src/main/java/com/openAi/security/entity/UserLog.java @@ -3,7 +3,7 @@ import lombok.*; import lombok.experimental.Accessors; -import javax.persistence.*; +import jakarta.persistence.*; import java.util.Date; @Entity diff --git a/src/main/java/com/openAi/security/entity/UserTeamRoles.java b/src/main/java/com/openAi/security/entity/UserTeamRoles.java index a1664a4..693ce0f 100644 --- a/src/main/java/com/openAi/security/entity/UserTeamRoles.java +++ b/src/main/java/com/openAi/security/entity/UserTeamRoles.java @@ -1,9 +1,10 @@ package com.openAi.security.entity; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.*; import lombok.experimental.Accessors; -import javax.persistence.*; +import jakarta.persistence.*; @Entity @Getter @@ -27,5 +28,8 @@ public class UserTeamRoles{ @JoinColumn(name = "role_id") private Roles userRole; - + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "team_id") + @JsonIgnoreProperties(value = {"teamLeads"}, allowSetters = true) + private Team team; } diff --git a/src/main/java/com/openAi/security/service/UserService.java b/src/main/java/com/openAi/security/service/UserService.java index 5a11824..0336262 100644 --- a/src/main/java/com/openAi/security/service/UserService.java +++ b/src/main/java/com/openAi/security/service/UserService.java @@ -5,7 +5,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.List; import java.util.Map; diff --git a/src/main/java/com/openAi/security/service/UserServiceImpl.java b/src/main/java/com/openAi/security/service/UserServiceImpl.java index 0ea3d63..926c60c 100644 --- a/src/main/java/com/openAi/security/service/UserServiceImpl.java +++ b/src/main/java/com/openAi/security/service/UserServiceImpl.java @@ -57,7 +57,7 @@ public UserModel findUserByEmailOrAttendance(String email) { } catch (Exception e) { List attendanceList = attendanceRepository.findByEmailIdOrderByYearDescMonthDesc(email); if (attendanceList == null || attendanceList.isEmpty()) { - throw new javax.persistence.EntityNotFoundException("User not found with email " + email); + throw new jakarta.persistence.EntityNotFoundException("User not found with email " + email); } UserRole role = UserRole.valueOf("People Group".equals(attendanceList.get(0).getEmployeeFunction()) ? "PEOPLE_GROUP" : attendanceList.get(0).getEmployeeGrade()); diff --git a/src/main/java/com/openAi/security/utils/JpaConfig.java b/src/main/java/com/openAi/security/utils/JpaConfig.java index f132e6c..bae16bb 100644 --- a/src/main/java/com/openAi/security/utils/JpaConfig.java +++ b/src/main/java/com/openAi/security/utils/JpaConfig.java @@ -1,5 +1,6 @@ package com.openAi.security.utils; +import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -11,12 +12,15 @@ public class JpaConfig { @Bean - public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, - DataSource dataSource) { + public LocalContainerEntityManagerFactoryBean entityManagerFactory( + EntityManagerFactoryBuilder builder, + DataSource dataSource, + JpaProperties jpaProperties) { return builder .dataSource(dataSource) .packages("com.openAi.security.entity") .persistenceUnit("default") + .properties(jpaProperties.getProperties()) .build(); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index c1e2606..43dc9bc 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -20,13 +20,13 @@ spring: ddl-auto: update ai: vectorstore: - redis: - host: localhost - port: 6379 - database: 0 - index: faqs - prefix: "faq:" - initialize-schema: true +# redis: +# host: localhost +# port: 6379 +# database: 0 +# index: faqs +# prefix: "faq:" +# initialize-schema: true openai: temperature: 0.3 @@ -36,3 +36,7 @@ security: jwtSecret: cdfe45gfbcnhf jwtExpirationMs: 604800000 apiKey: 53e72eed-6f0b-4d5b-9cc5-088487d969b9 + +customer-login: + site-url: https://dev-orion.talentica.com + login-endpoint: /login \ No newline at end of file From 73304d912b0f78e55494ec1f3d22981114b510ff Mon Sep 17 00:00:00 2001 From: krishnaBaile Date: Mon, 6 Jan 2025 16:06:36 +0530 Subject: [PATCH 4/9] security implementation --- pom.xml | 5 + .../openAi/application/OpenAiApplication.java | 43 +++++-- .../openAi/security/WebSecurityConfig.java | 60 ++++++--- .../security/controller/UserController.java | 121 ++++++++++++++++++ .../openAi/security/entity/AllowedDomain.java | 7 + .../security/entity/CustomerCredentials.java | 1 + .../com/openAi/security/entity/UserLog.java | 1 + .../openAi/security/entity/UserTeamRoles.java | 1 + .../openAi/security/enums/AppConstant.java | 8 ++ .../security/mapper/UserTeamRolesMapper.java | 12 ++ .../security/model/UserListViewResponse.java | 23 ++++ .../security/repository/RolesRepository.java | 9 ++ .../openAi/security/service/UserService.java | 7 + .../security/service/UserServiceImpl.java | 97 +++++++++++--- .../security/service/UserTeamRoleService.java | 10 ++ .../service/UserTeamRoleServiceImpl.java | 36 ++++++ .../openAi/security/utils/SessionUtils.java | 35 +++++ 17 files changed, 434 insertions(+), 42 deletions(-) create mode 100644 src/main/java/com/openAi/security/controller/UserController.java create mode 100644 src/main/java/com/openAi/security/enums/AppConstant.java create mode 100644 src/main/java/com/openAi/security/mapper/UserTeamRolesMapper.java create mode 100644 src/main/java/com/openAi/security/model/UserListViewResponse.java create mode 100644 src/main/java/com/openAi/security/repository/RolesRepository.java create mode 100644 src/main/java/com/openAi/security/service/UserTeamRoleService.java create mode 100644 src/main/java/com/openAi/security/service/UserTeamRoleServiceImpl.java create mode 100644 src/main/java/com/openAi/security/utils/SessionUtils.java diff --git a/pom.xml b/pom.xml index 73c973c..0abfd43 100644 --- a/pom.xml +++ b/pom.xml @@ -140,6 +140,11 @@ jakarta.annotation jakarta.annotation-api + + org.apache.tomcat.embed + tomcat-embed-core + 10.1.25 + diff --git a/src/main/java/com/openAi/application/OpenAiApplication.java b/src/main/java/com/openAi/application/OpenAiApplication.java index f114958..527d040 100644 --- a/src/main/java/com/openAi/application/OpenAiApplication.java +++ b/src/main/java/com/openAi/application/OpenAiApplication.java @@ -1,6 +1,5 @@ package com.openAi.application; - import com.openAi.security.AuthenticationFilter; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.openai.OpenAiChatModel; @@ -9,21 +8,43 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -@SpringBootApplication(scanBasePackages = "com.openAi") +@SpringBootApplication(scanBasePackages = "com.openAi", exclude = {SecurityAutoConfiguration.class}) @EnableJpaRepositories(basePackages = "com.openAi.security.repository") @EntityScan(basePackages = "com.openAi.security.entity") public class OpenAiApplication { - public static void main(String[] args) { - SpringApplication.run(OpenAiApplication.class, args); - } - @Bean - ChatModel chatModel(@Value("${spring.ai.openai.api-key}") String apiKey) { - return new OpenAiChatModel(new OpenAiApi(apiKey)); - } -} + public static void main(String[] args) { + SpringApplication.run(OpenAiApplication.class, args); + } + + @Bean + ChatModel chatModel(@Value("${spring.ai.openai.api-key}") String apiKey) { + return new OpenAiChatModel(new OpenAiApi(apiKey)); + } + + @Bean + public UsernamePasswordAuthenticationFilter authenticationFilter(AuthenticationManager authenticationManager) { + UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(); + filter.setAuthenticationManager(authenticationManager); + return filter; + } + + @Bean + public FilterRegistrationBean filterRegistrationBean() { + AuthenticationFilter filter = new AuthenticationFilter(); + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(filter); + registrationBean.setEnabled(false); + return registrationBean; + } + + +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/WebSecurityConfig.java b/src/main/java/com/openAi/security/WebSecurityConfig.java index 564d18e..9593c0b 100644 --- a/src/main/java/com/openAi/security/WebSecurityConfig.java +++ b/src/main/java/com/openAi/security/WebSecurityConfig.java @@ -7,10 +7,14 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.ObjectPostProcessor; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.AuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.HttpStatusEntryPoint; import org.springframework.security.config.http.SessionCreationPolicy; @@ -24,21 +28,18 @@ @Configuration @EnableMethodSecurity(prePostEnabled = true) @RequiredArgsConstructor +@EnableWebSecurity public class WebSecurityConfig { - private final AuthenticationFilter filter; private final AllowedDomainRepository allowedDomainRepository; private final CorsConfiguration configuration = new CorsConfiguration(); @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - http.cors() - .and() - .csrf().disable() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .and() + public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception { + http.cors(cors -> cors.configurationSource(corsConfigurationSource())) + .csrf(csrf -> csrf.disable()) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(authorize -> authorize .requestMatchers( "/getToken", @@ -49,16 +50,35 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti ).permitAll() .anyRequest().authenticated() ) - .exceptionHandling() - .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) - .and() - .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class); + .exceptionHandling(exception -> exception.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) + .addFilterBefore(authenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class); return http.build(); } @Bean - @Profile({"dev", "staging", "prod"}) + public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + + @Bean + public AuthenticationConfiguration authenticationConfiguration(ObjectPostProcessor objectPostProcessor) { + AuthenticationConfiguration authenticationConfiguration = new AuthenticationConfiguration(); + authenticationConfiguration.setObjectPostProcessor(objectPostProcessor); + return authenticationConfiguration; + } + + @Bean + public ObjectPostProcessor objectPostProcessor() { + return new ObjectPostProcessor() { + @Override + public O postProcess(O object) { + return object; + } + }; + } + + @Bean public CorsConfigurationSource corsConfigurationSource() { updateCorsConfiguration(); configuration.addExposedHeader("Set-Cookie"); @@ -128,4 +148,14 @@ void updateCorsConfiguration() { .stream().map(AllowedDomain::getDomainName).toList(); configuration.setAllowedOrigins(origins); } -} + @Bean + public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor objectPostProcessor) { + return new AuthenticationManagerBuilder(objectPostProcessor); + } + @Bean + public UsernamePasswordAuthenticationFilter authenticationFilter(AuthenticationManager authenticationManager) { + UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(); + filter.setAuthenticationManager(authenticationManager); + return filter; + } +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/controller/UserController.java b/src/main/java/com/openAi/security/controller/UserController.java new file mode 100644 index 0000000..913fcf0 --- /dev/null +++ b/src/main/java/com/openAi/security/controller/UserController.java @@ -0,0 +1,121 @@ +package com.openAi.security.controller; + +import com.openAi.security.entity.Roles; +import com.openAi.security.entity.User; +import com.openAi.security.enums.AppConstant; +import com.openAi.security.enums.EntityStatus; +import com.openAi.security.enums.UserRole; +import com.openAi.security.mapper.UserMapper; +import com.openAi.security.mapper.UserTeamRolesMapper; +import com.openAi.security.model.UserListViewResponse; +import com.openAi.security.model.UserModel; +import com.openAi.security.service.UserService; +import com.openAi.security.service.UserTeamRoleService; +import com.openAi.security.utils.SessionUtils; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.mapstruct.factory.Mappers; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +@Slf4j +@RestController +@RequestMapping("/user") +@RequiredArgsConstructor +public class UserController { + + UserMapper userMapper = Mappers.getMapper(UserMapper.class); + UserTeamRolesMapper userTeamRolesMapper = Mappers.getMapper(UserTeamRolesMapper.class); + private final UserService userService; + private final SessionUtils sessionUtils; + private final UserTeamRoleService userTeamRoleService; + + @GetMapping("/loggedInUser") + public ResponseEntity getLoggedInUser() { + return ResponseEntity.status(HttpStatus.OK).body(sessionUtils.getLoggedInUser()); + } + + @GetMapping + public ResponseEntity getUser(@RequestParam String email) { + if (StringUtils.isEmpty(email)) { + log.error("Invalid email address."); + throw new IllegalArgumentException("Invalid email address"); + } + UserModel userModel = userService.findUserByEmailOrAttendance(email); + return ResponseEntity.status(HttpStatus.OK).body(userModel); + } + + @GetMapping("/roles") + public ResponseEntity> getRoles() { + List roles = userService.getRoles(); + return ResponseEntity.status(HttpStatus.OK).body(roles); + } + + @GetMapping("all") + public ResponseEntity getAllUser( + @RequestParam(value = "role", required = false) UserRole role, + @RequestParam(value = "status", required = false) EntityStatus status, + @RequestParam(value = "name", required = false) String name, + @RequestParam(value = "email", required = false) String email, + @RequestParam(value = "teamName", required = false) String teamName, + @RequestParam(value = "isTeg", required = false) Boolean isTeg, + @RequestParam(value = "orderBy", defaultValue = "id", required = false) String orderBy, + @RequestParam(value = "direction", defaultValue = "DESC", required = false) + Sort.Direction direction, + @RequestParam(value = "page", defaultValue = AppConstant.DEFAULT_PAGE, required = false) + int page, + @RequestParam(value = "size", defaultValue = AppConstant.DEFAULT_PAGE_SIZE, required = false) + int size, + @RequestParam(value = "searchField", required = false) String searchField) { + Sort sort = + orderBy.equalsIgnoreCase("id") + ? Sort.by(direction, orderBy) + : Sort.by(direction, orderBy).and(Sort.by(Sort.Direction.ASC, "id")); + Pageable paging = PageRequest.of(page, size, sort); + Specification userSpecification = Specification.where(null); + + if (Arrays.asList(UserRole.values()).contains(role)) { + userSpecification = userSpecification.and(User.roleSpec(role)); + } + if (Objects.nonNull(status)) { + userSpecification = userSpecification.and(User.statusSpec(status)); + } + if (Objects.nonNull(name)) { + userSpecification = userSpecification.and(User.nameSpec(name)); + } + if (Objects.nonNull(email)) { + userSpecification = userSpecification.and(User.emailSpec(email)); + } + if (Objects.nonNull(teamName)) { + userSpecification = userSpecification.and(User.teamSpec(teamName)); + } + if (Objects.nonNull(isTeg)) { + userSpecification = userSpecification.and(User.isTegSpec(isTeg)); + } + if (StringUtils.isNotBlank(searchField)) { + userSpecification = userSpecification.and(User.userSearchFieldSpec(searchField)); + } + userSpecification = userSpecification.and(User.distinct()); + UserListViewResponse userListViewResponse = userService.findAllUsers(userSpecification, paging); + return ResponseEntity.status(HttpStatus.OK).body(userListViewResponse); + } + + @GetMapping("/manager-list") + public ResponseEntity> getSeniorManagers(@RequestParam(required = true) String role) { + UserRole userRole = UserRole.valueOf(role); + return ResponseEntity.ok(userTeamRoleService.getUsersByRole(userRole)); + } +} diff --git a/src/main/java/com/openAi/security/entity/AllowedDomain.java b/src/main/java/com/openAi/security/entity/AllowedDomain.java index 3f92251..1c8be4e 100644 --- a/src/main/java/com/openAi/security/entity/AllowedDomain.java +++ b/src/main/java/com/openAi/security/entity/AllowedDomain.java @@ -13,6 +13,7 @@ @Builder @NoArgsConstructor @AllArgsConstructor +@Table(name = "allowed_domain") public class AllowedDomain { @Id @@ -20,15 +21,21 @@ public class AllowedDomain { @Column(columnDefinition = "INT(11) UNSIGNED") private Integer id; + @Column(name = "domain_name") private String domainName; + @Column(name = "customer_id") private Integer customerId; + @Column(name = "team_ids") private String teamIds; + @Column(name = "is_on_boarded") private Boolean isOnBoarded; + @Column(name = "on_boarded_date") private LocalDate onBoardedDate; + @Column(name = "data_from") private LocalDate dataFrom; } diff --git a/src/main/java/com/openAi/security/entity/CustomerCredentials.java b/src/main/java/com/openAi/security/entity/CustomerCredentials.java index 5d871c2..88e107f 100644 --- a/src/main/java/com/openAi/security/entity/CustomerCredentials.java +++ b/src/main/java/com/openAi/security/entity/CustomerCredentials.java @@ -11,6 +11,7 @@ @Getter @Setter @Accessors(chain = true) +@Table(name = "customer_credentials") public class CustomerCredentials { @Id @Column(columnDefinition = "INT(11) UNSIGNED") diff --git a/src/main/java/com/openAi/security/entity/UserLog.java b/src/main/java/com/openAi/security/entity/UserLog.java index e85cc7f..5ad917c 100644 --- a/src/main/java/com/openAi/security/entity/UserLog.java +++ b/src/main/java/com/openAi/security/entity/UserLog.java @@ -13,6 +13,7 @@ @Accessors(chain = true) @NoArgsConstructor @AllArgsConstructor +@Table(name = "user_log") public class UserLog { @Id @Column(columnDefinition = "INT(11) UNSIGNED") diff --git a/src/main/java/com/openAi/security/entity/UserTeamRoles.java b/src/main/java/com/openAi/security/entity/UserTeamRoles.java index 693ce0f..acbf950 100644 --- a/src/main/java/com/openAi/security/entity/UserTeamRoles.java +++ b/src/main/java/com/openAi/security/entity/UserTeamRoles.java @@ -13,6 +13,7 @@ @Builder @NoArgsConstructor @AllArgsConstructor +@Table(name = "user_team_roles") public class UserTeamRoles{ @Id diff --git a/src/main/java/com/openAi/security/enums/AppConstant.java b/src/main/java/com/openAi/security/enums/AppConstant.java new file mode 100644 index 0000000..fc6193c --- /dev/null +++ b/src/main/java/com/openAi/security/enums/AppConstant.java @@ -0,0 +1,8 @@ +package com.openAi.security.enums; + +public class AppConstant { + private AppConstant(){} + public static final String DEFAULT_PAGE = "0"; + public static final String DEFAULT_PAGE_SIZE = "10"; + public static final String DEFAULT_PAGE_SIZE_PRODUCT_ROADMAP = "50"; +} diff --git a/src/main/java/com/openAi/security/mapper/UserTeamRolesMapper.java b/src/main/java/com/openAi/security/mapper/UserTeamRolesMapper.java new file mode 100644 index 0000000..604f41b --- /dev/null +++ b/src/main/java/com/openAi/security/mapper/UserTeamRolesMapper.java @@ -0,0 +1,12 @@ +package com.openAi.security.mapper; + +import com.openAi.security.entity.UserTeamRoles; +import com.openAi.security.model.UserTeamRolesModel; +import org.mapstruct.Mapper; + +@Mapper +public interface UserTeamRolesMapper { + UserTeamRolesModel entityToModel(UserTeamRoles userTeamRoles); + + UserTeamRoles modelToEntity(UserTeamRolesModel userTeamRolesModel); +} diff --git a/src/main/java/com/openAi/security/model/UserListViewResponse.java b/src/main/java/com/openAi/security/model/UserListViewResponse.java new file mode 100644 index 0000000..e68c288 --- /dev/null +++ b/src/main/java/com/openAi/security/model/UserListViewResponse.java @@ -0,0 +1,23 @@ +package com.openAi.security.model; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.util.ArrayList; +import java.util.List; + +/** UserListViewResponse. */ +@Getter +@Setter +@Accessors(chain = true) +public class UserListViewResponse { + + private List userListViews = new ArrayList<>(); + private Long totalRecords; + private Integer totalPages; + private boolean hasNext = false; + private boolean hasPrevious = false; + private Integer page; + private Integer size; +} diff --git a/src/main/java/com/openAi/security/repository/RolesRepository.java b/src/main/java/com/openAi/security/repository/RolesRepository.java new file mode 100644 index 0000000..1bbed2e --- /dev/null +++ b/src/main/java/com/openAi/security/repository/RolesRepository.java @@ -0,0 +1,9 @@ +package com.openAi.security.repository; + +import com.openAi.security.entity.Roles; +import com.openAi.security.enums.UserRole; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RolesRepository extends JpaRepository { + Roles findByRole(UserRole userRole); +} diff --git a/src/main/java/com/openAi/security/service/UserService.java b/src/main/java/com/openAi/security/service/UserService.java index 0336262..238caf5 100644 --- a/src/main/java/com/openAi/security/service/UserService.java +++ b/src/main/java/com/openAi/security/service/UserService.java @@ -1,6 +1,8 @@ package com.openAi.security.service; +import com.openAi.security.entity.Roles; import com.openAi.security.entity.User; +import com.openAi.security.model.UserListViewResponse; import com.openAi.security.model.UserModel; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; @@ -20,4 +22,9 @@ public interface UserService { UserModel findUserByEmail(String email); void saveUserLog(String userEmail); + + UserListViewResponse findAllUsers(Specification userSpecification, Pageable paging); + + List getRoles(); + } diff --git a/src/main/java/com/openAi/security/service/UserServiceImpl.java b/src/main/java/com/openAi/security/service/UserServiceImpl.java index 926c60c..4d0afa6 100644 --- a/src/main/java/com/openAi/security/service/UserServiceImpl.java +++ b/src/main/java/com/openAi/security/service/UserServiceImpl.java @@ -1,22 +1,27 @@ package com.openAi.security.service; -import com.openAi.security.repository.AttendanceRepository; -import com.openAi.security.repository.CustomerCredentialRepository; -import com.openAi.security.repository.UserLogRepository; -import com.openAi.security.repository.UserTeamRoleRepository; -import com.openAi.security.entity.Attendance; +import com.openAi.security.entity.*; import com.openAi.security.enums.UserRole; +import com.openAi.security.exceptions.EntityNotFoundException; import com.openAi.security.mapper.UserMapper; +import com.openAi.security.mapper.UserTeamRolesMapper; +import com.openAi.security.model.UserListViewResponse; import com.openAi.security.model.UserModel; +import com.openAi.security.repository.*; +import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.mapstruct.factory.Mappers; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.List; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.*; import static com.openAi.security.enums.EntityStatus.ACTIVE; @@ -30,17 +35,16 @@ public class UserServiceImpl implements UserService { private final UserMapper userMapper = Mappers.getMapper(UserMapper.class); private final String LOGIN = "login"; -/* @Autowired - UserRepository userRepository;*/ @Autowired -UserTeamRoleRepository userTeamRoleRepository; + UserTeamRoleRepository userTeamRoleRepository; @Autowired AttendanceRepository attendanceRepository; @Autowired CustomerCredentialRepository customerCredentialRepository; @Autowired PasswordEncoder passwordEncoder; - + @Autowired + UserRepository userRepository; @Value("${customer-login.site-url}") private String siteURL; @@ -49,6 +53,8 @@ public class UserServiceImpl implements UserService { @Autowired private UserLogRepository userLogRepository; + private final UserTeamRolesMapper userTeamRolesMapper = Mappers.getMapper(UserTeamRolesMapper.class); + @Override public UserModel findUserByEmailOrAttendance(String email) { UserModel userModel = null; @@ -70,20 +76,19 @@ public UserModel findUserByEmailOrAttendance(String email) { @Override public UserModel findUserByEmail(String email) { - /*log.debug("Finding user with email: {}", email); + log.debug("Finding user with email: {}", email); User user = userRepository .findByEmailIgnoreCaseAndStatus(email, ACTIVE) .orElseThrow(() -> EntityNotFoundException.user("User not found with email " + email)); UserModel userModel = userMapper.entityToModel(user); userModel.setCustomers(user.getTeams().stream().map(Team::getCustomer).toList()); - return userModel;*/ - return null; + return userModel; } @Override public void saveUserLog(String email) { -/* + try { Optional optionalUser = userRepository.findUserByEmail(email); if (optionalUser.isPresent()) { @@ -104,8 +109,68 @@ public void saveUserLog(String email) { } catch (Exception e) { log.error(e.getMessage()); } -*/ + + } + + @Override + public UserListViewResponse findAllUsers(Specification userSpecification, Pageable paging) { + Page pagedResult = userRepository.findAll(userSpecification, paging); + + UserListViewResponse userListViewResponse; + if (pagedResult.hasContent()) { + userListViewResponse = populateUserListViewResponse(pagedResult); + } else { + userListViewResponse = new UserListViewResponse(); + userListViewResponse.setTotalPages(pagedResult.getTotalPages()); + userListViewResponse.setTotalRecords(pagedResult.getTotalElements()); + userListViewResponse.setPage(pagedResult.getNumber()); + userListViewResponse.setSize(pagedResult.getSize()); + userListViewResponse.setHasNext(pagedResult.hasNext()); + userListViewResponse.setHasPrevious(pagedResult.hasPrevious()); + log.warn("No User(s) found"); + } + return userListViewResponse; + } + + private UserListViewResponse populateUserListViewResponse(Page pagedResult) { + UserListViewResponse userListViewResponse = + new UserListViewResponse() + .setTotalPages(pagedResult.getTotalPages()) + .setTotalRecords(pagedResult.getTotalElements()) + .setPage(pagedResult.getNumber()) + .setSize(pagedResult.getSize()) + .setHasNext(pagedResult.hasNext()) + .setHasPrevious(pagedResult.hasPrevious()); + + List userEntityList = pagedResult.getContent(); + List userList = + userEntityList.stream() + .map( + user -> { + var userModel = userMapper.entityToModel(user); + userModel.setTeams(new HashSet<>(userModel.getTeams()).stream().toList()); + userModel.setTeamRoles( + user.getUserTeamRoles().stream() + .map(userTeamRoles -> userTeamRolesMapper.entityToModel(userTeamRoles)) + .toList()); +// userModel.setIsCustomerRole( +// userModel.getTeamRoles().stream() +// .anyMatch( +// userTeamRolesModel -> +// userTeamRolesModel.getUserRole().getRole().equals(UserRole.CUSTOMER))); + return userModel; + }) + .toList(); + + userListViewResponse.setUserListViews(userList); + return userListViewResponse; + } + + + @Override + public List getRoles() { + return List.of(); } } diff --git a/src/main/java/com/openAi/security/service/UserTeamRoleService.java b/src/main/java/com/openAi/security/service/UserTeamRoleService.java new file mode 100644 index 0000000..4e692c8 --- /dev/null +++ b/src/main/java/com/openAi/security/service/UserTeamRoleService.java @@ -0,0 +1,10 @@ +package com.openAi.security.service; + +import com.openAi.security.enums.UserRole; + +import java.util.Set; + +public interface UserTeamRoleService { + + Set getUsersByRole(UserRole role); +} diff --git a/src/main/java/com/openAi/security/service/UserTeamRoleServiceImpl.java b/src/main/java/com/openAi/security/service/UserTeamRoleServiceImpl.java new file mode 100644 index 0000000..28692d6 --- /dev/null +++ b/src/main/java/com/openAi/security/service/UserTeamRoleServiceImpl.java @@ -0,0 +1,36 @@ +package com.openAi.security.service; + + +import com.openAi.security.entity.Roles; +import com.openAi.security.entity.User; +import com.openAi.security.entity.UserTeamRoles; +import com.openAi.security.enums.UserRole; +import com.openAi.security.repository.RolesRepository; +import com.openAi.security.repository.UserTeamRoleRepository; +import lombok.RequiredArgsConstructor; + +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class UserTeamRoleServiceImpl implements UserTeamRoleService { + + private final UserTeamRoleRepository userTeamRoleRepository; + private final RolesRepository rolesRepository; + + @Override + public Set getUsersByRole(UserRole userRole) { + + Roles role = rolesRepository.findByRole(userRole); + + List userTeamRoles = userTeamRoleRepository.findByUserRole(role); + return userTeamRoles.stream() + .map(UserTeamRoles::getUser) + .map(User::getName) + .collect(Collectors.toSet()); + } +} diff --git a/src/main/java/com/openAi/security/utils/SessionUtils.java b/src/main/java/com/openAi/security/utils/SessionUtils.java new file mode 100644 index 0000000..cd4bd48 --- /dev/null +++ b/src/main/java/com/openAi/security/utils/SessionUtils.java @@ -0,0 +1,35 @@ +package com.openAi.security.utils; + +import com.openAi.security.model.UserModel; +import com.openAi.security.service.UserService; +import com.openAi.security.utils.JwtUtils; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Objects; + +@Service +@RequiredArgsConstructor +public class SessionUtils { + + private final HttpServletRequest request; + private final UserService userService; + private final JwtUtils jwtUtils; + + public UserModel getLoggedInUser() { + Cookie[] cookieAuth = request.getCookies(); + String jwt = ""; + if (Objects.nonNull(cookieAuth)) { + for (Cookie cookie : cookieAuth) { + if (cookie.getName().equals("auth-token")) { + jwt = cookie.getValue(); + } + } + } + + String email = jwtUtils.getSubject(jwt); + return userService.findUserByEmail(email); + } +} From 04a71a7247dd4a5b123dd3f263e4f9f022634306 Mon Sep 17 00:00:00 2001 From: krishnaBaile Date: Mon, 6 Jan 2025 16:09:27 +0530 Subject: [PATCH 5/9] swagger --- pom.xml | 7 +++++++ src/main/java/com/openAi/SwaggerConfig.java | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 src/main/java/com/openAi/SwaggerConfig.java diff --git a/pom.xml b/pom.xml index 0abfd43..18817db 100644 --- a/pom.xml +++ b/pom.xml @@ -145,6 +145,13 @@ tomcat-embed-core 10.1.25 + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.0.0 + diff --git a/src/main/java/com/openAi/SwaggerConfig.java b/src/main/java/com/openAi/SwaggerConfig.java new file mode 100644 index 0000000..5ff1da6 --- /dev/null +++ b/src/main/java/com/openAi/SwaggerConfig.java @@ -0,0 +1,19 @@ +package com.openAi; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfig { + + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("API Documentation") + .version("1.0") + .description("API documentation for the project")); + } +} \ No newline at end of file From adfbdbc399e38593c5b8ae1c4614f7edb90af004 Mon Sep 17 00:00:00 2001 From: krishnaBaile Date: Mon, 6 Jan 2025 16:13:54 +0530 Subject: [PATCH 6/9] Revert "swagger" This reverts commit 04a71a7247dd4a5b123dd3f263e4f9f022634306. --- pom.xml | 7 ------- src/main/java/com/openAi/SwaggerConfig.java | 19 ------------------- 2 files changed, 26 deletions(-) delete mode 100644 src/main/java/com/openAi/SwaggerConfig.java diff --git a/pom.xml b/pom.xml index 18817db..0abfd43 100644 --- a/pom.xml +++ b/pom.xml @@ -145,13 +145,6 @@ tomcat-embed-core 10.1.25 - - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - 2.0.0 - diff --git a/src/main/java/com/openAi/SwaggerConfig.java b/src/main/java/com/openAi/SwaggerConfig.java deleted file mode 100644 index 5ff1da6..0000000 --- a/src/main/java/com/openAi/SwaggerConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.openAi; - -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class SwaggerConfig { - - @Bean - public OpenAPI customOpenAPI() { - return new OpenAPI() - .info(new Info() - .title("API Documentation") - .version("1.0") - .description("API documentation for the project")); - } -} \ No newline at end of file From 4b3d6aaf4d444a5320895b195b0e04cd0f0f8b4d Mon Sep 17 00:00:00 2001 From: krishnaBaile Date: Mon, 13 Jan 2025 14:40:51 +0530 Subject: [PATCH 7/9] security implementation --- pom.xml | 11 ++ .../com/openAi/security/ConfigController.java | 4 +- .../CustomHttpServletRequestFactory.java | 14 ++ ...curityContextHolderAwareRequestFilter.java | 31 +++++ .../openAi/security/WebSecurityConfig.java | 130 +++++++----------- .../com/openAi/security/utils/JpaConfig.java | 26 ---- .../security/utils/JwtKeyGenerator.java | 15 ++ src/main/resources/application.yml | 3 +- 8 files changed, 124 insertions(+), 110 deletions(-) create mode 100644 src/main/java/com/openAi/security/CustomHttpServletRequestFactory.java create mode 100644 src/main/java/com/openAi/security/CustomSecurityContextHolderAwareRequestFilter.java delete mode 100644 src/main/java/com/openAi/security/utils/JpaConfig.java create mode 100644 src/main/java/com/openAi/security/utils/JwtKeyGenerator.java diff --git a/pom.xml b/pom.xml index 0abfd43..799cce9 100644 --- a/pom.xml +++ b/pom.xml @@ -145,6 +145,17 @@ tomcat-embed-core 10.1.25 + + jakarta.servlet + jakarta.servlet-api + 6.0.0 + provided + + + org.springframework.boot + spring-boot-starter-tomcat + + diff --git a/src/main/java/com/openAi/security/ConfigController.java b/src/main/java/com/openAi/security/ConfigController.java index e622ced..22269b3 100644 --- a/src/main/java/com/openAi/security/ConfigController.java +++ b/src/main/java/com/openAi/security/ConfigController.java @@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.cors.CorsConfiguration; @RestController @RequestMapping("/security-config") @@ -19,7 +20,8 @@ public class ConfigController { @PostMapping("/refresh-cors-config") public ResponseEntity refreshCorsConfig() { - webSecurityConfig.updateCorsConfiguration(); + CorsConfiguration configuration = new CorsConfiguration(); + webSecurityConfig.updateCorsConfiguration(configuration); return ResponseEntity.ok("CORS configuration updated successfully"); } } diff --git a/src/main/java/com/openAi/security/CustomHttpServletRequestFactory.java b/src/main/java/com/openAi/security/CustomHttpServletRequestFactory.java new file mode 100644 index 0000000..c952977 --- /dev/null +++ b/src/main/java/com/openAi/security/CustomHttpServletRequestFactory.java @@ -0,0 +1,14 @@ +package com.openAi.security; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper; +import org.springframework.stereotype.Component; + +@Component +public class CustomHttpServletRequestFactory { + + public SecurityContextHolderAwareRequestWrapper create(HttpServletRequest request, HttpServletResponse response) { + return new SecurityContextHolderAwareRequestWrapper(request, response.toString()); + } +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/CustomSecurityContextHolderAwareRequestFilter.java b/src/main/java/com/openAi/security/CustomSecurityContextHolderAwareRequestFilter.java new file mode 100644 index 0000000..ef7b139 --- /dev/null +++ b/src/main/java/com/openAi/security/CustomSecurityContextHolderAwareRequestFilter.java @@ -0,0 +1,31 @@ +package com.openAi.security; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter; +import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper; +import org.springframework.stereotype.Component; + +@Component +public class CustomSecurityContextHolderAwareRequestFilter extends SecurityContextHolderAwareRequestFilter { + + private final CustomHttpServletRequestFactory customHttpServletRequestFactory; + + public CustomSecurityContextHolderAwareRequestFilter(CustomHttpServletRequestFactory customHttpServletRequestFactory) { + this.customHttpServletRequestFactory = customHttpServletRequestFactory; + } +// @Override + protected SecurityContextHolderAwareRequestWrapper wrapRequest(HttpServletRequest request) { + return customHttpServletRequestFactory.create(request, null); + } + +// @Override + protected SecurityContextHolderAwareRequestWrapper wrapRequest(HttpServletRequest request, HttpServletResponse response) { + return customHttpServletRequestFactory.create(request, response); + } + +// @Override + protected SecurityContextHolderAwareRequestWrapper create(HttpServletRequest request, HttpServletResponse response) { + return customHttpServletRequestFactory.create(request, response); + } +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/WebSecurityConfig.java b/src/main/java/com/openAi/security/WebSecurityConfig.java index 9593c0b..ef616e4 100644 --- a/src/main/java/com/openAi/security/WebSecurityConfig.java +++ b/src/main/java/com/openAi/security/WebSecurityConfig.java @@ -8,22 +8,20 @@ import org.springframework.context.annotation.Profile; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.config.annotation.ObjectPostProcessor; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.HttpStatusEntryPoint; -import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; @Configuration @EnableMethodSecurity(prePostEnabled = true) @@ -33,8 +31,6 @@ public class WebSecurityConfig { private final AllowedDomainRepository allowedDomainRepository; - private final CorsConfiguration configuration = new CorsConfiguration(); - @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception { http.cors(cors -> cors.configurationSource(corsConfigurationSource())) @@ -61,41 +57,13 @@ public AuthenticationManager authenticationManager(AuthenticationConfiguration a return authenticationConfiguration.getAuthenticationManager(); } - @Bean - public AuthenticationConfiguration authenticationConfiguration(ObjectPostProcessor objectPostProcessor) { - AuthenticationConfiguration authenticationConfiguration = new AuthenticationConfiguration(); - authenticationConfiguration.setObjectPostProcessor(objectPostProcessor); - return authenticationConfiguration; - } - - @Bean - public ObjectPostProcessor objectPostProcessor() { - return new ObjectPostProcessor() { - @Override - public O postProcess(O object) { - return object; - } - }; - } - @Bean public CorsConfigurationSource corsConfigurationSource() { - updateCorsConfiguration(); - configuration.addExposedHeader("Set-Cookie"); - configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); - configuration.setAllowedHeaders( - List.of( - "Api-Key", - "Authorization", - "Cache-Control", - "Content-Type", - "Access-Control-Allow-Origin", - "Access-Control-Allow-Credentials" - ) - ); - configuration.setAllowCredentials(true); + CorsConfiguration configuration = new CorsConfiguration(); + updateCorsConfiguration(configuration); + applyCommonCorsSettings(configuration); - final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } @@ -103,59 +71,57 @@ public CorsConfigurationSource corsConfigurationSource() { @Bean @Profile("test") public CorsConfigurationSource corsConfigurationSourceTest() { - final CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins( - List.of( - "https://playbook.talentica.com/", - "https://orion.talentica.com/", - "https://prod-orion.talentica.com/", - "http://localhost:3000/", - "http://localhost/", - "https://stagingplaybook.talentica.com", - "https://dev-orion.talentica.com/", - "https://stagingorion.talentica.com", - "https://staging-orion.talentica.com/", - "http://localhost:3001/", - "https://stagingknowledgebase.talentica.com/", - "https://stagingknowledgebase-sales.talentica.com/", - "https://staging.kb.talentica.com/", - "https://stagingknowledgebase.talentica.com/", - "https://nexus.talentica.com/", - "https://kb.talentica.com/" - ) - ); - configuration.addExposedHeader("Set-Cookie"); - configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); - configuration.setAllowedHeaders( - List.of( - "Api-Key", - "Authorization", - "Cache-Control", - "Content-Type", - "Access-Control-Allow-Origin", - "Access-Control-Allow-Credentials" - ) - ); - configuration.setAllowCredentials(true); + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOrigins(List.of( + "https://playbook.talentica.com/", + "https://orion.talentica.com/", + "https://prod-orion.talentica.com/", + "http://localhost:3000/", + "http://localhost/", + "https://stagingplaybook.talentica.com", + "https://dev-orion.talentica.com/", + "https://stagingorion.talentica.com", + "https://staging-orion.talentica.com/", + "http://localhost:3001/", + "https://stagingknowledgebase.talentica.com/", + "https://stagingknowledgebase-sales.talentica.com/", + "https://staging.kb.talentica.com/", + "https://nexus.talentica.com/", + "https://kb.talentica.com/" + )); + applyCommonCorsSettings(configuration); - final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } - void updateCorsConfiguration() { - List origins = allowedDomainRepository.findAll() - .stream().map(AllowedDomain::getDomainName).toList(); - configuration.setAllowedOrigins(origins); + public void updateCorsConfiguration(CorsConfiguration configuration) { + List allowedOrigins = allowedDomainRepository.findAll() + .stream() + .map(AllowedDomain::getDomainName) + .collect(Collectors.toList()); + configuration.setAllowedOrigins(allowedOrigins); } - @Bean - public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor objectPostProcessor) { - return new AuthenticationManagerBuilder(objectPostProcessor); + + private void applyCommonCorsSettings(CorsConfiguration configuration) { + configuration.addExposedHeader("Set-Cookie"); + configuration.setAllowedMethods(List.of("GET", "POST", "OPTIONS", "PUT", "DELETE")); + configuration.setAllowedHeaders(List.of( + "Api-Key", + "Authorization", + "Cache-Control", + "Content-Type", + "Access-Control-Allow-Origin", + "Access-Control-Allow-Credentials" + )); + configuration.setAllowCredentials(true); } + @Bean public UsernamePasswordAuthenticationFilter authenticationFilter(AuthenticationManager authenticationManager) { UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(); filter.setAuthenticationManager(authenticationManager); return filter; } -} \ No newline at end of file +} diff --git a/src/main/java/com/openAi/security/utils/JpaConfig.java b/src/main/java/com/openAi/security/utils/JpaConfig.java deleted file mode 100644 index bae16bb..0000000 --- a/src/main/java/com/openAi/security/utils/JpaConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.openAi.security.utils; - -import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; -import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; - -import javax.sql.DataSource; - -@Configuration -public class JpaConfig { - - @Bean - public LocalContainerEntityManagerFactoryBean entityManagerFactory( - EntityManagerFactoryBuilder builder, - DataSource dataSource, - JpaProperties jpaProperties) { - return builder - .dataSource(dataSource) - .packages("com.openAi.security.entity") - .persistenceUnit("default") - .properties(jpaProperties.getProperties()) - .build(); - } -} diff --git a/src/main/java/com/openAi/security/utils/JwtKeyGenerator.java b/src/main/java/com/openAi/security/utils/JwtKeyGenerator.java new file mode 100644 index 0000000..a6f8c53 --- /dev/null +++ b/src/main/java/com/openAi/security/utils/JwtKeyGenerator.java @@ -0,0 +1,15 @@ +package com.openAi.security.utils; + +import io.jsonwebtoken.security.Keys; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.io.Encoders; + +import java.security.Key; + +public class JwtKeyGenerator { + public static void main(String[] args) { + Key key = Keys.secretKeyFor(SignatureAlgorithm.HS512); // Generates a secure random key + String base64Key = Encoders.BASE64.encode(key.getEncoded()); // Encode key to Base64 + System.out.println("Generated Key: " + base64Key); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 43dc9bc..204ecfa 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -33,7 +33,8 @@ spring: api-key: ${OPEN-AI-KEY} model: gpt-3.5-turbo security: - jwtSecret: cdfe45gfbcnhf + jwtSecret: 0aQ+z+0UifxvQzCXzQ4L1AdXVXLjPjS3t3DEVWCG2SMyEVrNFHtQ6Bok106znS0+DjxMHwT2OGTcmAS5DNXFIg== + jwtExpirationMs: 604800000 apiKey: 53e72eed-6f0b-4d5b-9cc5-088487d969b9 From e139532e944f38ff83a18bfb02acaa94eae0495b Mon Sep 17 00:00:00 2001 From: krishnaBaile Date: Wed, 15 Jan 2025 15:51:50 +0530 Subject: [PATCH 8/9] security implementation --- .../openAi/application/OpenAiApplication.java | 7 - .../openAi/security/AuthenticationFilter.java | 23 +-- .../com/openAi/security/ConfigController.java | 2 +- .../openAi/security/WebSecurityConfig.java | 158 ++++++++++-------- .../security/utils/WebSecurityConfig.java | 126 ++++++++++++++ src/main/resources/application.yml | 2 +- 6 files changed, 226 insertions(+), 92 deletions(-) create mode 100644 src/main/java/com/openAi/security/utils/WebSecurityConfig.java diff --git a/src/main/java/com/openAi/application/OpenAiApplication.java b/src/main/java/com/openAi/application/OpenAiApplication.java index 527d040..f5e6026 100644 --- a/src/main/java/com/openAi/application/OpenAiApplication.java +++ b/src/main/java/com/openAi/application/OpenAiApplication.java @@ -30,13 +30,6 @@ ChatModel chatModel(@Value("${spring.ai.openai.api-key}") String apiKey) { return new OpenAiChatModel(new OpenAiApi(apiKey)); } - @Bean - public UsernamePasswordAuthenticationFilter authenticationFilter(AuthenticationManager authenticationManager) { - UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(); - filter.setAuthenticationManager(authenticationManager); - return filter; - } - @Bean public FilterRegistrationBean filterRegistrationBean() { AuthenticationFilter filter = new AuthenticationFilter(); diff --git a/src/main/java/com/openAi/security/AuthenticationFilter.java b/src/main/java/com/openAi/security/AuthenticationFilter.java index 0764ae2..354756b 100644 --- a/src/main/java/com/openAi/security/AuthenticationFilter.java +++ b/src/main/java/com/openAi/security/AuthenticationFilter.java @@ -5,6 +5,10 @@ import com.openAi.security.service.UserService; import com.openAi.security.utils.JwtUtils; import io.jsonwebtoken.Claims; +import jakarta.servlet.FilterChain; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -21,10 +25,6 @@ import org.springframework.web.context.support.SpringBeanAutowiringSupport; import org.springframework.web.filter.OncePerRequestFilter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.util.Collections; import java.util.Date; import java.util.Objects; @@ -61,13 +61,14 @@ protected void doFilterInternal( String.format("Requested path: %s at %s by %s", path, new Date(), request.getRemoteHost())); if ( new AntPathMatcher().match("/getToken", path) - || new AntPathMatcher().match("/getTokenGoogleAuth", path) - || new AntPathMatcher().match("/getTokenUserAuth", path) - || new AntPathMatcher().match("/user/generatePassword", path) - || new AntPathMatcher().match("/resetPassword", path) - || HttpMethod.OPTIONS.name().equalsIgnoreCase(request.getMethod()) - || new AntPathMatcher().match("/", path) - && apiKey.equals(request.getHeader("Api-Key"))) { + || new AntPathMatcher().match("/getTokenGoogleAuth", path) + || new AntPathMatcher().match("/getTokenUserAuth", path) + || new AntPathMatcher().match("/user/generatePassword", path) + || new AntPathMatcher().match("/resetPassword", path) + || new AntPathMatcher().match("/user/roles", path) + || HttpMethod.OPTIONS.name().equalsIgnoreCase(request.getMethod()) + || new AntPathMatcher().match("/", path) + && apiKey.equals(request.getHeader("Api-Key"))) { filterChain.doFilter(request, response); return; } diff --git a/src/main/java/com/openAi/security/ConfigController.java b/src/main/java/com/openAi/security/ConfigController.java index 22269b3..09924f7 100644 --- a/src/main/java/com/openAi/security/ConfigController.java +++ b/src/main/java/com/openAi/security/ConfigController.java @@ -21,7 +21,7 @@ public class ConfigController { @PostMapping("/refresh-cors-config") public ResponseEntity refreshCorsConfig() { CorsConfiguration configuration = new CorsConfiguration(); - webSecurityConfig.updateCorsConfiguration(configuration); + webSecurityConfig.updateCorsConfiguration(); return ResponseEntity.ok("CORS configuration updated successfully"); } } diff --git a/src/main/java/com/openAi/security/WebSecurityConfig.java b/src/main/java/com/openAi/security/WebSecurityConfig.java index ef616e4..18e6084 100644 --- a/src/main/java/com/openAi/security/WebSecurityConfig.java +++ b/src/main/java/com/openAi/security/WebSecurityConfig.java @@ -3,42 +3,56 @@ import com.openAi.security.entity.AllowedDomain; import com.openAi.security.repository.AllowedDomainRepository; import lombok.RequiredArgsConstructor; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.http.HttpStatus; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.HttpStatusEntryPoint; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; @Configuration -@EnableMethodSecurity(prePostEnabled = true) -@RequiredArgsConstructor @EnableWebSecurity -public class WebSecurityConfig { +@EnableGlobalMethodSecurity(prePostEnabled = true) +@RequiredArgsConstructor +public class WebSecurityConfig { + + private final AuthenticationFilter filter; private final AllowedDomainRepository allowedDomainRepository; - @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception { + private CorsConfiguration configuration = new CorsConfiguration(); + + +// @Override + protected void configure(HttpSecurity http) throws Exception { http.cors(cors -> cors.configurationSource(corsConfigurationSource())) .csrf(csrf -> csrf.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(authorize -> authorize .requestMatchers( "/getToken", + "/cicero/cicero-compliance-data", + "/cicero/importCiceroData", + "/technology/getTechDigest/label", + "/valueAdd/valueAddsByTag", + "/tech/categories", + "/tech/categories/*", + "/tech/category/*/value-adds", + "/tech/category/*/blogs", + "/tech/category/*/teams", + "/tech/category/**", + "/tech/**", "/getTokenUserAuth", "/user/generatePassword", "/resetPassword", @@ -47,23 +61,30 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http, Authentication .anyRequest().authenticated() ) .exceptionHandling(exception -> exception.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) - .addFilterBefore(authenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class); - - return http.build(); - } - - @Bean - public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { - return authenticationConfiguration.getAuthenticationManager(); + .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class); } - @Bean + @Profile({"dev","staging","prod"}) public CorsConfigurationSource corsConfigurationSource() { - CorsConfiguration configuration = new CorsConfiguration(); - updateCorsConfiguration(configuration); - applyCommonCorsSettings(configuration); + updateCorsConfiguration(); + configuration.addExposedHeader("Set-Cookie"); + configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); + // setAllowCredentials(true) is important, otherwise: + // The value of the 'Access-Control-Allow-Origin' header in the response must not be the + // wildcard '*' when the request's credentials mode is 'include'. + // setAllowedHeaders is important! Without it, OPTIONS preflight request + // will fail with 403 Invalid CORS request + configuration.setAllowedHeaders( + List.of( + "Api-Key", + "Authorization", + "Cache-Control", + "Content-Type", + "Access-Control-Allow-Origin", + "Access-Control-Allow-Credentials")); + configuration.setAllowCredentials(true); - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } @@ -71,57 +92,50 @@ public CorsConfigurationSource corsConfigurationSource() { @Bean @Profile("test") public CorsConfigurationSource corsConfigurationSourceTest() { - CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(List.of( - "https://playbook.talentica.com/", - "https://orion.talentica.com/", - "https://prod-orion.talentica.com/", - "http://localhost:3000/", - "http://localhost/", - "https://stagingplaybook.talentica.com", - "https://dev-orion.talentica.com/", - "https://stagingorion.talentica.com", - "https://staging-orion.talentica.com/", - "http://localhost:3001/", - "https://stagingknowledgebase.talentica.com/", - "https://stagingknowledgebase-sales.talentica.com/", - "https://staging.kb.talentica.com/", - "https://nexus.talentica.com/", - "https://kb.talentica.com/" - )); - applyCommonCorsSettings(configuration); + final CorsConfiguration corsConfiguration = new CorsConfiguration(); + corsConfiguration.setAllowedOrigins( + List.of( + "https://playbook.talentica.com/", + "https://orion.talentica.com/", + "https://prod-orion.talentica.com/", + "http://localhost:3000/", + "http://localhost/", + "https://stagingplaybook.talentica.com", + "https://dev-orion.talentica.com/", + "https://stagingorion.talentica.com", + "https://staging-orion.talentica.com/", + "http://localhost:3001/", + "https://stagingknowledgebase.talentica.com/", + "https://stagingknowledgebase-sales.talentica.com/", + "https://staging.kb.talentica.com/", + "https://stagingknowledgebase.talentica.com/", + "https://nexus.talentica.com/", + "https://kb.talentica.com/")); + corsConfiguration.addExposedHeader("Set-Cookie"); + corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); + // setAllowCredentials(true) is important, otherwise: + // The value of the 'Access-Control-Allow-Origin' header in the response must not be the + // wildcard '*' when the request's credentials mode is 'include'. + // setAllowedHeaders is important! Without it, OPTIONS preflight request + // will fail with 403 Invalid CORS request + corsConfiguration.setAllowedHeaders( + List.of( + "Api-Key", + "Authorization", + "Cache-Control", + "Content-Type", + "Access-Control-Allow-Origin", + "Access-Control-Allow-Credentials")); + corsConfiguration.setAllowCredentials(true); - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", configuration); + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", corsConfiguration); return source; } - public void updateCorsConfiguration(CorsConfiguration configuration) { - List allowedOrigins = allowedDomainRepository.findAll() - .stream() - .map(AllowedDomain::getDomainName) - .collect(Collectors.toList()); - configuration.setAllowedOrigins(allowedOrigins); - } - - private void applyCommonCorsSettings(CorsConfiguration configuration) { - configuration.addExposedHeader("Set-Cookie"); - configuration.setAllowedMethods(List.of("GET", "POST", "OPTIONS", "PUT", "DELETE")); - configuration.setAllowedHeaders(List.of( - "Api-Key", - "Authorization", - "Cache-Control", - "Content-Type", - "Access-Control-Allow-Origin", - "Access-Control-Allow-Credentials" - )); - configuration.setAllowCredentials(true); - } - - @Bean - public UsernamePasswordAuthenticationFilter authenticationFilter(AuthenticationManager authenticationManager) { - UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(); - filter.setAuthenticationManager(authenticationManager); - return filter; + public void updateCorsConfiguration() { + List origins = allowedDomainRepository.findAll() + .stream().map(AllowedDomain::getDomainName).toList(); + configuration.setAllowedOrigins(origins); } } diff --git a/src/main/java/com/openAi/security/utils/WebSecurityConfig.java b/src/main/java/com/openAi/security/utils/WebSecurityConfig.java new file mode 100644 index 0000000..ccf21c0 --- /dev/null +++ b/src/main/java/com/openAi/security/utils/WebSecurityConfig.java @@ -0,0 +1,126 @@ +//package com.openAi.security; +// +//import com.openAi.security.entity.AllowedDomain; +//import com.openAi.security.repository.AllowedDomainRepository; +//import lombok.RequiredArgsConstructor; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.context.annotation.Profile; +//import org.springframework.http.HttpStatus; +//import org.springframework.security.authentication.AuthenticationManager; +//import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +//import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +//import org.springframework.security.config.annotation.web.builders.HttpSecurity; +//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +//import org.springframework.security.config.http.SessionCreationPolicy; +//import org.springframework.security.web.SecurityFilterChain; +//import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +//import org.springframework.security.web.authentication.HttpStatusEntryPoint; +//import org.springframework.web.cors.CorsConfiguration; +//import org.springframework.web.cors.CorsConfigurationSource; +//import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +// +//import java.util.List; +//import java.util.stream.Collectors; +// +//@Configuration +//@EnableMethodSecurity(prePostEnabled = true) +//@RequiredArgsConstructor +//@EnableWebSecurity +//public class WebSecurityConfig { +// +// private final AllowedDomainRepository allowedDomainRepository; +// +// @Bean +// public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception { +// http.cors(cors -> cors.configurationSource(corsConfigurationSource())) +// .csrf(csrf -> csrf.disable()) +// .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) +// .authorizeHttpRequests(authorize -> authorize +// .requestMatchers( +// "/getToken", +// "/getTokenUserAuth", +// "/user/generatePassword", +// "/resetPassword", +// "/getTokenGoogleAuth" +// ).permitAll() +// .anyRequest().authenticated() +// ) +// .exceptionHandling(exception -> exception.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) +// .addFilterBefore(authenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class); +// return http.build(); +// } +// +// @Bean +// public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { +// return authenticationConfiguration.getAuthenticationManager(); +// } +// +// @Bean +// public CorsConfigurationSource corsConfigurationSource() { +// CorsConfiguration configuration = new CorsConfiguration(); +// updateCorsConfiguration(configuration); +// applyCommonCorsSettings(configuration); +// +// UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); +// source.registerCorsConfiguration("/**", configuration); +// return source; +// } +// +// @Bean +// @Profile("test") +// public CorsConfigurationSource corsConfigurationSourceTest() { +// CorsConfiguration configuration = new CorsConfiguration(); +// configuration.setAllowedOrigins(List.of( +// "https://playbook.talentica.com/", +// "https://orion.talentica.com/", +// "https://prod-orion.talentica.com/", +// "http://localhost:3000/", +// "http://localhost/", +// "https://stagingplaybook.talentica.com", +// "https://dev-orion.talentica.com/", +// "https://stagingorion.talentica.com", +// "https://staging-orion.talentica.com/", +// "http://localhost:3001/", +// "https://stagingknowledgebase.talentica.com/", +// "https://stagingknowledgebase-sales.talentica.com/", +// "https://staging.kb.talentica.com/", +// "https://nexus.talentica.com/", +// "https://kb.talentica.com/" +// )); +// applyCommonCorsSettings(configuration); +// +// UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); +// source.registerCorsConfiguration("/**", configuration); +// return source; +// } +// +// public void updateCorsConfiguration(CorsConfiguration configuration) { +// List allowedOrigins = allowedDomainRepository.findAll() +// .stream() +// .map(AllowedDomain::getDomainName) +// .collect(Collectors.toList()); +// configuration.setAllowedOrigins(allowedOrigins); +// } +// +// private void applyCommonCorsSettings(CorsConfiguration configuration) { +// configuration.addExposedHeader("Set-Cookie"); +// configuration.setAllowedMethods(List.of("GET", "POST", "OPTIONS", "PUT", "DELETE")); +// configuration.setAllowedHeaders(List.of( +// "Api-Key", +// "Authorization", +// "Cache-Control", +// "Content-Type", +// "Access-Control-Allow-Origin", +// "Access-Control-Allow-Credentials" +// )); +// configuration.setAllowCredentials(true); +// } +// +// @Bean +// public UsernamePasswordAuthenticationFilter authenticationFilter(AuthenticationManager authenticationManager) { +// UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(); +// filter.setAuthenticationManager(authenticationManager); +// return filter; +// } +//} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 204ecfa..9c4f1ed 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -33,7 +33,7 @@ spring: api-key: ${OPEN-AI-KEY} model: gpt-3.5-turbo security: - jwtSecret: 0aQ+z+0UifxvQzCXzQ4L1AdXVXLjPjS3t3DEVWCG2SMyEVrNFHtQ6Bok106znS0+DjxMHwT2OGTcmAS5DNXFIg== + jwtSecret: eQUxnnSq6Ypz7FvcVBFh8AzvRwInfXokdCPCgY8G3ZTVsWCcpDE0Xun3HlgWd9OqRxxkKghUTAuZLJrt4grpPQ== jwtExpirationMs: 604800000 apiKey: 53e72eed-6f0b-4d5b-9cc5-088487d969b9 From 67eb2a33e9f6bc7093b50139b5168ac0cb85fef8 Mon Sep 17 00:00:00 2001 From: krishnaBaile Date: Mon, 20 Jan 2025 15:37:13 +0530 Subject: [PATCH 9/9] security implementation --- .../openAi/security/AuthenticationFilter.java | 11 +- .../com/openAi/security/ConfigController.java | 4 +- .../openAi/security/WebSecurityConfig.java | 282 +++++++++--------- .../security/utils/WebSecurityConfig.java | 252 ++++++++-------- 4 files changed, 275 insertions(+), 274 deletions(-) diff --git a/src/main/java/com/openAi/security/AuthenticationFilter.java b/src/main/java/com/openAi/security/AuthenticationFilter.java index 354756b..86362d3 100644 --- a/src/main/java/com/openAi/security/AuthenticationFilter.java +++ b/src/main/java/com/openAi/security/AuthenticationFilter.java @@ -16,6 +16,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; @@ -46,6 +47,7 @@ public class AuthenticationFilter extends OncePerRequestFilter { @Value("${security.apiKey}") private String apiKey; + private AuthenticationManager authenticationManager; public AuthenticationFilter() { SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); @@ -61,11 +63,6 @@ protected void doFilterInternal( String.format("Requested path: %s at %s by %s", path, new Date(), request.getRemoteHost())); if ( new AntPathMatcher().match("/getToken", path) - || new AntPathMatcher().match("/getTokenGoogleAuth", path) - || new AntPathMatcher().match("/getTokenUserAuth", path) - || new AntPathMatcher().match("/user/generatePassword", path) - || new AntPathMatcher().match("/resetPassword", path) - || new AntPathMatcher().match("/user/roles", path) || HttpMethod.OPTIONS.name().equalsIgnoreCase(request.getMethod()) || new AntPathMatcher().match("/", path) && apiKey.equals(request.getHeader("Api-Key"))) { @@ -128,6 +125,10 @@ public String parseJwt() { throw InvalidAuthenticationException.invalidToken("Failed to parse JWT Token"); } + + public void setAuthenticationManager(AuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + } } diff --git a/src/main/java/com/openAi/security/ConfigController.java b/src/main/java/com/openAi/security/ConfigController.java index 09924f7..7fbd1d2 100644 --- a/src/main/java/com/openAi/security/ConfigController.java +++ b/src/main/java/com/openAi/security/ConfigController.java @@ -16,12 +16,12 @@ @RequiredArgsConstructor public class ConfigController { - private final WebSecurityConfig webSecurityConfig; + private final com.openAi.security.WebSecurityConfig webSecurityConfig; @PostMapping("/refresh-cors-config") public ResponseEntity refreshCorsConfig() { CorsConfiguration configuration = new CorsConfiguration(); - webSecurityConfig.updateCorsConfiguration(); + webSecurityConfig.updateCorsConfiguration(configuration); return ResponseEntity.ok("CORS configuration updated successfully"); } } diff --git a/src/main/java/com/openAi/security/WebSecurityConfig.java b/src/main/java/com/openAi/security/WebSecurityConfig.java index 18e6084..ef459b1 100644 --- a/src/main/java/com/openAi/security/WebSecurityConfig.java +++ b/src/main/java/com/openAi/security/WebSecurityConfig.java @@ -1,141 +1,141 @@ -package com.openAi.security; - -import com.openAi.security.entity.AllowedDomain; -import com.openAi.security.repository.AllowedDomainRepository; -import lombok.RequiredArgsConstructor; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.http.HttpStatus; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.web.authentication.HttpStatusEntryPoint; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.CorsConfigurationSource; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; - -import java.util.Arrays; -import java.util.List; - -@Configuration -@EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true) -@RequiredArgsConstructor -public class WebSecurityConfig { - - private final AuthenticationFilter filter; - - private final AllowedDomainRepository allowedDomainRepository; - - private CorsConfiguration configuration = new CorsConfiguration(); - - -// @Override - protected void configure(HttpSecurity http) throws Exception { - http.cors(cors -> cors.configurationSource(corsConfigurationSource())) - .csrf(csrf -> csrf.disable()) - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .authorizeHttpRequests(authorize -> authorize - .requestMatchers( - "/getToken", - "/cicero/cicero-compliance-data", - "/cicero/importCiceroData", - "/technology/getTechDigest/label", - "/valueAdd/valueAddsByTag", - "/tech/categories", - "/tech/categories/*", - "/tech/category/*/value-adds", - "/tech/category/*/blogs", - "/tech/category/*/teams", - "/tech/category/**", - "/tech/**", - "/getTokenUserAuth", - "/user/generatePassword", - "/resetPassword", - "/getTokenGoogleAuth" - ).permitAll() - .anyRequest().authenticated() - ) - .exceptionHandling(exception -> exception.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) - .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class); - } - @Bean - @Profile({"dev","staging","prod"}) - public CorsConfigurationSource corsConfigurationSource() { - updateCorsConfiguration(); - configuration.addExposedHeader("Set-Cookie"); - configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); - // setAllowCredentials(true) is important, otherwise: - // The value of the 'Access-Control-Allow-Origin' header in the response must not be the - // wildcard '*' when the request's credentials mode is 'include'. - // setAllowedHeaders is important! Without it, OPTIONS preflight request - // will fail with 403 Invalid CORS request - configuration.setAllowedHeaders( - List.of( - "Api-Key", - "Authorization", - "Cache-Control", - "Content-Type", - "Access-Control-Allow-Origin", - "Access-Control-Allow-Credentials")); - configuration.setAllowCredentials(true); - - final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", configuration); - return source; - } - - @Bean - @Profile("test") - public CorsConfigurationSource corsConfigurationSourceTest() { - final CorsConfiguration corsConfiguration = new CorsConfiguration(); - corsConfiguration.setAllowedOrigins( - List.of( - "https://playbook.talentica.com/", - "https://orion.talentica.com/", - "https://prod-orion.talentica.com/", - "http://localhost:3000/", - "http://localhost/", - "https://stagingplaybook.talentica.com", - "https://dev-orion.talentica.com/", - "https://stagingorion.talentica.com", - "https://staging-orion.talentica.com/", - "http://localhost:3001/", - "https://stagingknowledgebase.talentica.com/", - "https://stagingknowledgebase-sales.talentica.com/", - "https://staging.kb.talentica.com/", - "https://stagingknowledgebase.talentica.com/", - "https://nexus.talentica.com/", - "https://kb.talentica.com/")); - corsConfiguration.addExposedHeader("Set-Cookie"); - corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); - // setAllowCredentials(true) is important, otherwise: - // The value of the 'Access-Control-Allow-Origin' header in the response must not be the - // wildcard '*' when the request's credentials mode is 'include'. - // setAllowedHeaders is important! Without it, OPTIONS preflight request - // will fail with 403 Invalid CORS request - corsConfiguration.setAllowedHeaders( - List.of( - "Api-Key", - "Authorization", - "Cache-Control", - "Content-Type", - "Access-Control-Allow-Origin", - "Access-Control-Allow-Credentials")); - corsConfiguration.setAllowCredentials(true); - - final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", corsConfiguration); - return source; - } - - public void updateCorsConfiguration() { - List origins = allowedDomainRepository.findAll() - .stream().map(AllowedDomain::getDomainName).toList(); - configuration.setAllowedOrigins(origins); - } -} +//package com.openAi.security; +// +//import com.openAi.security.entity.AllowedDomain; +//import com.openAi.security.repository.AllowedDomainRepository; +//import lombok.RequiredArgsConstructor; +// +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.context.annotation.Profile; +//import org.springframework.http.HttpStatus; +//import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +//import org.springframework.security.config.annotation.web.builders.HttpSecurity; +//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +//import org.springframework.security.config.http.SessionCreationPolicy; +//import org.springframework.security.web.authentication.HttpStatusEntryPoint; +//import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +//import org.springframework.web.cors.CorsConfiguration; +//import org.springframework.web.cors.CorsConfigurationSource; +//import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +// +//import java.util.Arrays; +//import java.util.List; +// +//@Configuration +//@EnableWebSecurity +//@EnableGlobalMethodSecurity(prePostEnabled = true) +//@RequiredArgsConstructor +//public class WebSecurityConfig { +// +// private final AuthenticationFilter filter; +// +// private final AllowedDomainRepository allowedDomainRepository; +// +// private CorsConfiguration configuration = new CorsConfiguration(); +// +// +//// @Override +// protected void configure(HttpSecurity http) throws Exception { +// http.cors(cors -> cors.configurationSource(corsConfigurationSource())) +// .csrf(csrf -> csrf.disable()) +// .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) +// .authorizeHttpRequests(authorize -> authorize +// .requestMatchers( +// "/getToken", +// "/cicero/cicero-compliance-data", +// "/cicero/importCiceroData", +// "/technology/getTechDigest/label", +// "/valueAdd/valueAddsByTag", +// "/tech/categories", +// "/tech/categories/*", +// "/tech/category/*/value-adds", +// "/tech/category/*/blogs", +// "/tech/category/*/teams", +// "/tech/category/**", +// "/tech/**", +// "/getTokenUserAuth", +// "/user/generatePassword", +// "/resetPassword", +// "/getTokenGoogleAuth" +// ).permitAll() +// .anyRequest().authenticated() +// ) +// .exceptionHandling(exception -> exception.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) +// .addFilterBefore(filter, AuthenticationFilter.class); +// } +// @Bean +// @Profile({"dev","staging","prod"}) +// public CorsConfigurationSource corsConfigurationSource() { +// updateCorsConfiguration(); +// configuration.addExposedHeader("Set-Cookie"); +// configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); +// // setAllowCredentials(true) is important, otherwise: +// // The value of the 'Access-Control-Allow-Origin' header in the response must not be the +// // wildcard '*' when the request's credentials mode is 'include'. +// // setAllowedHeaders is important! Without it, OPTIONS preflight request +// // will fail with 403 Invalid CORS request +// configuration.setAllowedHeaders( +// List.of( +// "Api-Key", +// "Authorization", +// "Cache-Control", +// "Content-Type", +// "Access-Control-Allow-Origin", +// "Access-Control-Allow-Credentials")); +// configuration.setAllowCredentials(true); +// +// final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); +// source.registerCorsConfiguration("/**", configuration); +// return source; +// } +// +// @Bean +// @Profile("test") +// public CorsConfigurationSource corsConfigurationSourceTest() { +// final CorsConfiguration corsConfiguration = new CorsConfiguration(); +// corsConfiguration.setAllowedOrigins( +// List.of( +// "https://playbook.talentica.com/", +// "https://orion.talentica.com/", +// "https://prod-orion.talentica.com/", +// "http://localhost:3000/", +// "http://localhost/", +// "https://stagingplaybook.talentica.com", +// "https://dev-orion.talentica.com/", +// "https://stagingorion.talentica.com", +// "https://staging-orion.talentica.com/", +// "http://localhost:3001/", +// "https://stagingknowledgebase.talentica.com/", +// "https://stagingknowledgebase-sales.talentica.com/", +// "https://staging.kb.talentica.com/", +// "https://stagingknowledgebase.talentica.com/", +// "https://nexus.talentica.com/", +// "https://kb.talentica.com/")); +// corsConfiguration.addExposedHeader("Set-Cookie"); +// corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); +// // setAllowCredentials(true) is important, otherwise: +// // The value of the 'Access-Control-Allow-Origin' header in the response must not be the +// // wildcard '*' when the request's credentials mode is 'include'. +// // setAllowedHeaders is important! Without it, OPTIONS preflight request +// // will fail with 403 Invalid CORS request +// corsConfiguration.setAllowedHeaders( +// List.of( +// "Api-Key", +// "Authorization", +// "Cache-Control", +// "Content-Type", +// "Access-Control-Allow-Origin", +// "Access-Control-Allow-Credentials")); +// corsConfiguration.setAllowCredentials(true); +// +// final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); +// source.registerCorsConfiguration("/**", corsConfiguration); +// return source; +// } +// +// public void updateCorsConfiguration() { +// List origins = allowedDomainRepository.findAll() +// .stream().map(AllowedDomain::getDomainName).toList(); +// configuration.setAllowedOrigins(origins); +// } +//} diff --git a/src/main/java/com/openAi/security/utils/WebSecurityConfig.java b/src/main/java/com/openAi/security/utils/WebSecurityConfig.java index ccf21c0..2a0fd11 100644 --- a/src/main/java/com/openAi/security/utils/WebSecurityConfig.java +++ b/src/main/java/com/openAi/security/utils/WebSecurityConfig.java @@ -1,126 +1,126 @@ -//package com.openAi.security; -// -//import com.openAi.security.entity.AllowedDomain; -//import com.openAi.security.repository.AllowedDomainRepository; -//import lombok.RequiredArgsConstructor; -//import org.springframework.context.annotation.Bean; -//import org.springframework.context.annotation.Configuration; -//import org.springframework.context.annotation.Profile; -//import org.springframework.http.HttpStatus; -//import org.springframework.security.authentication.AuthenticationManager; -//import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -//import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; -//import org.springframework.security.config.annotation.web.builders.HttpSecurity; -//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -//import org.springframework.security.config.http.SessionCreationPolicy; -//import org.springframework.security.web.SecurityFilterChain; -//import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -//import org.springframework.security.web.authentication.HttpStatusEntryPoint; -//import org.springframework.web.cors.CorsConfiguration; -//import org.springframework.web.cors.CorsConfigurationSource; -//import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -// -//import java.util.List; -//import java.util.stream.Collectors; -// -//@Configuration -//@EnableMethodSecurity(prePostEnabled = true) -//@RequiredArgsConstructor -//@EnableWebSecurity -//public class WebSecurityConfig { -// -// private final AllowedDomainRepository allowedDomainRepository; -// -// @Bean -// public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception { -// http.cors(cors -> cors.configurationSource(corsConfigurationSource())) -// .csrf(csrf -> csrf.disable()) -// .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) -// .authorizeHttpRequests(authorize -> authorize -// .requestMatchers( -// "/getToken", -// "/getTokenUserAuth", -// "/user/generatePassword", -// "/resetPassword", -// "/getTokenGoogleAuth" -// ).permitAll() -// .anyRequest().authenticated() -// ) -// .exceptionHandling(exception -> exception.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) -// .addFilterBefore(authenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class); -// return http.build(); -// } -// -// @Bean -// public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { -// return authenticationConfiguration.getAuthenticationManager(); -// } -// -// @Bean -// public CorsConfigurationSource corsConfigurationSource() { -// CorsConfiguration configuration = new CorsConfiguration(); -// updateCorsConfiguration(configuration); -// applyCommonCorsSettings(configuration); -// -// UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); -// source.registerCorsConfiguration("/**", configuration); -// return source; -// } -// -// @Bean -// @Profile("test") -// public CorsConfigurationSource corsConfigurationSourceTest() { -// CorsConfiguration configuration = new CorsConfiguration(); -// configuration.setAllowedOrigins(List.of( -// "https://playbook.talentica.com/", -// "https://orion.talentica.com/", -// "https://prod-orion.talentica.com/", -// "http://localhost:3000/", -// "http://localhost/", -// "https://stagingplaybook.talentica.com", -// "https://dev-orion.talentica.com/", -// "https://stagingorion.talentica.com", -// "https://staging-orion.talentica.com/", -// "http://localhost:3001/", -// "https://stagingknowledgebase.talentica.com/", -// "https://stagingknowledgebase-sales.talentica.com/", -// "https://staging.kb.talentica.com/", -// "https://nexus.talentica.com/", -// "https://kb.talentica.com/" -// )); -// applyCommonCorsSettings(configuration); -// -// UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); -// source.registerCorsConfiguration("/**", configuration); -// return source; -// } -// -// public void updateCorsConfiguration(CorsConfiguration configuration) { -// List allowedOrigins = allowedDomainRepository.findAll() -// .stream() -// .map(AllowedDomain::getDomainName) -// .collect(Collectors.toList()); -// configuration.setAllowedOrigins(allowedOrigins); -// } -// -// private void applyCommonCorsSettings(CorsConfiguration configuration) { -// configuration.addExposedHeader("Set-Cookie"); -// configuration.setAllowedMethods(List.of("GET", "POST", "OPTIONS", "PUT", "DELETE")); -// configuration.setAllowedHeaders(List.of( -// "Api-Key", -// "Authorization", -// "Cache-Control", -// "Content-Type", -// "Access-Control-Allow-Origin", -// "Access-Control-Allow-Credentials" -// )); -// configuration.setAllowCredentials(true); -// } -// -// @Bean -// public UsernamePasswordAuthenticationFilter authenticationFilter(AuthenticationManager authenticationManager) { -// UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(); -// filter.setAuthenticationManager(authenticationManager); -// return filter; -// } -//} +package com.openAi.security; + +import com.openAi.security.entity.AllowedDomain; +import com.openAi.security.repository.AllowedDomainRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.HttpStatusEntryPoint; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +import java.util.List; +import java.util.stream.Collectors; + +@Configuration +@EnableMethodSecurity(prePostEnabled = true) +@RequiredArgsConstructor +@EnableWebSecurity +public class WebSecurityConfig { + + private final AllowedDomainRepository allowedDomainRepository; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception { + http.cors(cors -> cors.configurationSource(corsConfigurationSource())) + .csrf(csrf -> csrf.disable()) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(authorize -> authorize + .requestMatchers( + "/getToken", + "/getTokenUserAuth", + "/user/generatePassword", + "/resetPassword", + "/getTokenGoogleAuth" + ).permitAll() + .anyRequest().authenticated() + ) + .exceptionHandling(exception -> exception.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) + .addFilterBefore(authenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class); + return http.build(); + } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + updateCorsConfiguration(configuration); + applyCommonCorsSettings(configuration); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } + + @Bean + @Profile("test") + public CorsConfigurationSource corsConfigurationSourceTest() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOrigins(List.of( + "https://playbook.talentica.com/", + "https://orion.talentica.com/", + "https://prod-orion.talentica.com/", + "http://localhost:3000/", + "http://localhost/", + "https://stagingplaybook.talentica.com", + "https://dev-orion.talentica.com/", + "https://stagingorion.talentica.com", + "https://staging-orion.talentica.com/", + "http://localhost:3001/", + "https://stagingknowledgebase.talentica.com/", + "https://stagingknowledgebase-sales.talentica.com/", + "https://staging.kb.talentica.com/", + "https://nexus.talentica.com/", + "https://kb.talentica.com/" + )); + applyCommonCorsSettings(configuration); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } + + public void updateCorsConfiguration(CorsConfiguration configuration) { + List allowedOrigins = allowedDomainRepository.findAll() + .stream() + .map(AllowedDomain::getDomainName) + .collect(Collectors.toList()); + configuration.setAllowedOrigins(allowedOrigins); + } + + private void applyCommonCorsSettings(CorsConfiguration configuration) { + configuration.addExposedHeader("Set-Cookie"); + configuration.setAllowedMethods(List.of("GET", "POST", "OPTIONS", "PUT", "DELETE")); + configuration.setAllowedHeaders(List.of( + "Api-Key", + "Authorization", + "Cache-Control", + "Content-Type", + "Access-Control-Allow-Origin", + "Access-Control-Allow-Credentials" + )); + configuration.setAllowCredentials(true); + } + + @Bean + public AuthenticationFilter authenticationFilter(AuthenticationManager authenticationManager) { + AuthenticationFilter filter = new AuthenticationFilter(); + filter.setAuthenticationManager(authenticationManager); + return filter; + } +}