Skip to content

fix(springboot): add session-cookie-path-enforcement flag to isolate …#2609

Merged
kthoms merged 16 commits into
operaton:mainfrom
Fejbien:pathfix
Apr 8, 2026
Merged

fix(springboot): add session-cookie-path-enforcement flag to isolate …#2609
kthoms merged 16 commits into
operaton:mainfrom
Fejbien:pathfix

Conversation

@Fejbien

@Fejbien Fejbien commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

…Operaton session cookie (LF insted of crlf)

  • introduces operaton.bpm.webapp.session-cookie-path-enforcement property (default false)
  • when enabled, applies Path=/operaton to session cookie via filter to prevent JSESSIONID conflicts
  • resolves conflict with backend/Keycloak session when running in single Spring Boot app

related to #1632

…Operaton session cookie (LF insted of crlf)

- introduces operaton.bpm.webapp.session-cookie-path-enforcement property (default false)
- when enabled, applies Path=/operaton to session cookie via filter to prevent JSESSIONID conflicts
- resolves conflict with backend/Keycloak session when running in single Spring Boot app

related to operaton#1632

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the Spring Boot webapp integration to better isolate Operaton’s session cookie in “single Spring Boot app” setups (e.g., backend + Keycloak + Operaton) by enabling optional session-cookie path enforcement and by enhancing existing cookie-related filters/config.

Changes:

  • Add optional operaton.bpm.webapp.session-cookie-path-enforcement that registers a new response-wrapping filter to enforce a Path attribute on the session cookie.
  • Extend cookie configuration to support cookiePath and improve session-cookie header detection/configuration in SessionCookieFilter.
  • Introduce operaton.bpm.session.cookie.name (via new SessionProperties) and wire it into filter init params as an alias for session cookie name handling.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
webapps/assembly/src/main/java/org/operaton/bpm/webapp/impl/security/filter/SessionCookieFilter.java Enhances Set-Cookie rewriting to also enforce a configured cookie Path.
webapps/assembly/src/main/java/org/operaton/bpm/webapp/impl/security/filter/CsrfPreventionFilter.java Decouples CSRF cookie naming from session-cookie configuration by introducing a dedicated csrfCookieName.
webapps/assembly/src/main/java/org/operaton/bpm/webapp/impl/security/filter/CookieConfigurator.java Adds support for parsing and exposing a cookiePath init param, and allows explicit cookieName init param override.
spring-boot-starter/starter/src/main/java/org/operaton/bpm/spring/boot/starter/property/SessionProperties.java Adds new nested config object for operaton.bpm.session.cookie.name.
spring-boot-starter/starter/src/main/java/org/operaton/bpm/spring/boot/starter/property/SessionCookieProperties.java Adds cookiePath property and passes it through to filter init params.
spring-boot-starter/starter/src/main/java/org/operaton/bpm/spring/boot/starter/property/OperatonBpmProperties.java Wires new SessionProperties into the root configuration properties.
spring-boot-starter/starter-webapp-core/src/main/java/org/operaton/bpm/spring/boot/starter/webapp/filter/SessionCookiePathFilter.java New filter that rewrites the session cookie Path via addCookie and Set-Cookie header rewriting.
spring-boot-starter/starter-webapp-core/src/main/java/org/operaton/bpm/spring/boot/starter/webapp/OperatonBpmWebappInitializer.java Adds alias wiring: operaton.bpm.session.cookie.name → SessionCookieFilter init params.
spring-boot-starter/starter-webapp-core/src/main/java/org/operaton/bpm/spring/boot/starter/webapp/OperatonBpmWebappAutoConfiguration.java Registers the new SessionCookiePathFilter behind the session-cookie-path-enforcement flag.
spring-boot-starter/starter-webapp-core/src/test/java/org/operaton/bpm/spring/boot/starter/webapp/filter/util/HttpClientExtension.java Updates the default expected session-cookie Path segment in test regex helpers.
Comments suppressed due to low confidence (1)

webapps/assembly/src/main/java/org/operaton/bpm/webapp/impl/security/filter/SessionCookieFilter.java:53

  • doFilter only invokes filterChain.doFilter(...) when both request/response are HTTP. If this filter is ever applied to non-HTTP requests/responses, the chain will not proceed and the request will effectively be dropped. Consider adding an else branch that delegates to filterChain.doFilter(servletRequest, servletResponse) to preserve the Filter contract.
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
          throws IOException, ServletException {
    if ((servletRequest instanceof HttpServletRequest httpServletRequest) && (servletResponse instanceof HttpServletResponse httpServletResponse)) {
      // create a session if none exists yet
      httpServletRequest.getSession();
      // execute filter chain with a response wrapper that handles sameSite attributes
      filterChain.doFilter(httpServletRequest, new SameSiteResponseProxy(httpServletResponse));
    }
  }

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (1)

webapps/assembly/src/main/java/org/operaton/bpm/webapp/impl/security/filter/SessionCookieFilter.java:53

  • SessionCookieFilter.doFilter only invokes filterChain.doFilter() inside the HttpServletRequest/HttpServletResponse instanceof check; if the filter is ever applied to a non-HTTP request/response, the chain will not continue and the request will effectively be dropped. Consider always calling filterChain.doFilter(...), wrapping only when the request/response are HTTP.
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
          throws IOException, ServletException {
    if ((servletRequest instanceof HttpServletRequest httpServletRequest) && (servletResponse instanceof HttpServletResponse httpServletResponse)) {
      // create a session if none exists yet
      httpServletRequest.getSession();
      // execute filter chain with a response wrapper that handles sameSite attributes
      filterChain.doFilter(httpServletRequest, new SameSiteResponseProxy(httpServletResponse));
    }
  }

