Skip to content

Commit

Permalink
fixes #sabi-113 (#152) (#153)
Browse files Browse the repository at this point in the history
fixes sabi-113 HTTP.500 after login (returned users)
  • Loading branch information
StefanSchubert authored Feb 22, 2024
1 parent 702c441 commit 6833250
Show file tree
Hide file tree
Showing 26 changed files with 470 additions and 124 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# History of changes (since 5/2022)

## Release 1.2.5

### Bugfixes
* HTTP.500 in some cases for returing users with timedout session (sabi-113)

## Release 1.2.4

### Bugfixes
Expand Down
40 changes: 4 additions & 36 deletions sabi-webclient/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<groupId>de.bluewhale</groupId>
<artifactId>sabi-webclient</artifactId>
<version>1.2.4</version>
<version>1.2.5</version>
<packaging>jar</packaging>
<name>sabi-webclient</name>
<description>A JSF based webclient for sabi.</description>
Expand Down Expand Up @@ -47,7 +47,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.7</version>
<version>3.2.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

Expand All @@ -57,8 +57,8 @@
<java.version>21</java.version>
<log4j2.version>2.20.0</log4j2.version>
<jakarta.cdi.version>4.0.1</jakarta.cdi.version>
<micrometer.prometheus.version>1.12.2</micrometer.prometheus.version>
<joinfaces.version>5.1.4</joinfaces.version>
<micrometer.prometheus.version>1.12.3</micrometer.prometheus.version>
<joinfaces.version>5.2.2</joinfaces.version>
<sabi.boundary.version>1.2.5</sabi.boundary.version>
<passay.version>1.6.4</passay.version>
<owasp.plugin.version>9.0.9</owasp.plugin.version>
Expand Down Expand Up @@ -107,11 +107,6 @@
</exclusions>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
Expand Down Expand Up @@ -215,22 +210,6 @@

<build>
<finalName>sabi-webclient</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.joinfaces</groupId>
<artifactId>joinfaces-maven-plugin</artifactId>
<version>${joinfaces.version}</version>
<executions>
<execution>
<goals>
<goal>classpath-scan</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>

<plugins>
<plugin>
Expand Down Expand Up @@ -276,17 +255,6 @@
</executions>
</plugin>

<plugin>
<!--
Description from: https://docs.joinfaces.org/current/reference/
JoinFaces provides org.joinfaces:joinfaces-maven-plugin Maven plugin
to configure a classpath scan at build-time in order to reduce the
startup time of applications which use an embedded servlet container.
-->
<groupId>org.joinfaces</groupId>
<artifactId>joinfaces-maven-plugin</artifactId>
</plugin>

<plugin>
<!-- Used for vulnerability checks
The examples below can be executed using mvn verify.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 by Stefan Schubert under the MIT License (MIT).
* Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT).
* See project LICENSE file for the detailed terms and conditions.
*/

Expand All @@ -8,16 +8,20 @@
import de.bluewhale.sabi.webclient.utils.I18nUtil;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.servlet.http.Cookie;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.context.annotation.SessionScope;

import java.io.Serializable;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;

/**
* Container for mandatory things which we need to keep in a user session.
Expand Down Expand Up @@ -170,8 +174,24 @@ public void setLanguage(String language) {

/** Invalidates Frontend Session in case of logout. */
public void endSession(){

// On the Serverside
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().invalidateSession();
ExternalContext externalContext = context.getExternalContext();
externalContext.invalidateSession();

// And on the Client Side. Otherwise the cookies there
// might survive and we may observe a HTTP-500
// in combination with a server restart, see sabi-113 for details.
// Löschen der Cookies
Map<String, Object> cookies = externalContext.getRequestCookieMap();
Iterator<String> iterator = cookies.keySet().iterator();
while (iterator.hasNext()) {
String cookieName = iterator.next();
Cookie cookie = (Cookie) cookies.get(cookieName);
cookie.setMaxAge(0); // By setting the expiration "date" to 0, the cookie is being invalidates by the browser.
externalContext.addResponseCookie(cookieName, null, null);
}
}

@PostConstruct
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 by Stefan Schubert under the MIT License (MIT).
* Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT).
* See project LICENSE file for the detailed terms and conditions.
*/

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
/*
* Copyright (c) 2023 by Stefan Schubert under the MIT License (MIT).
* Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT).
* See project LICENSE file for the detailed terms and conditions.
*/

package de.bluewhale.sabi.webclient.config;

import de.bluewhale.sabi.webclient.security.CustomExceptionHandlerFilter;
import de.bluewhale.sabi.webclient.security.SabiDoorKeeper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;

