Skip to content

Conversation

@ethaaalpha
Copy link
Contributor

@ethaaalpha ethaaalpha commented Sep 24, 2025

Firstly, this pull request is based on another one: multi_api.
This one introduce the new /internal/session endpoint, which implement the DELETE, POST, GET methods.

Spring Security

A new SecurityFilterChain is present:InternalSecurityConfig, it handles all /internal/** urls:

  • CORS policy is enabled
  • CSRF Token verification is enabled:
    The token will be defined with set_cookie after a successful login.
    All of the "non secure" http requests will need the CSRF Token except for POST on /internal/session.
  • vip-session-cookie and vip-user-cookie are defined on login and use by the filter chain to check authentication

Cookies and actual frontend endpoints evolutions

By the way, we changed the cookies to httpOnly and adapt the actual frontend to support them in this case. It mean that the actual frontend will use GET /internal/session to determine if the user is actually logged (the current sign-in also use the new endpoint).
Some small modifications were made in GWT serverside code to support httpOnly.
The cookies are also set as secure if the apache.sslport properties is not 80.

Others

Some new annotations were introduced for the deprecation of SmartGWT (@VIPRemoval and @VIPCheckRemoval)

- add new `InternalSecurityConfig` filter chain (defined as order: 2)
- created DELETE/POST/GET methods for /internal/session
- move some models from vip-api to vip-core
- create specific class for `CurrentUserProvider` service
- add a new `SessionAuthenticationProvider` with associated Filter/Token
- refractor `ApikeyAuthenticationProvider` and
  `SessionAuthenticationProvider` into `AbstractAuthenticationProvider`
- POST /internal/session now return Session object as valid response
- rename `SpringApiUser` to `SpringPrincipalUser`
- make COOKIES_SESSION and COOKIES_USER `httpOnly`
-- adapt GWT code to support httpOnly on server implementation
- cookies will set as `secure` only if *apache.sslport* != 80
- edit sign-in.js/home.js endpoints from */rest/session* to */internal/session* for sign-in and retrieving current session instead of cookies (due to **httpOnly**)
- VIPRemoval and VIPCheckRemoval created annotations
- all unsafe methods are concerned under /internal/** except for
  /internal/session (which creates the token)
- refactor `SessionControler` to handle http/cookie related objects
  instead of `SessionBusiness`
- make signIn define SecurityContextHolder
Copy link
Contributor

@ngeorges-cnrs ngeorges-cnrs left a comment

Choose a reason for hiding this comment

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

Works for me in general, I just made minor comments on some code.

Two points to be discussed with @axlbonnet :

  • the /internal API response body on errors is not final in the present PR, this is normally not a blocker, as it can be handled later.
  • server.getApacheSSLPort() != 80 as the condition for httpOnly cookies should probably be replaced by a dedicated new setting (and getApacheSSLPort removed as unused ?). This is used in two places where cookies are set, VipSessionBusiness.java and SessionController.java.

this.server = server;
}

@GetMapping()
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor syntax inconsistency : we typically do not write parenthesis for annotations with no parameters. This also applies to @PostMapping() below.

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import fr.insalyon.creatis.vip.core.client.view.CoreConstants;
Copy link
Contributor

Choose a reason for hiding this comment

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

New controllers for the internal API should ideally have no dependency on GWT-related packages, so any import of *.client.* or *.server.rpc.* should in theory induce a refactoring. This could also be handled a as separate task later.

Copy link
Contributor Author

@ethaaalpha ethaaalpha Sep 29, 2025

Choose a reason for hiding this comment

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

Yes, we'll handle that latter. I specific constants and models refactoring is needed.

fetch("/internal/session").then(function (response) {
if (response.status != 200) {
window.location = "index.html";
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: maybe use response.ok instead of response.status ?

Also, some notes on JS fetch() error handling, which will be more important for the JS front-end :

  • a 4XX/5XX response other than 401 technically doesn't indicate that the user is disconnected, so showing the login page in that case is not great, especially on 5XX. Some user-visible error message while staying on "home" might be preferable.
  • there is a similar problem in case of network errors, where the promise won't resolve and which can be handled with .catch()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, I've changed to response.ok.
About the JS notes, I'll write then down into a ticket of @hippolyteblot to make sure these issues will be handled by the new front.

@ethaaalpha ethaaalpha marked this pull request as ready for review September 29, 2025 08:41
Copy link
Contributor

@axlbonnet axlbonnet left a comment

Choose a reason for hiding this comment

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

Seems good except for a few remarks.

Also, it would be nice to check if spring security login/session/cookie could replace some stuff here.

User user) throws BusinessException, CoreException {
try {
// see explanation in SessionBusiness -> createCookie
boolean isSecure = server.getApacheSSLPort() != 80;
Copy link
Contributor

Choose a reason for hiding this comment

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

This config is (almost) unused and we'll get rid of it.
Maybe introduce a new "secure" or "development" config that could be used be several things.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I created the "dev" property which is by default false.


@Service
@Transactional
@VIPRemoval
Copy link
Contributor

Choose a reason for hiding this comment

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

As several methods are @VIPCheckRemoval I think the whole class should be too.


// this class was factorized from the Apikey Security provider
// since we have added the Session Security Provider
@Service
Copy link
Contributor

Choose a reason for hiding this comment

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

i don't think @service is necessary here as it is an abstract class

String session = null;

// this will actually always return null since we use httpOnly cookies
// the actual values are retrieved in the service implementation itself
Copy link
Contributor

Choose a reason for hiding this comment

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

you can remove it then

logger.debug("VIP successfully configured.");

if (configurationBusiness.validateSession(email, session)) {
User user = vipSessionBusiness.resetSessionFromCookie(getThreadLocalRequest());
Copy link
Contributor

Choose a reason for hiding this comment

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

remove email and session in method signature

response.addCookie(createCookie(CoreConstants.COOKIES_USER, null, 0, true));
response.addCookie(createCookie(CoreConstants.COOKIES_CSRF_TOKEN, null, 0, false));
} catch (BusinessException e) {
throw new ApiException(e); // change
Copy link
Contributor

Choose a reason for hiding this comment

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

change indeed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in #602.

Cookie cookie = new Cookie(name, value);
// for the moment we use that, but a property might be created in vip.conf
// instead!
boolean isSecure = server.getApacheSSLPort() != 80;
Copy link
Contributor

Choose a reason for hiding this comment

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

in development, we may need not httpOnly and not Secure ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In dev we only want to change secure (HTTPS) to false (HTTP). But the behavior of httpOnly is still wanted and needed.

// define authenticated user in Spring context for the current request
// this is usefull to call getSession()
SecurityContextHolder.getContext()
.setAuthentication(sessionAuthenticationProvider.createAuthenticationFromUser(user));
Copy link
Contributor

Choose a reason for hiding this comment

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

Just remove spring security stuff here and create a new session to make it simpler..

sessionCookie.setPath("/");
sessionCookie.setHttpOnly(true);
sessionCookie.setSecure(isSecure);

Copy link
Contributor

Choose a reason for hiding this comment

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

Could the cookie stuff be factorized with the stuff from Session controller ?

Copy link
Contributor Author

@ethaaalpha ethaaalpha Nov 17, 2025

Choose a reason for hiding this comment

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

Since this class will disappear after the GWT migration, I don't think this is really useful?

response.addCookie(createCookie(
CoreConstants.COOKIES_CSRF_TOKEN, token.getToken(), CoreConstants.COOKIES_DURATION, false));

return session;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the cookies are set at login but never renewed.
So I guess that after 1 week, the user will have to login again ?

session.password = null;
session.level = UserLevel.Beginner;
return session;
return sessionBusiness.getSession();
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe renew the cookies here to avoid them expiring after 1 week.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants