diff --git a/pom.xml b/pom.xml
index b793e50..930fa58 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,6 +30,8 @@
21
1.0.0-M6
2023.0.3
+ 21
+ 21
@@ -47,6 +49,15 @@
org.springframework.boot
spring-boot-starter-data-mongodb
+
+ com.azure.spring
+ azure-spring-boot-starter-active-directory
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-oauth2-resource-server
+
org.springframework.boot
spring-boot-starter-test
diff --git a/src/main/java/com/olympus/apollo/security/config/SecurityConfig.java b/src/main/java/com/olympus/apollo/security/config/SecurityConfig.java
index 50e215f..fa22199 100644
--- a/src/main/java/com/olympus/apollo/security/config/SecurityConfig.java
+++ b/src/main/java/com/olympus/apollo/security/config/SecurityConfig.java
@@ -1,14 +1,15 @@
package com.olympus.apollo.security.config;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.*;
+import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@@ -24,18 +25,11 @@ 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() {
@@ -47,38 +41,50 @@ public class SecurityConfig {
return authProvider;
}
-//@Bean
-//@Override
-//public AuthenticationManager authenticationManagerBean() throws Exception {
-// return super.authenticationManagerBean();
-//}
+
+
+ @Bean
+ PasswordEncoder passwordEncoder() {
+ return NoOpPasswordEncoder.getInstance();
+ }
@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("/**").permitAll()
- .anyRequest().authenticated()); //permitAll());
-
- http.authenticationProvider(authenticationProvider());
-
- http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
+ public SecurityFilterChain oauth2Security(HttpSecurity http) throws Exception {
+ http
+ .securityMatcher("/msauth/**") // Match only specific OAuth2 endpoints
+ .authorizeHttpRequests(auth -> auth
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2 -> oauth2.jwt()); // Enable OAuth2 JWT Validation
return http.build();
}
-}
\ No newline at end of file
+ // 🔓 2. Default security for all other URLs
+ @Bean
+ public SecurityFilterChain defaultSecurity(HttpSecurity http) throws Exception {
+ http
+ .csrf().disable()
+ .authorizeHttpRequests(auth -> auth
+ .requestMatchers("/api/auth/**", "/login").permitAll()
+ .anyRequest().authenticated()
+ )
+ .authenticationProvider(authenticationProvider())
+ .addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
+
+ return http.build();
+ }
+
+ @Bean
+ public AuthenticationManager authManager(HttpSecurity http) throws Exception {
+ return http.getSharedObject(AuthenticationManagerBuilder.class)
+ .userDetailsService(userDetailsService)
+ .passwordEncoder(passwordEncoder())
+ .and()
+ .build();
+ }
+
+
+}
+
+
diff --git a/src/main/java/com/olympus/apollo/security/controllers/AuthController.java b/src/main/java/com/olympus/apollo/security/controllers/AuthController.java
index 46cc661..f31ddce 100644
--- a/src/main/java/com/olympus/apollo/security/controllers/AuthController.java
+++ b/src/main/java/com/olympus/apollo/security/controllers/AuthController.java
@@ -1,90 +1,32 @@
package com.olympus.apollo.security.controllers;
-import java.security.Principal;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpHeaders;
+import com.olympus.apollo.security.services.JwtService;
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.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.security.oauth2.jwt.Jwt;
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;
+import java.util.Map;
@RestController
-@CrossOrigin
-@RequestMapping("/api/auth")
+@RequestMapping("/msauth")
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);
+ private final JwtService jwtService;
+ public AuthController(JwtService jwtService) {
+ this.jwtService = jwtService;
}
- @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 ");
+ @PostMapping("/exchange")
+ public ResponseEntity> exchangeToken(@AuthenticationPrincipal Jwt azureJwt) {
+ String internalToken = jwtService.generateInternalToken(azureJwt);
+ return ResponseEntity.ok(Map.of("token", internalToken));
}
}
+
+
+
diff --git a/src/main/java/com/olympus/apollo/security/controllers/LoginController.java b/src/main/java/com/olympus/apollo/security/controllers/LoginController.java
new file mode 100644
index 0000000..2d407ec
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/controllers/LoginController.java
@@ -0,0 +1,82 @@
+package com.olympus.apollo.security.controllers;
+
+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.services.JwtService;
+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.*;
+
+
+@RestController
+@RequestMapping("/api/auth")
+public class LoginController {
+ @Autowired
+ private AuthenticationManager authenticationManager;
+
+ @Autowired
+ private JwtService 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.generateInternalTokenFromUsername(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("fake");
+ FetchUserResponse fetchUserResponse = new FetchUserResponse();
+ fetchUserResponse.setData(principal);
+ return fetchUserResponse;
+
+ }
+
+
+ @GetMapping("/refresh-token")
+ public ResponseEntity> refreshToken(Authentication authentication) {
+
+
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ String jwt = jwtTokenProvider.generateInternalTokenFromUsername(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/filter/JwtTokenFilter.java b/src/main/java/com/olympus/apollo/security/filter/JwtTokenFilter.java
index 208b1d4..878757a 100644
--- a/src/main/java/com/olympus/apollo/security/filter/JwtTokenFilter.java
+++ b/src/main/java/com/olympus/apollo/security/filter/JwtTokenFilter.java
@@ -2,6 +2,7 @@ package com.olympus.apollo.security.filter;
import java.io.IOException;
+import com.olympus.apollo.security.services.JwtService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -11,8 +12,6 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS
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;
@@ -26,7 +25,7 @@ import lombok.NoArgsConstructor;
public class JwtTokenFilter extends OncePerRequestFilter {
@Autowired
- private JwtTokenProvider jwtTokenProvider;
+ private JwtService jwtTokenProvider;
@Autowired
private UserDetailsService userDetailsService;
diff --git a/src/main/java/com/olympus/apollo/security/services/JwtService.java b/src/main/java/com/olympus/apollo/security/services/JwtService.java
new file mode 100644
index 0000000..c9c6cd2
--- /dev/null
+++ b/src/main/java/com/olympus/apollo/security/services/JwtService.java
@@ -0,0 +1,116 @@
+package com.olympus.apollo.security.services;
+
+import io.jsonwebtoken.ExpiredJwtException;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.MalformedJwtException;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.UnsupportedJwtException;
+import io.jsonwebtoken.io.Decoders;
+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.security.oauth2.jwt.Jwt;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.security.Key;
+import java.util.Date;
+
+@Service
+@Slf4j
+public class JwtService {
+
+ private final long EXPIRATION_MS = 3600_000; // 1 hour
+
+
+ public static final String SECRET = "5367566B59703373367639792F423F4528482B4D6251655468576D5A713474375367566B59703373367639792F423F4528482B4D6251655468576D5A71347437";
+
+
+ private Key getSignKey() {
+ byte[] keyBytes = Decoders.BASE64.decode(SECRET);
+ return Keys.hmacShaKeyFor(keyBytes);
+ }
+
+
+ public String generateInternalToken(Jwt azureJwt) {
+ Date now = new Date();
+ Date expiry = new Date(now.getTime() + EXPIRATION_MS);
+
+ String username="";
+ String email = azureJwt.getClaim("email");
+ String username_claim = azureJwt.getClaim("username");
+ String unique_name = azureJwt.getClaim("unique_name");
+
+ if(username_claim == null){
+ username = unique_name;
+ }
+
+ if ( username.contains("@") ){
+ username = username.split("@")[0];
+ }
+ return Jwts.builder()
+ .setSubject(username)
+ .setIssuedAt(new Date())
+ .setExpiration(expiry)
+ .signWith(getSignKey(), SignatureAlgorithm.HS512)
+ //.signWith(SignatureAlgorithm.HS512, SECRET)
+ .compact();
+
+ }
+
+ public String generateInternalTokenFromUsername(Authentication authentication) {
+ UserDetails userDetails = (UserDetails) authentication.getPrincipal();
+ Date now = new Date();
+ Date expiry = new Date(now.getTime() + EXPIRATION_MS);
+
+ return Jwts.builder()
+ .setSubject(userDetails.getUsername())
+ .setIssuedAt(now)
+ .setExpiration(expiry)
+ .signWith(getSignKey(), SignatureAlgorithm.HS512)
+ .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(getSignKey()).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(getSignKey())
+ .parseClaimsJws(token)
+ .getBody()
+ .getSubject();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/olympus/apollo/security/utility/JwtTokenProvider.java b/src/main/java/com/olympus/apollo/security/utility/JwtTokenProvider.java
deleted file mode 100644
index cb00594..0000000
--- a/src/main/java/com/olympus/apollo/security/utility/JwtTokenProvider.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.olympus.apollo.security.utility;
-
-import org.springframework.stereotype.Component;
-
-import io.jsonwebtoken.*;
-import io.jsonwebtoken.io.Decoders;
-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 static final String SECRET = "5367566B59703373367639792F423F4528482B4D6251655468576D5A713474375367566B59703373367639792F423F4528482B4D6251655468576D5A71347437";
-
-
- private Key getSignKey() {
- byte[] keyBytes = Decoders.BASE64.decode(SECRET);
- return Keys.hmacShaKeyFor(keyBytes);
- }
-
-
- 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(getSignKey(), SignatureAlgorithm.HS512)
- //.signWith(SignatureAlgorithm.HS512, SECRET)
- .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(getSignKey()).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(getSignKey())
- .parseClaimsJws(token)
- .getBody()
- .getSubject();
- }
-}
-
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 14bd3c8..b7b1e82 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -13,6 +13,11 @@ generic-file-parser-module:
spring:
application:
name: apollo
+ security:
+ oauth2:
+ resourceserver:
+ jwt:
+ issuer-uri: https://sts.windows.net/e0793d39-0939-496d-b129-198edd916feb/
ai:
azure:
openai: