diff --git a/pom.xml b/pom.xml
index 1de04e3..94371a8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,7 +64,26 @@
1.18.34
-
+
+ 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
+
org.antlr
@@ -72,10 +91,10 @@
4.3.4
- com.google.code.gson
- gson
- 2.8.8
-
+ com.google.code.gson
+ gson
+ 2.8.8
+
diff --git a/src/main/java/com/olympus/hermione/security/config/CorsConfig.java b/src/main/java/com/olympus/hermione/security/config/CorsConfig.java
new file mode 100644
index 0000000..1d704b8
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/config/CorsConfig.java
@@ -0,0 +1,16 @@
+package com.olympus.hermione.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/hermione/security/config/SecurityConfig.java b/src/main/java/com/olympus/hermione/security/config/SecurityConfig.java
new file mode 100644
index 0000000..85f741f
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/config/SecurityConfig.java
@@ -0,0 +1,87 @@
+package com.olympus.hermione.security.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import org.springframework.security.authentication.AuthenticationManager;
+
+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.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.hermione.security.filter.JwtTokenFilter;
+import com.olympus.hermione.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()
+ .requestMatchers("/test/**").permitAll()
+ .anyRequest().permitAll());//.authenticated());
+
+ http.authenticationProvider(authenticationProvider());
+
+ http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
+
+ return http.build();
+ }
+
+}
+
diff --git a/src/main/java/com/olympus/hermione/security/controllers/AuthController.java b/src/main/java/com/olympus/hermione/security/controllers/AuthController.java
new file mode 100644
index 0000000..c1bd6d3
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/controllers/AuthController.java
@@ -0,0 +1,88 @@
+package com.olympus.hermione.security.controllers;
+
+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.hermione.security.dto.AuthenticationRequest;
+import com.olympus.hermione.security.dto.AuthenticationResponse;
+import com.olympus.hermione.security.dto.FetchUserResponse;
+import com.olympus.hermione.security.entity.User;
+import com.olympus.hermione.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/hermione/security/dto/AuthenticationRequest.java b/src/main/java/com/olympus/hermione/security/dto/AuthenticationRequest.java
new file mode 100644
index 0000000..0aa9c3a
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/dto/AuthenticationRequest.java
@@ -0,0 +1,18 @@
+package com.olympus.hermione.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/hermione/security/dto/AuthenticationResponse.java b/src/main/java/com/olympus/hermione/security/dto/AuthenticationResponse.java
new file mode 100644
index 0000000..f799068
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/dto/AuthenticationResponse.java
@@ -0,0 +1,19 @@
+package com.olympus.hermione.security.dto;
+
+import com.olympus.hermione.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/hermione/security/dto/FetchUserResponse.java b/src/main/java/com/olympus/hermione/security/dto/FetchUserResponse.java
new file mode 100644
index 0000000..ec9e324
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/dto/FetchUserResponse.java
@@ -0,0 +1,16 @@
+package com.olympus.hermione.security.dto;
+
+import com.olympus.hermione.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/hermione/security/entity/Role.java b/src/main/java/com/olympus/hermione/security/entity/Role.java
new file mode 100644
index 0000000..2216e14
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/entity/Role.java
@@ -0,0 +1,6 @@
+package com.olympus.hermione.security.entity;
+
+public enum Role {
+ ADMIN,USER
+}
+
diff --git a/src/main/java/com/olympus/hermione/security/entity/User.java b/src/main/java/com/olympus/hermione/security/entity/User.java
new file mode 100644
index 0000000..4bbd870
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/entity/User.java
@@ -0,0 +1,41 @@
+package com.olympus.hermione.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/hermione/security/filter/JwtTokenFilter.java b/src/main/java/com/olympus/hermione/security/filter/JwtTokenFilter.java
new file mode 100644
index 0000000..dd6dd26
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/filter/JwtTokenFilter.java
@@ -0,0 +1,54 @@
+package com.olympus.hermione.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.hermione.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);
+ }
+
+
+}
+
diff --git a/src/main/java/com/olympus/hermione/security/repository/UserRepository.java b/src/main/java/com/olympus/hermione/security/repository/UserRepository.java
new file mode 100644
index 0000000..1709b4a
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/repository/UserRepository.java
@@ -0,0 +1,15 @@
+package com.olympus.hermione.security.repository;
+
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.data.mongodb.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import com.olympus.hermione.security.entity.User;
+
+@Repository
+public interface UserRepository extends MongoRepository {
+
+ @Query("{username:'?0'}")
+ User findUserByUsername(String username);
+}
+
diff --git a/src/main/java/com/olympus/hermione/security/services/CustomUserDetailsService.java b/src/main/java/com/olympus/hermione/security/services/CustomUserDetailsService.java
new file mode 100644
index 0000000..977695b
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/services/CustomUserDetailsService.java
@@ -0,0 +1,35 @@
+package com.olympus.hermione.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.hermione.security.entity.User;
+import com.olympus.hermione.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/hermione/security/utility/JwtAuthenticationEntryPoint.java b/src/main/java/com/olympus/hermione/security/utility/JwtAuthenticationEntryPoint.java
new file mode 100644
index 0000000..affcdbc
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/utility/JwtAuthenticationEntryPoint.java
@@ -0,0 +1,30 @@
+package com.olympus.hermione.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/hermione/security/utility/JwtTokenProvider.java b/src/main/java/com/olympus/hermione/security/utility/JwtTokenProvider.java
new file mode 100644
index 0000000..d2f0b34
--- /dev/null
+++ b/src/main/java/com/olympus/hermione/security/utility/JwtTokenProvider.java
@@ -0,0 +1,76 @@
+package com.olympus.hermione.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.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();
+ }
+}
+