Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.fungover.system2024.config;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.fungover.system2024.user.entity.User;
import org.springframework.context.annotation.Profile;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;

import java.io.IOException;

import static org.fungover.system2024.config.DevelopmentAuthenticationFilterService.createAuthentication;

@Component
@Profile("development")
public class DevelopmentAuthenticationFilter extends GenericFilterBean {
private final DevelopmentAuthenticationFilterService developmentAuthenticationFilterService;

public DevelopmentAuthenticationFilter(DevelopmentAuthenticationFilterService developmentAuthenticationFilterService) {
this.developmentAuthenticationFilterService = developmentAuthenticationFilterService;
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
User user = developmentAuthenticationFilterService.getUser();
OAuth2User oAuth2DevelopmentUser = developmentAuthenticationFilterService.createOAuth2User(user);
Authentication authentication = createAuthentication(oAuth2DevelopmentUser);

SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
} catch (RuntimeException exception) {
throw new ServletException(exception);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.fungover.system2024.config;

import org.fungover.system2024.user.entity.User;
import org.fungover.system2024.user.repository.UserRepository;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class DevelopmentAuthenticationFilterService {
private final UserRepository userRepository;

public DevelopmentAuthenticationFilterService(UserRepository userRepository) {
this.userRepository = userRepository;
}

public User getUser() {
return userRepository.findByEmail("Code653ht57t26234yp@example.com")
.orElseThrow(() -> new RuntimeException("Development user not found by email"));
}

public DefaultOAuth2User createOAuth2User(User user) {
Map<String, Object> attributes = new HashMap<>();
attributes.put("email", user.getEmail());

List<SimpleGrantedAuthority> authorities = List.of(
new SimpleGrantedAuthority("ROLE_USER")
);

return new DefaultOAuth2User(authorities, attributes, "email");
}

public static Authentication createAuthentication(OAuth2User oAuth2DevelopmentUser) {
return new UsernamePasswordAuthenticationToken(
oAuth2DevelopmentUser, "N/A", oAuth2DevelopmentUser.getAuthorities());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.fungover.system2024.config;

import org.fungover.system2024.user.entity.User;
import org.fungover.system2024.user.repository.UserRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@Profile("development")
public class DevelopmentUserInitialize {

@Value("${development.user.password}")
private String password;

@Bean
public CommandLineRunner initializeDevelopmentUser(UserRepository userRepository, PasswordEncoder passwordEncoder) {
return args -> {
String email = "Code653ht57t26234yp@example.com";

if (userRepository.findByEmail(email).isEmpty()) {
User user = new User();
user.setFirst_name("Junior");
user.setLast_name("Code653ht57t26234yp");
user.setEmail(email);
user.setPassword(passwordEncoder.encode(password));
userRepository.save(user);
}
};
}
}
15 changes: 15 additions & 0 deletions src/main/java/org/fungover/system2024/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,28 @@
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

private final DevelopmentAuthenticationFilter developmentAuthenticationFilter;

public SecurityConfig(DevelopmentAuthenticationFilter developmentAuthenticationFilter) {
this.developmentAuthenticationFilter = developmentAuthenticationFilter;
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
@Profile("development")
public SecurityFilterChain developmentSecurityFilterChain(HttpSecurity http) throws Exception {
Expand All @@ -23,6 +37,7 @@ public SecurityFilterChain developmentSecurityFilterChain(HttpSecurity http) thr
.authorizeHttpRequests(auth -> auth
.anyRequest().permitAll() // Allow all requests for development
)
.addFilterBefore(developmentAuthenticationFilter, BasicAuthenticationFilter.class)
.httpBasic(Customizer.withDefaults()); // Use HTTP Basic authentication for development
return http.build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package org.fungover.system2024.user.repository;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import org.fungover.system2024.user.entity.User;
import org.springframework.data.repository.ListCrudRepository;

import java.util.Optional;

public interface UserRepository extends ListCrudRepository<User, Integer> {
Optional<User> findByEmail(@NotBlank @Email String email);
}
1 change: 1 addition & 0 deletions src/main/resources/application-development.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
development.user.password=password
1 change: 1 addition & 0 deletions src/main/resources/graphql/schema.graphqls
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
type Query {
users: [User]
testUserAuth: String
}

type User {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package org.fungover.system2024.config;

import org.fungover.system2024.user.entity.User;
import org.fungover.system2024.user.repository.UserRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2User;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class DevelopmentAuthenticationFilterServiceTest {
@Mock
private UserRepository userRepository;

private DevelopmentAuthenticationFilterService developmentAuthenticationFilterService;

@BeforeEach
void setUp() {
developmentAuthenticationFilterService = new DevelopmentAuthenticationFilterService(userRepository);
}

@Test
void testGetUser() {
User user = new User();
user.setEmail("development@example.com");

when(userRepository.findByEmail("development@example.com"))
.thenReturn(Optional.of(user));

User validUser = developmentAuthenticationFilterService.getUser();

assertNotNull(validUser);
assertEquals("development@example.com", validUser.getEmail());
}

@Test
void testGetUserNotFound() {
when(userRepository.findByEmail("development@example.com"))
.thenReturn(Optional.empty());

RuntimeException runtimeException = assertThrows(RuntimeException.class, ()
-> developmentAuthenticationFilterService.getUser());

assertEquals("Development user not found by email", runtimeException.getMessage());
}

@Test
void testCreateOAut2User() {
User user = new User();
user.setEmail("development@example.com");

DefaultOAuth2User oAuth2User = developmentAuthenticationFilterService.createOAuth2User(user);
List<String> authorities = oAuth2User.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.toList();

assertNotNull(oAuth2User);
assertEquals("development@example.com", oAuth2User.getAttributes().get("email"));
assertTrue(authorities.contains("ROLE_USER"));
}

@Test
void testCreateAuthentication() {
Map<String, Object> attributes = Map.of("email", "development@example.com");
List<GrantedAuthority> authorities = List.of(new SimpleGrantedAuthority("ROLE_USER"));
OAuth2User oAuth2User = new DefaultOAuth2User(authorities, attributes, "email");

Authentication authentication = DevelopmentAuthenticationFilterService.createAuthentication(oAuth2User);

assertNotNull(authentication);
assertEquals(authorities, authentication.getAuthorities());
assertEquals(oAuth2User, authentication.getPrincipal());
assertEquals("development@example.com", authentication.getName());
assertEquals("N/A", authentication.getCredentials().toString());
assertInstanceOf(UsernamePasswordAuthenticationToken.class, authentication);
}

@Test
void testCreateAuthenticationNoAuthorities() {
Map<String, Object> attributes = Map.of("email", "development@example.com");
List<GrantedAuthority> authorities = Collections.emptyList();
OAuth2User oAuth2User = new DefaultOAuth2User(authorities, attributes, "email");

Authentication authentication = DevelopmentAuthenticationFilterService.createAuthentication(oAuth2User);

assertNotNull(authentication);
assertEquals(oAuth2User, authentication.getPrincipal());
assertTrue(authentication.getAuthorities().isEmpty());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.fungover.system2024.config;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.testcontainers.containers.MySQLContainer;

import static org.junit.jupiter.api.Assertions.assertTrue;

import org.springframework.http.MediaType;

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("development")
class DevelopmentAuthenticationFilterSpringBootTest {
static MySQLContainer<?> mysqlContainer = new MySQLContainer<>("mysql:9.1")
.withDatabaseName("system24dbtest")
.withUsername("myuser")
.withPassword("secret");

static {
mysqlContainer.start();
}

@DynamicPropertySource
static void setProperties(DynamicPropertyRegistry propertyRegistry) {
propertyRegistry.add("spring.datasource.url", mysqlContainer::getJdbcUrl);
propertyRegistry.add("spring.datasource.username", mysqlContainer::getUsername);
propertyRegistry.add("spring.datasource.password", mysqlContainer::getPassword);
propertyRegistry.add("spring.jpa.hibernate.ddl-auto", () -> "create-drop");
}

@Autowired
MockMvc mockMvc;

@Test
void testDevelopmentAuthenticationFilter() throws Exception {
String request = "{\"query\": \"{testUserAuth}\"}";

MvcResult result = mockMvc.perform(post("/graphql").with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(request))
.andExpect(status().isOk())
.andReturn();

assertTrue(result.getResponse().getContentAsString().contains("Code653ht57t26234yp@example.com"));
}
}
Loading
Loading