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..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/**", @@ -101,7 +109,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"));