Skip to content

Commit b302fac

Browse files
authored
Merge pull request #11 from maximwlt/feature/refactoring
Feature/refactoring into main
2 parents 068bd04 + cea2b4f commit b302fac

86 files changed

Lines changed: 1567 additions & 1288 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/github-actions-demo.yml

Lines changed: 0 additions & 18 deletions
This file was deleted.

projekt/backend/pom.xml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>org.springframework.boot</groupId>
77
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>4.0.0</version>
8+
<version>4.0.4</version>
99
<relativePath/> <!-- lookup parent from repository -->
1010
</parent>
1111
<groupId>com.projektSSE</groupId>
@@ -41,7 +41,7 @@
4141
<dependency>
4242
<groupId>org.springframework.security</groupId>
4343
<artifactId>spring-security-crypto</artifactId>
44-
<version>7.0.0</version>
44+
<version>7.0.4</version>
4545
</dependency>
4646
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
4747
<dependency>
@@ -81,14 +81,12 @@
8181
<dependency>
8282
<groupId>org.springframework.boot</groupId>
8383
<artifactId>spring-boot-starter-mail</artifactId>
84-
<version>4.0.1</version>
8584
</dependency>
8685
<!-- Test Dependencies -->
8786
<!-- Source: https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-resttestclient -->
8887
<dependency>
8988
<groupId>org.springframework.boot</groupId>
9089
<artifactId>spring-boot-resttestclient</artifactId>
91-
<version>4.0.0</version>
9290
<scope>test</scope>
9391
</dependency>
9492
<dependency>
@@ -100,15 +98,15 @@
10098
<dependency>
10199
<groupId>org.mockito</groupId>
102100
<artifactId>mockito-core</artifactId>
103-
<version>5.22.0</version>
101+
<version>5.23.0</version>
104102
<scope>test</scope>
105103
</dependency>
106104
<!-- Logging Dependencies -->
107105
<!-- Source: https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
108106
<dependency>
109107
<groupId>org.slf4j</groupId>
110108
<artifactId>slf4j-api</artifactId>
111-
<version>2.1.0-alpha1</version>
109+
<version>2.0.17</version>
112110
<scope>compile</scope>
113111
</dependency>
114112
<!-- Devtools Dependencies -->
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.projektsse.backend.config;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
import jakarta.servlet.http.HttpServletResponse;
5+
import org.jspecify.annotations.NonNull;
6+
import org.springframework.http.HttpStatus;
7+
import org.springframework.http.MediaType;
8+
import org.springframework.http.ProblemDetail;
9+
import org.springframework.security.access.AccessDeniedException;
10+
import org.springframework.security.web.access.AccessDeniedHandler;
11+
import org.springframework.stereotype.Component;
12+
import tools.jackson.databind.ObjectMapper;
13+
14+
import java.io.IOException;
15+
import java.net.URI;
16+
17+
@Component
18+
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
19+
20+
private final ObjectMapper objectMapper;
21+
22+
public CustomAccessDeniedHandler(ObjectMapper objectMapper) {
23+
this.objectMapper = objectMapper;
24+
}
25+
26+
@Override
27+
public void handle(@NonNull HttpServletRequest request,
28+
@NonNull HttpServletResponse response,
29+
@NonNull AccessDeniedException accessDeniedException) throws IOException {
30+
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.FORBIDDEN, "Forbidden");
31+
problemDetail.setDetail("You do not have permission to access this resource.");
32+
problemDetail.setInstance(URI.create(request.getRequestURI()));
33+
34+
response.setStatus(HttpStatus.FORBIDDEN.value());
35+
response.setContentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE);
36+
objectMapper.writeValue(response.getWriter(), problemDetail);
37+
}
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.projektsse.backend.config;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
import jakarta.servlet.http.HttpServletResponse;
5+
import org.jspecify.annotations.NonNull;
6+
import org.springframework.http.HttpStatus;
7+
import org.springframework.http.MediaType;
8+
import org.springframework.http.ProblemDetail;
9+
import org.springframework.security.core.AuthenticationException;
10+
import org.springframework.security.web.AuthenticationEntryPoint;
11+
import org.springframework.stereotype.Component;
12+
import tools.jackson.databind.ObjectMapper;
13+
14+
import java.io.IOException;
15+
import java.net.URI;
16+
17+
@Component
18+
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
19+
private final ObjectMapper objectMapper;
20+
21+
public CustomAuthenticationEntryPoint(ObjectMapper objectMapper) {
22+
this.objectMapper = objectMapper;
23+
}
24+
25+
26+
@Override
27+
public void commence(@NonNull HttpServletRequest request,
28+
@NonNull HttpServletResponse response,
29+
@NonNull AuthenticationException authException) throws IOException {
30+
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.UNAUTHORIZED, "Unauthorized");
31+
problemDetail.setDetail("Authentication is required to access this resource.");
32+
problemDetail.setInstance(URI.create(request.getRequestURI()));
33+
34+
response.setStatus(HttpStatus.UNAUTHORIZED.value());
35+
response.setContentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE);
36+
objectMapper.writeValue(response.getWriter(), problemDetail);
37+
}
38+
}

projekt/backend/src/main/java/com/projektsse/backend/config/JwtFilter.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package com.projektsse.backend.config;
22

