Skip to content

Commit 94a0378

Browse files
NFC-47 Pass mobile login path via constructor. Delete MobileAuthInitResponse.java. Remove unnecessary /error permitAll. Rename JSON constant to OBJECT_WRITER and other strings to constant. Inline ChallengeDTO.
1 parent c2c8aa6 commit 94a0378

File tree

10 files changed

+50
-82
lines changed

10 files changed

+50
-82
lines changed

example/src/main/java/eu/webeid/example/config/ApplicationConfiguration.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import eu.webeid.example.security.WebEidMobileAuthInitFilter;
2929
import eu.webeid.example.security.ui.WebEidLoginPageGeneratingFilter;
3030
import eu.webeid.security.challenge.ChallengeNonceGenerator;
31-
import eu.webeid.security.challenge.ChallengeNonceStore;
3231
import org.springframework.context.annotation.Bean;
3332
import org.springframework.context.annotation.Configuration;
3433
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
@@ -53,12 +52,12 @@ public SecurityFilterChain filterChain(
5352
return http
5453
.authorizeHttpRequests(auth -> auth
5554
.requestMatchers("/css/**", "/files/**", "/img/**", "/js/**", "/scripts/**").permitAll()
56-
.requestMatchers("/", "/error").permitAll()
55+
.requestMatchers("/").permitAll()
5756
.requestMatchers("/welcome").hasRole("USER")
5857
.anyRequest().authenticated()
5958
)
6059
.authenticationProvider(authTokenDTOAuthenticationProvider)
61-
.addFilterBefore(new WebEidMobileAuthInitFilter("/auth/mobile/auth/init", challengeNonceGenerator), UsernamePasswordAuthenticationFilter.class)
60+
.addFilterBefore(new WebEidMobileAuthInitFilter("/auth/mobile/init", "/auth/mobile/login", challengeNonceGenerator), UsernamePasswordAuthenticationFilter.class)
6261
.addFilterBefore(new WebEidChallengeNonceFilter("/auth/challenge", challengeNonceGenerator), UsernamePasswordAuthenticationFilter.class)
6362
.addFilterBefore(new WebEidLoginPageGeneratingFilter("/auth/mobile/login"), UsernamePasswordAuthenticationFilter.class)
6463
.addFilterBefore(new WebEidAjaxLoginProcessingFilter("/auth/login", authConfig.getAuthenticationManager()), UsernamePasswordAuthenticationFilter.class)

example/src/main/java/eu/webeid/example/security/WebEidAjaxLoginProcessingFilter.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333
import jakarta.servlet.http.HttpServletResponse;
3434
import org.slf4j.Logger;
3535
import org.slf4j.LoggerFactory;
36+
import org.springframework.http.HttpHeaders;
3637
import org.springframework.http.HttpMethod;
38+
import org.springframework.http.MediaType;
3739
import org.springframework.security.authentication.AuthenticationManager;
3840
import org.springframework.security.authentication.AuthenticationServiceException;
3941
import org.springframework.security.core.Authentication;
@@ -68,8 +70,8 @@ public WebEidAjaxLoginProcessingFilter(
6870
@Override
6971
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
7072
throws AuthenticationException, IOException {
71-
final String contentType = request.getHeader("Content-type");
72-
if (contentType == null || !contentType.startsWith("application/json")) {
73+
final String contentType = request.getHeader(HttpHeaders.CONTENT_TYPE);
74+
if (contentType == null || !contentType.startsWith(MediaType.APPLICATION_JSON_VALUE)) {
7375
LOG.warn("Content type not supported: {}", contentType);
7476
throw new AuthenticationServiceException("Content type not supported: " + contentType);
7577
}

example/src/main/java/eu/webeid/example/security/WebEidChallengeNonceFilter.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,36 @@
1-
1+
/*
2+
* Copyright (c) 2020-2025 Estonian Information System Authority
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
222

323
package eu.webeid.example.security;
424

525
import com.fasterxml.jackson.databind.ObjectMapper;
626
import com.fasterxml.jackson.databind.ObjectWriter;
7-
import eu.webeid.example.service.dto.ChallengeDTO;
827
import eu.webeid.security.challenge.ChallengeNonceGenerator;
928
import jakarta.servlet.FilterChain;
1029
import jakarta.servlet.ServletException;
1130
import jakarta.servlet.http.HttpServletRequest;
1231
import jakarta.servlet.http.HttpServletResponse;
1332
import org.springframework.http.HttpMethod;
33+
import org.springframework.http.MediaType;
1434
import org.springframework.lang.NonNull;
1535
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
1636
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -19,9 +39,8 @@
1939
import java.io.IOException;
2040

2141
public final class WebEidChallengeNonceFilter extends OncePerRequestFilter {
22-
private static final ObjectWriter JSON = new ObjectMapper().writer();
42+
private static final ObjectWriter OBJECT_WRITER = new ObjectMapper().writer();
2343
private final RequestMatcher requestMatcher;
24-
2544
private final ChallengeNonceGenerator nonceGenerator;
2645

2746
public WebEidChallengeNonceFilter(String path, ChallengeNonceGenerator nonceGenerator) {
@@ -38,10 +57,11 @@ protected void doFilterInternal(@NonNull HttpServletRequest request,
3857
return;
3958
}
4059

41-
var dto = new ChallengeDTO();
42-
dto.setNonce(nonceGenerator.generateAndStoreNonce().getBase64EncodedNonce());
60+
var dto = new ChallengeDTO(nonceGenerator.generateAndStoreNonce().getBase64EncodedNonce());
4361

44-
response.setContentType("application/json");
45-
JSON.writeValue(response.getWriter(), dto);
62+
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
63+
OBJECT_WRITER.writeValue(response.getWriter(), dto);
4664
}
65+
66+
public record ChallengeDTO(String nonce) {}
4767
}

example/src/main/java/eu/webeid/example/security/WebEidMobileAuthInitFilter.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import jakarta.servlet.http.HttpServletRequest;
3030
import jakarta.servlet.http.HttpServletResponse;
3131
import org.springframework.http.HttpMethod;
32+
import org.springframework.http.MediaType;
3233
import org.springframework.lang.NonNull;
3334
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
3435
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -43,12 +44,13 @@
4344
public final class WebEidMobileAuthInitFilter extends OncePerRequestFilter {
4445
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
4546
private final RequestMatcher requestMatcher;
46-
4747
private final ChallengeNonceGenerator nonceGenerator;
48+
private final String loginPath;
4849

49-
public WebEidMobileAuthInitFilter(String path, ChallengeNonceGenerator nonceGenerator) {
50+
public WebEidMobileAuthInitFilter(String path, String loginPath, ChallengeNonceGenerator nonceGenerator) {
5051
this.requestMatcher = PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, path);
5152
this.nonceGenerator = nonceGenerator;
53+
this.loginPath = loginPath;
5254
}
5355

5456
@Override
@@ -63,7 +65,7 @@ protected void doFilterInternal(@NonNull HttpServletRequest request,
6365
var challenge = nonceGenerator.generateAndStoreNonce();
6466

6567
String loginUri = ServletUriComponentsBuilder.fromCurrentContextPath()
66-
.path("/auth/eid/login").build().toUriString();
68+
.path(loginPath).build().toUriString();
6769

6870
String payloadJson = OBJECT_MAPPER.writeValueAsString(Map.of(
6971
"challenge", challenge.getBase64EncodedNonce(),
@@ -72,7 +74,7 @@ protected void doFilterInternal(@NonNull HttpServletRequest request,
7274
String encoded = Base64.getEncoder().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));
7375
String eidAuthUri = "web-eid-mobile://auth#" + encoded;
7476

75-
response.setContentType("application/json");
77+
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
7678
OBJECT_MAPPER.writeValue(response.getWriter(), Map.of("auth_uri", eidAuthUri));
7779
}
7880
}

example/src/main/java/eu/webeid/example/security/ajax/AjaxAuthenticationSuccessHandler.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import jakarta.servlet.http.HttpServletResponse;
3131
import org.slf4j.Logger;
3232
import org.slf4j.LoggerFactory;
33+
import org.springframework.http.HttpHeaders;
34+
import org.springframework.http.MediaType;
3335
import org.springframework.security.core.Authentication;
3436
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
3537
import org.springframework.stereotype.Component;
@@ -56,7 +58,7 @@ public void onAuthenticationSuccess(
5658
LOG.info("onAuthenticationSuccess(): {}", authentication);
5759

5860
response.setStatus(HttpServletResponse.SC_OK);
59-
response.setHeader("Content-Type", "application/json; charset=utf-8");
61+
response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8");
6062

6163
response.getWriter().write(AuthSuccessDTO.asJson(authentication));
6264
}

example/src/main/java/eu/webeid/example/security/ui/WebEidLoginPageGeneratingFilter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import jakarta.servlet.http.HttpServletRequest;
2828
import jakarta.servlet.http.HttpServletResponse;
2929
import org.springframework.http.HttpMethod;
30+
import org.springframework.http.MediaType;
3031
import org.springframework.lang.NonNull;
3132
import org.springframework.security.web.csrf.CsrfToken;
3233
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
@@ -106,7 +107,7 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull Ht
106107
csrf != null ? csrf.getHeaderName() : "X-CSRF-TOKEN"
107108
);
108109

109-
response.setContentType("text/html;charset=UTF-8");
110+
response.setContentType(MediaType.TEXT_HTML_VALUE + ";charset=UTF-8");
110111
response.getWriter().write(html);
111112
}
112113

example/src/main/java/eu/webeid/example/service/dto/ChallengeDTO.java

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

example/src/main/java/eu/webeid/example/service/dto/MobileAuthInitResponse.java

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

example/src/main/resources/templates/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ <h3><a id="for-developers"></a>For developers</h3>
265265

266266
try {
267267
if (isMobileDevice()) {
268-
const resp = await fetch("/auth/mobile/auth/init", {
268+
const resp = await fetch("/auth/mobile/init", {
269269
method: "POST",
270270
headers: {
271271
"Content-Type": "application/json",

example/src/test/java/eu/webeid/example/security/WebEidAjaxLoginProcessingFilterTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
import jakarta.servlet.http.HttpServletRequest;
2727
import jakarta.servlet.http.HttpServletResponse;
2828
import org.junit.jupiter.api.Test;
29+
import org.springframework.http.HttpHeaders;
2930
import org.springframework.http.HttpMethod;
31+
import org.springframework.http.MediaType;
3032
import org.springframework.security.authentication.AuthenticationManager;
3133

3234
import java.io.BufferedReader;
@@ -51,7 +53,7 @@ void testAttemptAuthentication() throws Exception {
5153
final HttpServletRequest request = mock(HttpServletRequest.class);
5254
final HttpServletResponse response = mock(HttpServletResponse.class);
5355
when(request.getMethod()).thenReturn(HttpMethod.POST.name());
54-
when(request.getHeader("Content-type")).thenReturn("application/json");
56+
when(request.getHeader(HttpHeaders.CONTENT_TYPE)).thenReturn(MediaType.APPLICATION_JSON_VALUE);
5557
when(request.getReader()).thenReturn(new BufferedReader(new StringReader(AUTH_TOKEN)));
5658

5759
final AuthenticationManager authenticationManager = mock(AuthenticationManager.class);
@@ -66,7 +68,7 @@ void testAttemptAuthentication_V11AuthToken() throws Exception {
6668
final HttpServletRequest request = mock(HttpServletRequest.class);
6769
final HttpServletResponse response = mock(HttpServletResponse.class);
6870
when(request.getMethod()).thenReturn(HttpMethod.POST.name());
69-
when(request.getHeader("Content-type")).thenReturn("application/json");
71+
when(request.getHeader(HttpHeaders.CONTENT_TYPE)).thenReturn(MediaType.APPLICATION_JSON_VALUE);
7072

7173
var jsonBody = ObjectMother.toJson(Map.of("auth-token", ObjectMother.mockV11AuthToken().getToken()));
7274

0 commit comments

Comments
 (0)