Expand All @@ -31,12 +33,17 @@ public class WebSecurityConfig {
@Autowired
SabiDoorKeeper sabiAuthenticationProvider;

@Autowired
private CustomExceptionHandlerFilter customExceptionHandlerFilter;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {

MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);

http
// Add our sabi-113 required exception handler here
.addFilterAfter(customExceptionHandlerFilter, FilterSecurityInterceptor.class)
.authorizeRequests(authorize -> authorize
.requestMatchers(mvcMatcherBuilder.pattern("/jakarta.faces.resource/**")).permitAll()
// Allow Pages that don't require an auth context.
Expand All @@ -50,8 +57,10 @@ public SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospe
.requestMatchers(mvcMatcherBuilder.pattern( "/logout.xhtml")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern( "/sessionExpired.xhtml")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern( "/credits.xhtml")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern( "/static/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern( "/static/error/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern( "/.well-known/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern( "/error")).permitAll() // Error Controller
.requestMatchers(mvcMatcherBuilder.pattern( "/images/**")).permitAll() // Error Controller
// Allow Monitoring Endpoint
.requestMatchers(mvcMatcherBuilder.pattern(HttpMethod.GET, "/actuator/**")).permitAll()
// all others require authentication
Expand All @@ -61,7 +70,7 @@ public SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospe

// In Case of a session timeout don't go directly to the login page,
// use this page instead, for being able to notify the user what has happened.

.sessionManagement(session -> session.invalidSessionUrl("/sessionExpired.xhtml"))

// login - using this the browser redirect to this page if login is required and you are not logged in.
Expand All @@ -76,7 +85,8 @@ public SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospe
.authenticationProvider(this.sabiAuthenticationProvider)

// not needed as JSF 2.2 is implicitly protected against CSRF
.csrf(csrf -> csrf.disable());
.csrf(csrf -> csrf.disable())
;

return http.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import java.util.List;
import java.util.Locale;

import static de.bluewhale.sabi.webclient.utils.PageRegister.MEASUREMENT_VIEW_PAGE;

/**
* Controller for the Measurement View as shown in measureView.xhtml
*
Expand All @@ -39,7 +41,6 @@
@Getter
public class MeasurementListView extends AbstractControllerTools implements Serializable {

private static final String MEASUREMENT_VIEW_PAGE = "measureView";
private static final int MAX_RESULT_COUNT = 5;

@Autowired
Expand Down Expand Up @@ -119,7 +120,7 @@ public String getTankNameForId(Long tankId) {

public String resetForm() {
measurement = new MeasurementTo();
return MEASUREMENT_VIEW_PAGE;
return MEASUREMENT_VIEW_PAGE.getNavigationableAddress();
}

public String save() {
Expand All @@ -135,7 +136,7 @@ public String save() {
} else {
MessageUtil.warn("troubleMsg", "common.incompleted_formdata.t", userSession.getLocale());
}
return MEASUREMENT_VIEW_PAGE;
return MEASUREMENT_VIEW_PAGE.getNavigationableAddress();
}

private boolean allDataProvided(MeasurementTo measurement) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 by Stefan Schubert under the MIT License (MIT).
* Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT).
* See project LICENSE file for the detailed terms and conditions.
*/

Expand All @@ -9,6 +9,8 @@
import jakarta.inject.Named;
import lombok.extern.slf4j.Slf4j;

import static de.bluewhale.sabi.webclient.utils.PageRegister.LOGOUT_PAGE;

/**
* MenuActions
*
Expand All @@ -19,7 +21,7 @@
@Slf4j
public class MenuView {

static String LOGOUT_PAGE = "/logout?faces-redirect=true";
// static String LOGOUT_PAGE = "/logout?faces-redirect=true";

/**
* Kills the sessions. The frontend session will be invalidated during rendering
Expand All @@ -30,7 +32,7 @@ public class MenuView {
*/
public String logout() {
log.info(" #### User logged out. ####");
return LOGOUT_PAGE;
return "/"+LOGOUT_PAGE.getNavigationableAddress()+"?faces-redirect=true";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2024 by Stefan Schubert under the MIT License (MIT).
* See project LICENSE file for the detailed terms and conditions.
*/

package de.bluewhale.sabi.webclient.controller;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* Nice try (to solve sabi-113) but It won't work for <b>jakarta.faces.application.ViewExpiredException</b>
* as the Controller will be involved in the Context of the DispatcherServlet, which won't happen for errors
* occurring in the JSF engine. The error which has been seen by sabi-113 us happening
* in the Context of the FacesServlet which gets uncaught all way up through the springframework.security.eb Filterchain.
* <p>
* So though this Error-Controller configuration is more or less dead code because of the
* Faces Techstack here, I will leave it with this explanation as reference in it.
*/
@Controller
@Slf4j
public class MyErrorController implements ErrorController {

@RequestMapping("/error")
public String handleError(HttpServletRequest request) {
Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);

if (status != null) {
Integer statusCode = Integer.valueOf(status.toString());

if (statusCode == HttpStatus.NOT_FOUND.value()) {
return "/static/error/404.html";
} else if (statusCode == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
return "/static/error/500.html";
}
}

return "/static/error/error.html"; // fallback
}
}
Loading

0 comments on commit 6833250

Please sign in to comment.