33
import com.projektsse.backend.service.JwtService;
4+
import jakarta.annotation.PostConstruct;
45
import jakarta.servlet.FilterChain;
56
import jakarta.servlet.ServletException;
67
import jakarta.servlet.http.Cookie;
78
import jakarta.servlet.http.HttpServletRequest;
89
import jakarta.servlet.http.HttpServletResponse;
910
import org.jspecify.annotations.NonNull;
11+
import org.springframework.beans.factory.annotation.Value;
1012
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
1113
import org.springframework.security.core.context.SecurityContextHolder;
1214
import org.springframework.security.core.userdetails.UserDetails;
@@ -21,7 +23,9 @@
2123
@Component
2224
public class JwtFilter extends OncePerRequestFilter {
2325

24-
private static final String FINGERPRINT_COOKIE_NAME = "__Secure-Fgp";
26+
@Value("${app.cookie.secure}")
27+
private boolean cookieSecure;
28+
private String FINGERPRINT_COOKIE_NAME;
2529

2630
private final JwtService jwtService;
2731
private final UserDetailsService userDetailsService;
@@ -31,6 +35,11 @@ public JwtFilter(JwtService jwtService, UserDetailsService userDetailsService) {
3135
this.userDetailsService = userDetailsService;
3236
}
3337

38+
@PostConstruct
39+
public void init() {
40+
FINGERPRINT_COOKIE_NAME = cookieSecure ? "__Secure-Fgp" : "Fgp";
41+
}
42+
3443
@Override
3544
protected void doFilterInternal(
3645
HttpServletRequest request,
@@ -99,6 +108,11 @@ protected boolean shouldNotFilter(HttpServletRequest request) {
99108
return path.startsWith("/api/auth/register") ||
100109
path.startsWith("/api/auth/login") ||
101110
path.startsWith("/api/auth/verify-email") ||
102-
path.startsWith("/api/documents/public");
111+
path.startsWith("/api/documents/public") ||
112+
path.startsWith("/api/auth/rt/refresh-token") ||
113+
path.startsWith("/api/auth/rt/logout") ||
114+
path.startsWith("/api/auth/forgot-password") ||
115+
path.startsWith("/api/auth/reset-password") ||
116+
path.startsWith("/api/auth/csrf");
103117
}
104118
}

projekt/backend/src/main/java/com/projektsse/backend/config/SecurityBeansConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public AuthenticationProvider authenticationProvider(
2727
public PasswordEncoder passwordEncoder() {
2828
// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id
2929
// Configurations taken from OWASP recommendations
30+
3031
return new Argon2PasswordEncoder(
3132
16, // Salt length
3233
32, // Hash length

projekt/backend/src/main/java/com/projektsse/backend/config/SecurityConfig.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.projektsse.backend.config;
22

3-
import jakarta.servlet.http.HttpServletResponse;
3+
import org.springframework.beans.factory.annotation.Value;
44
import org.springframework.context.annotation.Bean;
55
import org.springframework.context.annotation.Configuration;
66
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -15,17 +15,28 @@
1515
@EnableWebSecurity
1616
public class SecurityConfig {
1717

18+
@Value("${app.cookie.secure}")
19+
private boolean cookieSecure;
20+
1821
private final JwtFilter jwtFilter;
1922

20-
SecurityConfig(JwtFilter jwtFilter) {
23+
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
24+
private final CustomAccessDeniedHandler customAccessDeniedHandler;
25+
26+
SecurityConfig(JwtFilter jwtFilter,
27+
CustomAuthenticationEntryPoint customAuthenticationEntryPoint,
28+
CustomAccessDeniedHandler customAccessDeniedHandler
29+
) {
2130
this.jwtFilter = jwtFilter;
31+
this.customAuthenticationEntryPoint = customAuthenticationEntryPoint;
32+
this.customAccessDeniedHandler = customAccessDeniedHandler;
2233
}
2334

2435
@Bean
2536
public SecurityFilterChain securityFilterChain(HttpSecurity http) {
2637
CookieCsrfTokenRepository repo = CookieCsrfTokenRepository.withHttpOnlyFalse();
2738
repo.setCookieCustomizer(cookie -> {
28-
cookie.secure(true);
39+
cookie.secure(cookieSecure);
2940
cookie.sameSite("Strict");
3041
cookie.path("/");
3142
});
@@ -38,6 +49,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) {
3849
"/api/auth/register",
3950
"/api/auth/verify-email",
4051
"/api/documents/public",
52+
"/api/documents/{docId}",
53+
"/api/documents",
4154
"/api/documents/public/search",
4255
"/api/auth/forgot-password",
4356
"/api/auth/reset-password"
@@ -49,8 +62,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) {
4962
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
5063
)
5164
.exceptionHandling(ex -> ex
52-
.authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"))
53-
.accessDeniedHandler((request, response, accessDeniedException) -> response.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden"))
65+
.authenticationEntryPoint(customAuthenticationEntryPoint)
66+
.accessDeniedHandler(customAccessDeniedHandler)
5467
)
5568
.authorizeHttpRequests(auth -> auth
5669
.requestMatchers(
@@ -62,7 +75,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) {
6275
"/api/auth/rt/refresh-token",
6376
"/api/auth/rt/logout",
6477
"/api/auth/forgot-password",
65-
"/api/auth/reset-password"
78+
"/api/auth/reset-password",
79+
"/api/auth/csrf"
6680
).permitAll().anyRequest().authenticated()
6781
)
6882
.formLogin(AbstractHttpConfigurer::disable)

0 commit comments

Comments
 (0)