From d0894a1f9222fd61220a8539c077a142b604b0fd Mon Sep 17 00:00:00 2001 From: Isaries Date: Mon, 6 Jul 2026 22:04:32 +0800 Subject: [PATCH 1/2] fix(security): deny unauthenticated access by default The authorization chain listed specific paths and ended without a final rule, so any request matching none of the rules was permitted. Most /api endpoints matched no rule and relied entirely on method-level annotations, so any endpoint missing an annotation was reachable without authentication. Add an explicit allow list for the endpoints that must remain public (sign-in and its OAuth callbacks, registration, account and password recovery, the contact form, the public home, news, library and preview content, and the bootstrap configuration) and require authentication for every other request, so a missing method annotation fails closed. --- .../portal/spring/impl/WebSecurityConfig.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/wise/portal/spring/impl/WebSecurityConfig.java b/src/main/java/org/wise/portal/spring/impl/WebSecurityConfig.java index d98f79e2e..c58891e3e 100644 --- a/src/main/java/org/wise/portal/spring/impl/WebSecurityConfig.java +++ b/src/main/java/org/wise/portal/spring/impl/WebSecurityConfig.java @@ -101,7 +101,27 @@ protected void configure(HttpSecurity http) throws Exception { .antMatchers("/studentStatus").hasAnyRole("TEACHER", "STUDENT") .antMatchers("/teacher/**").hasAnyRole("TEACHER") .antMatchers("/sso/discourse").hasAnyRole("TEACHER", "STUDENT") - .antMatchers("/").permitAll(); + // Endpoints that must stay reachable without authentication: sign-in and its + // OAuth callbacks, account registration, account and password recovery, the + // contact form, the public home, news, library and preview content, and the + // application bootstrap configuration. Every request that does not match a rule + // above falls through to the final rule and now requires authentication, rather + // than being permitted by default. The framework error dispatch and favicon are + // included so that an error raised while serving a public page renders the error + // response instead of being turned into an authentication redirect. + .antMatchers("/", "/login", "/login/**", "/error", "/errors/**", "/favicon.ico", + "/run-survey/**", "/previewproject.html").permitAll() + .antMatchers("/api/j_acegi_security_check", "/api/google-login", "/api/microsoft-login", + "/api/logout").permitAll() + .antMatchers("/api/student/register", "/api/student/register/questions", + "/api/teacher/register", "/api/contact").permitAll() + .antMatchers("/api/student/forgot/**", "/api/teacher/forgot/**").permitAll() + .antMatchers("/api/user/config", "/api/user/info", "/api/user/languages", + "/api/announcement", "/api/news", "/api/project/library", "/api/project/community", + "/api/config/vle", "/api/config/preview/**", "/api/project/info/*", + "/api/run/info", "/api/runInfo", "/api/session/renew", + "/api/google-user/check-user-exists").permitAll() + .anyRequest().authenticated(); http.formLogin().loginPage("/login").permitAll(); http.logout().addLogoutHandler(wiseLogoutHandler()) .logoutRequestMatcher(new AntPathRequestMatcher("/api/logout")); From 2c1ac6dbb08239f2e9d4cf9e0006f5f7ad7fb7d5 Mon Sep 17 00:00:00 2001 From: Isaries Date: Mon, 6 Jul 2026 23:02:29 +0800 Subject: [PATCH 2/2] fix(security): keep public static assets reachable under default-deny Denying unmatched requests by default also caught the static asset paths served by the resource handlers configured in WebConfig (portal scripts, themes and translations, the runtime engine, project files and project icons). Those are public content that the login page and the anonymous project preview need, so blocking them would break sign-in and preview for signed-out visitors. Permit those paths explicitly. Student uploaded files are intentionally left requiring authentication. --- .../org/wise/portal/spring/impl/WebSecurityConfig.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/org/wise/portal/spring/impl/WebSecurityConfig.java b/src/main/java/org/wise/portal/spring/impl/WebSecurityConfig.java index c58891e3e..5dcde175d 100644 --- a/src/main/java/org/wise/portal/spring/impl/WebSecurityConfig.java +++ b/src/main/java/org/wise/portal/spring/impl/WebSecurityConfig.java @@ -86,6 +86,14 @@ protected void configure(HttpSecurity http) throws Exception { .addFilterAfter(microsoftOpenIdConnectFilter(), OAuth2ClientContextFilter.class) .addFilterAfter(authenticationProcessingFilter(), GoogleOpenIdConnectFilter.class) .authorizeRequests() + // Static assets served by the resource handlers configured in WebConfig are public + // content (portal scripts, themes and translations, the runtime engine, project + // files and project icons). They must stay reachable without signing in, now that + // unmatched requests are denied by default, otherwise the login and public preview + // pages would fail to load their assets. Student uploaded files are intentionally + // excluded so they continue to require authentication. + .antMatchers("/pages/resources/**", "/portal/javascript/**", "/portal/themes/**", + "/portal/translate/**", "/vle/**", "/curriculum/**", "/projectIcons/**").permitAll() // Matched the way Spring MVC matches, so a trailing slash cannot slip an exact path // past these rules and into the broader "/admin/**" rule below. .mvcMatchers("/admin/account/**", "/admin/portal/**", "/admin/news/**",