Skip to content

Commit

Permalink
https://jira.fingo.info/browse/IJ-317 Prepare backend for no-auth (#199)
Browse files Browse the repository at this point in the history
Co-authored-by: Dawid Dudek <dawid.dudek@fingo.pl>
  • Loading branch information
DaDudek and Dawid Dudek authored Dec 27, 2022
1 parent 25e765f commit 41f0203
Show file tree
Hide file tree
Showing 18 changed files with 234 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@ConditionalOnProperty(name = "ad.configuration.enabled", havingValue = "true", matchIfMissing = true)
public class ActiveDirectorySynchronizationScheduler {
private static final Logger LOGGER = LoggerFactory.getLogger(ActiveDirectorySynchronizationScheduler.class);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package info.fingo.urlopia.api.v2.authentication.noauth;

import info.fingo.urlopia.api.v2.authentication.oauth.OAuthRedirectService;
import info.fingo.urlopia.api.v2.user.UserOutput;
import info.fingo.urlopia.config.authentication.UserData;
import info.fingo.urlopia.config.persistance.filter.Filter;
import info.fingo.urlopia.history.HistoryLogService;
import info.fingo.urlopia.user.UserExcerptProjection;
import info.fingo.urlopia.user.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import javax.annotation.security.RolesAllowed;
import java.util.List;

@RestController
@RequestMapping(value = "/api/v2/noauth/session")
@RequiredArgsConstructor
@ConditionalOnProperty(name = "ad.configuration.enabled", havingValue = "false")
public class NoAuthSessionController {

private final OAuthRedirectService oAuthRedirectService;
private final HistoryLogService historyLogService;
private final UserService userService;

@RolesAllowed({"ROLES_ADMIN", "ROLES_LEADER", "ROLES_WORKER"})
@GetMapping()
public UserData getUserData(Long userId) {
var userData = oAuthRedirectService.getUserData(userId);
var userEmploymentYear = historyLogService.getEmploymentYear(userData.getUserId());
userData.setEmploymentYear(userEmploymentYear);
return userData;
}

public List<UserOutput> getAll(Sort sort) {
var users = userService.get(Filter.empty(), sort);
return mapUserProjectionListToUserOutputList(users);
}

private List<UserOutput> mapUserProjectionListToUserOutputList(List<UserExcerptProjection> users){
return users.stream()
.map(UserOutput::fromUserExcerptProjection)
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package info.fingo.urlopia.api.v2.oauth;
package info.fingo.urlopia.api.v2.authentication.oauth;

import info.fingo.urlopia.config.authentication.UserData;
import info.fingo.urlopia.config.authentication.UserIdInterceptor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package info.fingo.urlopia.api.v2.oauth;
package info.fingo.urlopia.api.v2.authentication.oauth;

import info.fingo.urlopia.api.v2.user.UserRolesProvider;
import info.fingo.urlopia.config.authentication.TeamInfo;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package info.fingo.urlopia.config.authentication;

import org.springframework.web.filter.OncePerRequestFilter;

public interface AuthorizationFilterProvider {

OncePerRequestFilter getAuthorizationFilter();

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

private final JwtFilter jwtFilter;

private final Environment environment;
private final AuthorizationFilterProvider authorizationFilterProvider;

@Override
protected void configure(HttpSecurity http) throws Exception {
Expand Down Expand Up @@ -55,8 +54,9 @@ private void sessionConfiguration(HttpSecurity http) throws Exception {
}

private void filtersConfiguration(HttpSecurity http){
var authFilter = authorizationFilterProvider.getAuthorizationFilter();
http
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
.addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class);
}

private void exceptionHandlingConfiguration(HttpSecurity http) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package info.fingo.urlopia.config.authentication;

import info.fingo.urlopia.api.v2.user.UserRolesProvider;
import info.fingo.urlopia.user.User;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

@RequiredArgsConstructor
@Component
public class UserAuthoritiesProvider {

public static final String ROLE_PREFIX = "ROLE_";
private final UserRolesProvider userRolesProvider;

public Set<SimpleGrantedAuthority> getAuthoritiesFromUser(User user) {
var authorities = new HashSet<SimpleGrantedAuthority>();
var roles = userRolesProvider.getRolesFromUser(user);
roles.forEach(role -> addAuthorityFromRole(role, authorities));
return authorities;
}

private void addAuthorityFromRole(String role,
Set<SimpleGrantedAuthority> authorities){
var authority = role;
if (!role.startsWith(ROLE_PREFIX)){
authority = ROLE_PREFIX + role;
}
authorities.add(new SimpleGrantedAuthority(authority));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import info.fingo.urlopia.config.authentication.oauth.JwtTokenValidator;
import info.fingo.urlopia.user.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

Expand All @@ -11,6 +12,7 @@

@Component
@RequiredArgsConstructor
@ConditionalOnProperty(name = "ad.configuration.enabled", havingValue = "true", matchIfMissing = true)
public class UserIdInterceptor implements HandlerInterceptor {


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package info.fingo.urlopia.config.authentication.noauth;

import info.fingo.urlopia.config.authentication.UserAuthoritiesProvider;
import info.fingo.urlopia.config.authentication.UserIdInterceptor;
import info.fingo.urlopia.config.authentication.oauth.InvalidTokenException;
import info.fingo.urlopia.user.NoSuchUserException;
import info.fingo.urlopia.user.User;
import info.fingo.urlopia.user.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
@RequiredArgsConstructor
public class NoAuthFilter extends OncePerRequestFilter {

private final UserAuthoritiesProvider userAuthoritiesProvider;
private final UserService userService;

@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String header = request.getHeader(UserIdInterceptor.USER_ID_ATTRIBUTE);
if (header == null) {
filterChain.doFilter(request, response);
return;
}
var user = userService.get(Long.valueOf(header));
var authResult = getAuthenticationForUser(user, response);
if (authResult != null){
SecurityContextHolder.getContext().setAuthentication(authResult);
filterChain.doFilter(request, response);
}
}

private Authentication getAuthenticationForUser(User user,
HttpServletResponse response) {
try{
var principal = user.getPrincipalName();
var authorities = userAuthoritiesProvider.getAuthoritiesFromUser(user);
return new UsernamePasswordAuthenticationToken(principal, null, authorities);
}catch (InvalidTokenException | NoSuchUserException exception){
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package info.fingo.urlopia.config.authentication.noauth;

import info.fingo.urlopia.config.authentication.AuthorizationFilterProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

@Component
@RequiredArgsConstructor
@ConditionalOnProperty(name = "ad.configuration.enabled", havingValue = "false")
public class NoAuthFilterProvider implements AuthorizationFilterProvider {

private final NoAuthFilter noAuthFilter;

@Override
public OncePerRequestFilter getAuthorizationFilter() {
return noAuthFilter;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package info.fingo.urlopia.config.authentication.noauth;

import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@RequiredArgsConstructor
@ConditionalOnProperty(name = "ad.configuration.enabled", havingValue = "false")
public class NoAuthWebConfig implements WebMvcConfigurer {

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*");
}
}

Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package info.fingo.urlopia.config.authentication;
package info.fingo.urlopia.config.authentication.oauth;


import info.fingo.urlopia.api.v2.oauth.OAuthRedirectService;
import info.fingo.urlopia.config.authentication.oauth.InvalidTokenException;
import info.fingo.urlopia.config.authentication.oauth.JwtTokenValidator;
import info.fingo.urlopia.api.v2.authentication.oauth.OAuthRedirectService;
import info.fingo.urlopia.user.NoSuchUserException;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
Expand All @@ -20,6 +19,7 @@

@Component
@RequiredArgsConstructor
@ConditionalOnProperty(name = "ad.configuration.enabled", havingValue = "true", matchIfMissing = true)
public class JwtFilter extends OncePerRequestFilter {
private final JwtTokenValidator jwtTokenValidator;

Expand All @@ -32,7 +32,7 @@ protected void doFilterInternal(HttpServletRequest request,
chain.doFilter(request, response);
return;
}
Authentication authResult = getAuthenticationByToken(header, response);
var authResult = getAuthenticationByToken(header, response);
if (authResult != null){
SecurityContextHolder.getContext().setAuthentication(authResult);
chain.doFilter(request, response);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,23 @@
package info.fingo.urlopia.config.authentication.oauth;

import com.auth0.jwt.interfaces.DecodedJWT;
import info.fingo.urlopia.api.v2.user.UserRolesProvider;
import info.fingo.urlopia.user.User;
import info.fingo.urlopia.config.authentication.UserAuthoritiesProvider;
import info.fingo.urlopia.user.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

@RequiredArgsConstructor
@Component
public class JwtTokenAuthoritiesProvider {

public static final String ROLE_PREFIX = "ROLE_";

private final UserService userService;
private final UserRolesProvider userRolesProvider;
private final UserAuthoritiesProvider userAuthoritiesProvider;

public Set<SimpleGrantedAuthority> getAuthoritiesFromJWT(DecodedJWT decodedToken){
var principal = JwtUtils.getPrincipalNameFromDecodedToken(decodedToken);
var user = userService.getByPrincipal(principal);
return getAuthoritiesFromUser(user);
}

private Set<SimpleGrantedAuthority> getAuthoritiesFromUser(User user) {
var authorities = new HashSet<SimpleGrantedAuthority>();
var roles = userRolesProvider.getRolesFromUser(user);
roles.forEach(role -> addAuthorityFromRole(role, authorities));
return authorities;
}

private void addAuthorityFromRole(String role,
Set<SimpleGrantedAuthority> authorities){
var authority = role;
if (!role.startsWith(ROLE_PREFIX)){
authority = ROLE_PREFIX + role;
}
authorities.add(new SimpleGrantedAuthority(authority));
return userAuthoritiesProvider.getAuthoritiesFromUser(user);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.gson.JsonObject;
import info.fingo.urlopia.api.v2.oauth.OAuthRedirectService;
import info.fingo.urlopia.api.v2.authentication.oauth.OAuthRedirectService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package info.fingo.urlopia.config.authentication.oauth;

import info.fingo.urlopia.config.authentication.AuthorizationFilterProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

@Component
@RequiredArgsConstructor
@ConditionalOnProperty(name = "ad.configuration.enabled", havingValue = "true", matchIfMissing = true)
public class OAuthFilterProvider implements AuthorizationFilterProvider {

private final JwtFilter jwtFilter;

@Override
public OncePerRequestFilter getAuthorizationFilter() {
return jwtFilter;
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package info.fingo.urlopia.config.authentication;
package info.fingo.urlopia.config.authentication.oauth;

import info.fingo.urlopia.config.authentication.UserIdInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
@ConditionalOnProperty(name = "ad.configuration.enabled", havingValue = "true", matchIfMissing = true)
public class OAuthWebConfig implements WebMvcConfigurer {

private final UserIdInterceptor userIdInterceptor;
@Override
Expand Down
Loading

0 comments on commit 41f0203

Please sign in to comment.