diff --git a/pom.xml b/pom.xml
index 1c685a1..8865359 100644
--- a/pom.xml
+++ b/pom.xml
@@ -98,6 +98,27 @@
6.8.0.202311291450-r
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.11.5
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.11.5
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.11.5
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
diff --git a/src/main/java/com/olympus/apollo/security/config/CorsConfig.java b/src/main/java/com/olympus/apollo/security/config/CorsConfig.java
new file mode 100644
index 0000000..7c6e6bb
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/config/CorsConfig.java
@@ -0,0 +1,17 @@
+package com.olympus.apollo.security.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class CorsConfig implements WebMvcConfigurer {
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowedOrigins("*")
+ .allowedHeaders("*")
+ .allowedMethods("GET", "POST", "PUT", "DELETE");
+ }
+}
+
diff --git a/src/main/java/com/olympus/apollo/security/config/SecurityConfig.java b/src/main/java/com/olympus/apollo/security/config/SecurityConfig.java
new file mode 100644
index 0000000..f3db6bb
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/config/SecurityConfig.java
@@ -0,0 +1,89 @@
+package com.olympus.apollo.security.config;
+
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import org.springframework.context.annotation.Lazy;
+import org.springframework.security.authentication.AuthenticationManager;
+
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
+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.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+import com.olympus.apollo.security.filter.JwtTokenFilter;
+import com.olympus.apollo.security.services.CustomUserDetailsService;
+
+@EnableWebSecurity
+@Configuration
+public class SecurityConfig {
+
+ @Autowired
+ CustomUserDetailsService userDetailsService;
+
+ /* @Autowired
+ private AuthEntryPointJwt unauthorizedHandler;
+ */
+ @Bean
+ public JwtTokenFilter authenticationJwtTokenFilter() {
+ return new JwtTokenFilter();
+ }
+
+//@Override
+//public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
+// authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
+//}
+
+ @Bean
+ public DaoAuthenticationProvider authenticationProvider() {
+ DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
+
+ authProvider.setUserDetailsService(userDetailsService);
+ authProvider.setPasswordEncoder(passwordEncoder());
+
+ return authProvider;
+ }
+
+//@Bean
+//@Override
+//public AuthenticationManager authenticationManagerBean() throws Exception {
+// return super.authenticationManagerBean();
+//}
+
+ @Bean
+ public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
+ return authConfig.getAuthenticationManager();
+ }
+
+
+ @Bean
+ PasswordEncoder passwordEncoder() {
+ return NoOpPasswordEncoder.getInstance();
+ }
+
+
+ @Bean
+ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+ http.csrf(csrf -> csrf.disable())
+ .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+ .authorizeHttpRequests(auth -> auth.requestMatchers("/api/auth/**").permitAll().requestMatchers("/api/test/**")
+ .permitAll().anyRequest().authenticated());
+
+ http.authenticationProvider(authenticationProvider());
+
+ http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
+
+ return http.build();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/olympus/apollo/security/controllers/AuthController.java b/src/main/java/com/olympus/apollo/security/controllers/AuthController.java
new file mode 100644
index 0000000..46cc661
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/controllers/AuthController.java
@@ -0,0 +1,90 @@
+package com.olympus.apollo.security.controllers;
+
+import java.security.Principal;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.olympus.apollo.security.dto.AuthenticationRequest;
+import com.olympus.apollo.security.dto.AuthenticationResponse;
+import com.olympus.apollo.security.dto.FetchUserResponse;
+import com.olympus.apollo.security.entity.User;
+import com.olympus.apollo.security.utility.JwtTokenProvider;
+
+@RestController
+@CrossOrigin
+@RequestMapping("/api/auth")
+public class AuthController {
+
+ @Autowired
+ private AuthenticationManager authenticationManager;
+
+ @Autowired
+ private JwtTokenProvider jwtTokenProvider;
+
+ @PostMapping("/login")
+ public ResponseEntity> authenticateUser(@RequestBody AuthenticationRequest authenticationRequest) {
+
+ Authentication authentication = authenticationManager.authenticate(
+ new UsernamePasswordAuthenticationToken(
+ authenticationRequest.getUsername(),
+ authenticationRequest.getPassword()
+ )
+ );
+
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ String jwt = jwtTokenProvider.createToken(authentication);
+
+
+ HttpHeaders httpHeaders = new HttpHeaders();
+ httpHeaders.add("authorization", jwt);
+ httpHeaders.add("access-control-expose-headers", "authorization");
+ AuthenticationResponse authenticationResponse = new AuthenticationResponse(jwt, (User) authentication.getPrincipal());
+
+ return ResponseEntity.ok().headers(httpHeaders).body(authenticationResponse);
+
+ }
+
+ @GetMapping("/fetch-user")
+ public FetchUserResponse fetchUser(Authentication authentication) {
+ User principal = (User) authentication.getPrincipal();
+ principal.setPassword(null);
+ FetchUserResponse fetchUserResponse = new FetchUserResponse();
+ fetchUserResponse.setData(principal);
+ return fetchUserResponse;
+
+ }
+
+
+ @GetMapping("/refresh-token")
+ public ResponseEntity> refreshToken(Authentication authentication) {
+
+
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ String jwt = jwtTokenProvider.createToken(authentication);
+
+
+ HttpHeaders httpHeaders = new HttpHeaders();
+ httpHeaders.add("authorization", jwt);
+ httpHeaders.add("access-control-expose-headers", "authorization");
+ AuthenticationResponse authenticationResponse = new AuthenticationResponse(jwt, (User) authentication.getPrincipal());
+
+ return ResponseEntity.ok().headers(httpHeaders).body(authenticationResponse);
+ }
+
+ @GetMapping("/test")
+ public ResponseEntity> test() {
+ return ResponseEntity.ok(" you have access now ");
+ }
+}
diff --git a/src/main/java/com/olympus/apollo/security/dto/AuthenticationRequest.java b/src/main/java/com/olympus/apollo/security/dto/AuthenticationRequest.java
new file mode 100644
index 0000000..4c4accc
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/dto/AuthenticationRequest.java
@@ -0,0 +1,16 @@
+package com.olympus.apollo.security.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+public class AuthenticationRequest {
+
+ private String username;
+ private String password;
+}
diff --git a/src/main/java/com/olympus/apollo/security/dto/AuthenticationResponse.java b/src/main/java/com/olympus/apollo/security/dto/AuthenticationResponse.java
new file mode 100644
index 0000000..53dcd46
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/dto/AuthenticationResponse.java
@@ -0,0 +1,19 @@
+package com.olympus.apollo.security.dto;
+
+import com.olympus.apollo.security.entity.User;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class AuthenticationResponse {
+
+ private String accessToken;
+ private User data;
+
+}
diff --git a/src/main/java/com/olympus/apollo/security/dto/FetchUserResponse.java b/src/main/java/com/olympus/apollo/security/dto/FetchUserResponse.java
new file mode 100644
index 0000000..41f5aed
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/dto/FetchUserResponse.java
@@ -0,0 +1,23 @@
+package com.olympus.apollo.security.dto;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+import com.olympus.apollo.security.entity.Role;
+import com.olympus.apollo.security.entity.User;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class FetchUserResponse {
+ private User data;
+
+
+
+}
+
diff --git a/src/main/java/com/olympus/apollo/security/entity/Role.java b/src/main/java/com/olympus/apollo/security/entity/Role.java
new file mode 100644
index 0000000..1b56158
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/entity/Role.java
@@ -0,0 +1,5 @@
+package com.olympus.apollo.security.entity;
+
+public enum Role {
+ ADMIN,USER
+}
diff --git a/src/main/java/com/olympus/apollo/security/entity/User.java b/src/main/java/com/olympus/apollo/security/entity/User.java
new file mode 100644
index 0000000..0524cac
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/entity/User.java
@@ -0,0 +1,43 @@
+package com.olympus.apollo.security.entity;
+
+import java.util.Collection;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import java.util.List;
+
+
+@Document(collection = "users")
+@Getter @Setter
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class User implements UserDetails{
+ @Id
+ private String id;
+ private String username;
+ private String password;
+ private String name;
+ private String surname;
+
+ private Role role;
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ return List.of(new SimpleGrantedAuthority(role.name()));
+ }
+
+
+}
+
diff --git a/src/main/java/com/olympus/apollo/security/filter/JwtTokenFilter.java b/src/main/java/com/olympus/apollo/security/filter/JwtTokenFilter.java
new file mode 100644
index 0000000..208b1d4
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/filter/JwtTokenFilter.java
@@ -0,0 +1,53 @@
+package com.olympus.apollo.security.filter;
+
+import java.io.IOException;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import com.olympus.apollo.security.utility.JwtTokenProvider;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+
+@Component
+@AllArgsConstructor
+@NoArgsConstructor
+public class JwtTokenFilter extends OncePerRequestFilter {
+
+ @Autowired
+ private JwtTokenProvider jwtTokenProvider;
+
+ @Autowired
+ private UserDetailsService userDetailsService;
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+
+ String token = jwtTokenProvider.resolveToken(request);
+
+ if (token != null && jwtTokenProvider.validateToken(token)) {
+
+ UserDetails userDetails = userDetailsService.loadUserByUsername(jwtTokenProvider.getUsername(token));
+
+ UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
+
+ authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ }
+
+ filterChain.doFilter(request, response);
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/olympus/apollo/security/repository/UserRepository.java b/src/main/java/com/olympus/apollo/security/repository/UserRepository.java
new file mode 100644
index 0000000..e1ce363
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/repository/UserRepository.java
@@ -0,0 +1,14 @@
+package com.olympus.apollo.security.repository;
+
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.data.mongodb.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import com.olympus.apollo.security.entity.User;
+
+@Repository
+public interface UserRepository extends MongoRepository {
+
+ @Query("{username:'?0'}")
+ User findUserByUsername(String username);
+}
diff --git a/src/main/java/com/olympus/apollo/security/services/CustomUserDetailsService.java b/src/main/java/com/olympus/apollo/security/services/CustomUserDetailsService.java
new file mode 100644
index 0000000..b231ee7
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/services/CustomUserDetailsService.java
@@ -0,0 +1,35 @@
+package com.olympus.apollo.security.services;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+import com.olympus.apollo.security.entity.User;
+import com.olympus.apollo.security.repository.UserRepository;
+
+@Configuration
+@Service
+public class CustomUserDetailsService implements UserDetailsService {
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ try {
+ User user = userRepository.findUserByUsername(username);
+ if(user != null){
+ return user;
+ }else{
+ throw new Exception("user Not found ");
+ }
+
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/src/main/java/com/olympus/apollo/security/utility/JwtAuthenticationEntryPoint.java b/src/main/java/com/olympus/apollo/security/utility/JwtAuthenticationEntryPoint.java
new file mode 100644
index 0000000..b7d7526
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/utility/JwtAuthenticationEntryPoint.java
@@ -0,0 +1,29 @@
+package com.olympus.apollo.security.utility;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+
+import io.jsonwebtoken.io.IOException;
+
+
+@Component
+public class JwtAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
+
+ @Override
+ public void commence(HttpServletRequest request, HttpServletResponse response,
+ AuthenticationException authException) throws IOException, java.io.IOException {
+
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.setContentType("application/json");
+ response.getWriter().write("{ \"message\": \"" + authException.getMessage() + "\" }");
+ }
+
+ @Override
+ public void afterPropertiesSet() {
+ setRealmName("JWT Authentication");
+ super.afterPropertiesSet();
+ }
+}
diff --git a/src/main/java/com/olympus/apollo/security/utility/JwtTokenProvider.java b/src/main/java/com/olympus/apollo/security/utility/JwtTokenProvider.java
new file mode 100644
index 0000000..55c13c2
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/utility/JwtTokenProvider.java
@@ -0,0 +1,76 @@
+package com.olympus.apollo.security.utility;
+
+import org.springframework.stereotype.Component;
+
+import io.jsonwebtoken.*;
+import io.jsonwebtoken.security.Keys;
+import io.jsonwebtoken.security.SignatureException;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import java.security.Key;
+import java.util.Date;
+
+@Component
+@Slf4j
+public class JwtTokenProvider {
+
+ Key key = Keys.secretKeyFor(SignatureAlgorithm.HS512);
+
+ public String createToken(Authentication authentication) {
+
+ UserDetails userDetails = (UserDetails) authentication.getPrincipal();
+ Date now = new Date();
+ Date expiryDate = new Date(now.getTime() + 3600000);
+
+ return Jwts.builder()
+ .setSubject(userDetails.getUsername())
+ .setIssuedAt(new Date())
+ .setExpiration(expiryDate)
+ .signWith(SignatureAlgorithm.HS512, key)
+ .compact();
+ }
+
+
+ public String resolveToken(HttpServletRequest request) {
+
+ String bearerToken = request.getHeader("Authorization");
+ if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
+ return bearerToken.substring(7);
+ }
+ return null;
+ }
+
+ // Check if the token is valid and not expired
+ public boolean validateToken(String token) {
+
+ try {
+ Jwts.parser().setSigningKey(key).parseClaimsJws(token);
+ return true;
+ } catch (MalformedJwtException ex) {
+ log.error("Invalid JWT token");
+ } catch (ExpiredJwtException ex) {
+ log.error("Expired JWT token");
+ } catch (UnsupportedJwtException ex) {
+ log.error("Unsupported JWT token");
+ } catch (IllegalArgumentException ex) {
+ log.error("JWT claims string is empty");
+ } catch (SignatureException e) {
+ log.error("there is an error with the signature of you token ");
+ }
+ return false;
+ }
+
+ // Extract the username from the JWT token
+ public String getUsername(String token) {
+
+ return Jwts.parser()
+ .setSigningKey(key)
+ .parseClaimsJws(token)
+ .getBody()
+ .getSubject();
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 121bc5b..f7da776 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -27,3 +27,5 @@ spring.ai.openai.api-key=sk-proj-j3TFJ0h348DIzMrYYfyUT3BlbkFJjk4HMc8A2ux2Asg8Y7H
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=100MB
+spring.main.allow-circular-references=true
+