Skip to content

Commit

Permalink
api-key auth
Browse files Browse the repository at this point in the history
  • Loading branch information
siewer committed Dec 12, 2024
1 parent 894d3ea commit 7cb71ad
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.security.SignatureException;
import io.mixeway.mixewayflowapi.auth.UserDetailsServiceImpl;
import io.mixeway.mixewayflowapi.db.entity.UserInfo;
import io.mixeway.mixewayflowapi.domain.user.FindUserService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
Expand All @@ -23,6 +25,7 @@
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Optional;

@Component
@RequiredArgsConstructor
Expand All @@ -31,11 +34,49 @@ public class JwtAuthFilter extends OncePerRequestFilter {

private final JwtService jwtService;
private final UserDetailsServiceImpl userDetailsServiceImpl;
private final FindUserService findUserService; // Add this so we can look up user by API key

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {

log.debug("JwtAuthFilter: Processing request " + request.getRequestURI());

Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
if (existingAuth != null && existingAuth.isAuthenticated()) {
filterChain.doFilter(request, response);
return; // Already authenticated
}

// 1. Check if API key header is present
String apiKey = request.getHeader("X-API-KEY");
if (apiKey != null && !apiKey.isBlank()) {
log.debug("Attempting API key authentication");
Optional<UserInfo> userInfo = findUserService.findByApiKey(apiKey);
if (userInfo.isPresent()) {
// Validate user's roles and details
UserDetails userDetails = userDetailsServiceImpl.loadUserByUsername(userInfo.get().getUsername());
// Create an authentication token
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// Set authentication context
SecurityContextHolder.getContext().setAuthentication(authenticationToken);

log.debug("API key authentication successful for user: " + userInfo.get().getUsername());
filterChain.doFilter(request, response);
return;
} else {
log.warn("Invalid API key provided");
// If invalid, we do not stop the chain here necessarily. You can choose to reject immediately or let
// the request continue and be rejected by other mechanisms.
// For security, you may want to set a response and return here:
// response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid API Key");
// return;
}
}

// 2. If no API key authentication, proceed with JWT authentication as before
String token = null;
String username = null;

Expand Down Expand Up @@ -67,17 +108,18 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
}
}

// Authenticate the user
// Authenticate the user via JWT
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
try {
UserDetails userDetails = userDetailsServiceImpl.loadUserByUsername(username);
if (jwtService.validateToken(token, userDetails)) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
} catch (UsernameNotFoundException e){
log.error("[Auth] {}",e.getLocalizedMessage());
} catch (UsernameNotFoundException e) {
log.error("[Auth] {}", e.getLocalizedMessage());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class UserInfo {
@Size(min = 8, message = "Password must be at least 8 characters long")
private String password;


@ManyToMany(fetch = FetchType.EAGER)
private final Set<UserRole> roles = new HashSet<>();

Expand All @@ -42,6 +43,7 @@ public class UserInfo {
)
private final Set<Team> teams = new HashSet<>();

@JsonIgnore
@Column(name = "api_key")
private String apiKey;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface UserRepository extends CrudRepository<UserInfo, Long> {
Expand All @@ -15,4 +16,6 @@ public interface UserRepository extends CrudRepository<UserInfo, Long> {

@Query("SELECT u FROM UserInfo u JOIN u.teams t WHERE t.id = :teamId")
List<UserInfo> getUsersByTeamId(@Param("teamId") Long teamId);

Optional<UserInfo> findByApiKey(String apiKey);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ public UserInfo findUser(String username){
}
public List<UserInfo> findAll(){ return userRepository.findAll();}
public Optional<UserInfo> findById(Long id) { return userRepository.findById(id);}
public Optional<UserInfo> findByApiKey(String apiKey) { return userRepository.findByApiKey(apiKey);}
}

0 comments on commit 7cb71ad

Please sign in to comment.