Comment on lines 222 to 226
public String getSessionCookieRegex(String sameSite) {
return getSessionCookieRegex(null, null, sameSite, false);
return getSessionCookieRegex(DEFAULT_SESSION_COOKIE_PATH, null, sameSite, false);
}

public String getSessionCookieRegex(String cookieName, String sameSite) {

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HttpClientExtension now assumes the default expected session cookie Path is '/operaton' (via DEFAULT_SESSION_COOKIE_PATH). Existing session-cookie tests that don't enable path enforcement historically expected Path='/' and will likely fail. Consider keeping the default regex path as '/' (or leaving it unset) and only passing an explicit path in the new path-enforcement tests.

Copilot uses AI. Check for mistakes.
httpClientExtension.performRequest("http://localhost:" + port + "/operaton/app/tasklist/default");

assertThat(httpClientExtension.getCookie("JSESSIONID"))
.as("JSESSIONID should not exist when operaton.bpm.session.cookie.name is set alias wiring may be broken")

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertion message references operaton.bpm.session.cookie.name, but this test configures the cookie name via server.servlet.session.cookie.name. Updating the message to match the actual configuration will make failures easier to understand.

Suggested change
.as("JSESSIONID should not exist when operaton.bpm.session.cookie.name is set alias wiring may be broken")
.as("JSESSIONID should not exist when server.servlet.session.cookie.name is set; alias wiring may be broken")

Copilot uses AI. Check for mistakes.
Comment on lines +106 to +108
if (StringUtils.isNotBlank(cookiePath)) {
initParams.put("cookiePath", cookiePath);
}

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cookiePath is user-configurable and later inserted into Set-Cookie headers. To prevent invalid cookies / header injection, validate/normalize it (e.g., ensure it starts with '/', and reject CR/LF and ';') before putting it into initParams.

Copilot uses AI. Check for mistakes.
fabian.sucholas added 2 commits March 23, 2026 12:16
…path against invalid chars

- path is set automatically (in bean) based of operaton.bpm.webapp.application-path and server.servlet.context-path

related to operaton#1632

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 2 comments.

…t state

- Renames SessionCookiePathEnforcementDefaultIT to SessionCookiePathEnforcementEnabledDefaultIT
- Renames SessionCookiePathEnforcementCustomIT to SessionCookiePathEnforcementEnabledCustomIT
- SessionCookiePathEnforcementDisabledIT to test the actual default behavior (disabled) without explicitly setting the property

related to operaton#1632

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.


@NestedConfigurationProperty
private FilterProperty filter = new FilterProperty();

Copilot AI Mar 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new operaton.bpm.session.* configuration subtree is introduced (SessionProperties), but there is already an existing operaton.bpm.webapp.session-cookie.cookie-name (via SessionCookieProperties) that maps to the same cookieName init parameter. Adding a second way to configure the same behavior is confusing for users and complicates the public configuration surface; consider reusing the existing webapp.session-cookie.cookie-name property (or clearly documenting and differentiating responsibilities if both are required).

Suggested change
/**
* Deprecated configuration subtree for HTTP session settings.
* <p>
* This property exposes the {@code operaton.bpm.session.*} configuration
* subtree, which configures the same underlying behavior (including the
* {@code cookieName} init parameter) as
* {@code operaton.bpm.webapp.session-cookie.cookie-name}.
* <p>
* New configurations should use
* {@code operaton.bpm.webapp.session-cookie.cookie-name} instead of this
* property. The {@code operaton.bpm.session.*} subtree is kept only for
* backward compatibility and may be removed in a future release.
*/
@Deprecated

Copilot uses AI. Check for mistakes.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 4 comments.


/**
* Initializes the filter by reading the configuration parameters.
* * <p>If the {@value #PARAM_SESSION_COOKIE_NAME} or {@value #PARAM_COOKIE_PATH}

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a stray extra * in the Javadoc ("* *

...") which will render oddly in generated docs. Please remove the redundant asterisk so the Javadoc formatting stays correct.

Suggested change
* * <p>If the {@value #PARAM_SESSION_COOKIE_NAME} or {@value #PARAM_COOKIE_PATH}
* <p>If the {@value #PARAM_SESSION_COOKIE_NAME} or {@value #PARAM_COOKIE_PATH}

Copilot uses AI. Check for mistakes.
- Retrieve session cookie name from ServletContext as a reliable fallback
- Delegate cookie path formatting to SessionCookiePathFilter.normalizeCookiePath
- Remove unused StringUtils
- Remove asterisk in SessionCookiePathFilter Javadoc

related to operaton#1632
@Fejbien Fejbien requested a review from Copilot April 2, 2026 07:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.

@kthoms kthoms added scope:spring-boot Changes to the Spring Boot starter. noteworthy Should be documented in the release notes labels Apr 7, 2026
@kthoms kthoms added this to the 2.1.0 milestone Apr 7, 2026
@kthoms

kthoms commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

@Fejbien Sorry for the long delay. I had finally the rest to look at your PR in detail. I have added some changes and think it is now in a good shape. I will have a final look, but planning to merge for release 2.1.

@kthoms kthoms merged commit b3e0c40 into operaton:main Apr 8, 2026
12 checks passed
@kthoms

kthoms commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

Thank you for your patience and contributions, @Fejbien !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

noteworthy Should be documented in the release notes scope:spring-boot Changes to the Spring Boot starter.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants