Skip to content

Commit 7c1f2a5

Browse files
NFC-47 Path to static resources clearer. Remove filter paths permit. WebEidChallengeNonceFilter to post. Index js method to POST with csrf. Remove @secured and @EnableMethodSecurity. Remove WebMvcConfigurer and view controllers from ApplicationConfiguration. Return auth_uri as JSON map. Constant name to OBJECT_MAPPER. Remove unnecessary shouldNotFilterAsyncDispatch override. Inline CSRF token and header directly in login page script. Show mobileAuthError message on login page.
1 parent bcedbe2 commit 7c1f2a5

File tree

6 files changed

+26
-67
lines changed

6 files changed

+26
-67
lines changed

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

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,10 @@
2929
import eu.webeid.example.security.ui.WebEidLoginPageGeneratingFilter;
3030
import eu.webeid.security.challenge.ChallengeNonceGenerator;
3131
import eu.webeid.security.challenge.ChallengeNonceStore;
32-
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
3332
import org.springframework.context.annotation.Bean;
3433
import org.springframework.context.annotation.Configuration;
3534
import org.springframework.http.HttpMethod;
3635
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
37-
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
3836
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
3937
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
4038
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
@@ -43,13 +41,10 @@
4341
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
4442
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
4543
import org.springframework.security.web.csrf.CsrfFilter;
46-
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
47-
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
4844

4945
@Configuration
5046
@EnableWebSecurity
51-
@EnableMethodSecurity(securedEnabled = true)
52-
public class ApplicationConfiguration implements WebMvcConfigurer {
47+
public class ApplicationConfiguration {
5348

5449
@Bean
5550
public SecurityFilterChain filterChain(HttpSecurity http, AuthTokenDTOAuthenticationProvider authTokenDTOAuthenticationProvider, AuthenticationConfiguration authConfig, ChallengeNonceGenerator challengeNonceGenerator, ChallengeNonceStore challengeNonceStore) throws Exception {
@@ -58,14 +53,12 @@ public SecurityFilterChain filterChain(HttpSecurity http, AuthTokenDTOAuthentica
5853

5954
return http
6055
.authorizeHttpRequests(auth -> auth
61-
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
56+
.requestMatchers("/css/**", "/js/**", "/images/**", "/webjars/**", "/favicon.*", "/icon-*").permitAll()
6257
.requestMatchers("/", "/error").permitAll()
6358
.requestMatchers(HttpMethod.GET, "/auth/eid/login").permitAll()
64-
.requestMatchers("/auth/challenge").permitAll()
65-
.requestMatchers(HttpMethod.POST, "/auth/mobile/auth/init").permitAll()
6659
.requestMatchers("/auth/login").permitAll()
6760
.requestMatchers("/welcome").hasRole("USER")
68-
.anyRequest().permitAll()
61+
.anyRequest().authenticated()
6962
)
7063
.authenticationProvider(authTokenDTOAuthenticationProvider)
7164
.addFilterBefore(new WebEidLoginPageGeneratingFilter(), UsernamePasswordAuthenticationFilter.class)
@@ -76,10 +69,4 @@ public SecurityFilterChain filterChain(HttpSecurity http, AuthTokenDTOAuthentica
7669
.logout(l -> l.logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler()))
7770
.build();
7871
}
79-
80-
@Override
81-
public void addViewControllers(ViewControllerRegistry registry) {
82-
registry.addViewController("/").setViewName("index");
83-
registry.addViewController("/welcome").setViewName("welcome");
84-
}
8572
}

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

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,4 @@
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-
*/
1+
222

233
package eu.webeid.example.security;
244

@@ -42,7 +22,7 @@ public final class WebEidChallengeNonceFilter extends OncePerRequestFilter {
4222

4323
private static final ObjectWriter JSON = new ObjectMapper().writer();
4424
private final RequestMatcher matcher =
45-
PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/auth/challenge");
25+
PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/auth/challenge");
4626

4727
private final ChallengeNonceGenerator nonceGenerator;
4828

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

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
package eu.webeid.example.security;
2424

2525
import com.fasterxml.jackson.databind.ObjectMapper;
26-
import eu.webeid.example.service.dto.MobileAuthInitResponse;
2726
import eu.webeid.security.challenge.ChallengeNonceGenerator;
2827
import eu.webeid.security.challenge.ChallengeNonceStore;
2928
import jakarta.servlet.FilterChain;
@@ -43,9 +42,9 @@
4342
import java.util.Map;
4443

4544
public final class WebEidMobileAuthInitFilter extends OncePerRequestFilter {
46-
private static final ObjectMapper MAPPER = new ObjectMapper();
45+
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
4746
private final RequestMatcher matcher =
48-
PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/auth/mobile/auth/init");
47+
PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/auth/mobile/auth/init");
4948

5049
private final ChallengeNonceGenerator nonceGenerator;
5150
private final ChallengeNonceStore challengeNonceStore;
@@ -69,21 +68,16 @@ protected void doFilterInternal(@NonNull HttpServletRequest request,
6968
challengeNonceStore.put(challenge);
7069

7170
String loginUri = ServletUriComponentsBuilder.fromCurrentContextPath()
72-
.path("/auth/eid/login").build().toUriString();
71+
.path("/auth/eid/login").build().toUriString();
7372

74-
String payloadJson = MAPPER.writeValueAsString(Map.of(
75-
"challenge", challenge.getBase64EncodedNonce(),
76-
"login_uri", loginUri
73+
String payloadJson = OBJECT_MAPPER.writeValueAsString(Map.of(
74+
"challenge", challenge.getBase64EncodedNonce(),
75+
"login_uri", loginUri
7776
));
7877
String encoded = Base64.getEncoder().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));
7978
String eidAuthUri = "web-eid-mobile://auth#" + encoded;
8079

8180
response.setContentType("application/json");
82-
MAPPER.writeValue(response.getWriter(), new MobileAuthInitResponse(eidAuthUri));
83-
}
84-
85-
@Override
86-
protected boolean shouldNotFilterAsyncDispatch() {
87-
return false;
81+
OBJECT_MAPPER.writeValue(response.getWriter(), Map.of("auth_uri", eidAuthUri));
8882
}
8983
}

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ public final class WebEidLoginPageGeneratingFilter extends OncePerRequestFilter
4646
<head>
4747
<meta charset="utf-8">
4848
<title>Signing you in…</title>
49-
<meta id="csrftoken" content="%s"/>
50-
<meta id="csrfheadername" content="%s"/>
5149
</head>
5250
<body>
5351
<script>
@@ -62,16 +60,13 @@ public final class WebEidLoginPageGeneratingFilter extends OncePerRequestFilter
6260
return;
6361
}
6462
65-
const csrfToken = document.querySelector('#csrftoken').content;
66-
const csrfHeaderName = document.querySelector('#csrfheadername').content;
67-
6863
const authToken = payload["auth-token"] ?? payload;
6964
7065
fetch("/auth/login", {
7166
method: "POST",
7267
headers: {
7368
"Content-Type": "application/json",
74-
[csrfHeaderName]: csrfToken
69+
"%s": "%s"
7570
},
7671
body: JSON.stringify({ "auth-token": authToken }),
7772
credentials: "include"
@@ -82,7 +77,10 @@ public final class WebEidLoginPageGeneratingFilter extends OncePerRequestFilter
8277
})
8378
.catch(e => {
8479
console.error("Login failed", e);
85-
window.location.replace("/?mobileAuthError=login_failed");
80+
const errorDiv = document.createElement("div");
81+
errorDiv.style.color = "red";
82+
errorDiv.textContent = "Authentication failed.";
83+
document.body.appendChild(errorDiv);
8684
});
8785
})();
8886
</script>
@@ -93,7 +91,7 @@ public final class WebEidLoginPageGeneratingFilter extends OncePerRequestFilter
9391

9492
@Override
9593
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain chain)
96-
throws IOException, ServletException {
94+
throws IOException, ServletException {
9795
if (!requestMatcher.matches(request)) {
9896
chain.doFilter(request, response);
9997
return;
@@ -108,8 +106,8 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull Ht
108106
}
109107

110108
String html = generateHtml(
111-
csrf != null ? csrf.getToken() : "",
112-
csrf != null ? csrf.getHeaderName() : "X-CSRF-TOKEN"
109+
csrf != null ? csrf.getToken() : "",
110+
csrf != null ? csrf.getHeaderName() : "X-CSRF-TOKEN"
113111
);
114112

115113
response.setContentType("text/html;charset=UTF-8");

example/src/main/java/eu/webeid/example/web/WelcomeController.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,14 @@
2424

2525
import org.slf4j.Logger;
2626
import org.slf4j.LoggerFactory;
27-
import org.springframework.security.access.annotation.Secured;
2827
import org.springframework.stereotype.Controller;
2928
import org.springframework.ui.Model;
3029
import org.springframework.web.bind.annotation.GetMapping;
3130

3231
import java.security.Principal;
3332
import java.util.Objects;
3433

35-
import static eu.webeid.example.security.AuthTokenDTOAuthenticationProvider.ROLE_USER;
36-
3734
@Controller
38-
@Secured(ROLE_USER)
3935
public class WelcomeController {
4036
private static final Logger LOG = LoggerFactory.getLogger(WelcomeController.class);
4137

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,12 @@ <h3><a id="for-developers"></a>For developers</h3>
280280
}
281281

282282
const challengeResponse = await fetch("/auth/challenge", {
283-
method: "GET",
284-
headers: { "Content-Type": "application/json" }
283+
method: "POST",
284+
headers: {
285+
"Content-Type": "application/json",
286+
[csrfHeaderName]: csrfToken
287+
},
288+
credentials: "include"
285289
});
286290
await checkHttpError(challengeResponse);
287291
const {nonce} = await challengeResponse.json();

0 commit comments

Comments
 (0)