Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spring-security breaks Vaadin session serialization #18458

Closed
jorgheymans opened this issue Jan 15, 2024 · 2 comments · Fixed by #18463
Closed

spring-security breaks Vaadin session serialization #18458

jorgheymans opened this issue Jan 15, 2024 · 2 comments · Fixed by #18463

Comments

@jorgheymans
Copy link

Description of the bug

Given a minimal Vaadin starter project, adding and configuring spring-security as documented here https://vaadin.com/docs/latest/security/enabling-security makes the Vaadin session no longer serializable.

Expected behavior

The Vaadin session should stay serializable.

Minimal reproducible example

Start the attached project, navigating to localhost:8080 already produces the serialization exception.

org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver$1
	Start Track ID: 140, Stack depth: 17. Reference stack: 
		- field (class "org.springframework.aop.framework.AdvisedSupport", name: "targetSource", type: "interface org.springframework.aop.TargetSource")
		- object (class "org.springframework.aop.framework.ProxyFactory", org.springframework.aop.framework.ProxyFactory: 0 interfaces []; 0 advisors []; targetSource [org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver$1@2263eb]; proxyTargetClass=false; optimize=false; opaque=false; exposeProxy=false; frozen=false)
		- field (class "org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor", name: "advised", type: "class org.springframework.aop.framework.AdvisedSupport")
		- object (class "org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor", org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor@e42bae4)
		- field (class "com.vaadin.flow.server.auth.AccessAnnotationChecker$$SpringCGLIB$$0", name: "CGLIB$CALLBACK_0", type: "interface org.springframework.cglib.proxy.MethodInterceptor")
		- object (class "com.vaadin.flow.server.auth.AccessAnnotationChecker$$SpringCGLIB$$0", com.vaadin.flow.server.auth.AccessAnnotationChecker@17c5e11)
		- field (class "com.vaadin.flow.server.auth.AnnotatedViewAccessChecker", name: "accessAnnotationChecker", type: "class com.vaadin.flow.server.auth.AccessAnnotationChecker")
		- object (class "com.vaadin.flow.server.auth.AnnotatedViewAccessChecker", com.vaadin.flow.server.auth.AnnotatedViewAccessChecker@1764e45e)
		- custom writeObject data (class "java.util.CollSer")
		- object (class "java.util.CollSer", java.util.CollSer@79aa49f5)
		- field (class "com.vaadin.flow.server.auth.NavigationAccessControl", name: "checkerList", type: "interface java.util.List")
		- object (class "com.vaadin.flow.spring.security.SpringNavigationAccessControl", com.vaadin.flow.spring.security.SpringNavigationAccessControl@46aea580)
		- custom writeObject data (class "java.util.ArrayList")
		- object (class "java.util.ArrayList", [com.vaadin.flow.spring.security.SpringNavigationAccessControl@46aea580, com.vaadin.flow.spring.scopes.VaadinRouteScope$NavigationListener@5fa5da25])
		- element of array (index: 0)
		- array (class "[Ljava.lang.Object;", size: 2)
		- field (class "java.lang.invoke.SerializedLambda", name: "capturedArgs", type: "class [Ljava.lang.Object;")
		- object (class "java.lang.invoke.SerializedLambda", SerializedLambda[capturingClass=class com.vaadin.flow.component.internal.UIInternals, functionalInterfaceMethod=com/vaadin/flow/shared/Registration.remove:()V, implementation=invokeStatic com/vaadin/flow/component/internal/UIInternals.lambda$addListener$3630f8ab$1:(Ljava/util/List;Ljava/lang/Object;)V, instantiatedMethodType=()V, numCaptured=2])
		- field (class "com.vaadin.flow.spring.scopes.VaadinRouteScope$NavigationListener", name: "beforeEnterListener", type: "interface com.vaadin.flow.shared.Registration")
		- object (class "com.vaadin.flow.spring.scopes.VaadinRouteScope$NavigationListener", com.vaadin.flow.spring.scopes.VaadinRouteScope$NavigationListener@5fa5da25)
		- custom writeObject data (class "java.util.HashMap")
		- object (class "java.util.HashMap", {com.vaadin.flow.spring.scopes.VaadinRouteScope$NavigationListener=com.vaadin.flow.spring.scopes.VaadinRouteScope$NavigationListener@5fa5da25})
		- field (class "com.vaadin.flow.server.Attributes", name: "attributes", type: "class java.util.HashMap")
		- object (class "com.vaadin.flow.server.Attributes", com.vaadin.flow.server.Attributes@799ab9a)
		- field (class "com.vaadin.flow.component.Component", name: "attributes", type: "class com.vaadin.flow.server.Attributes")
		- object (class "com.vaadin.flow.component.UI", com.vaadin.flow.component.UI@66d3dee8)
		- custom writeObject data (class "java.util.HashMap")
		- object (class "java.util.HashMap", {0=com.vaadin.flow.component.UI@66d3dee8})
		- custom writeObject data (class "com.vaadin.flow.server.VaadinSession")
		- object (class "com.vaadin.flow.spring.SpringVaadinSession", com.vaadin.flow.spring.SpringVaadinSession@3c4721dd)
		- custom writeObject data (class "java.util.HashMap")
		- root object (class "java.util.HashMap", {com.vaadin.flow.server.VaadinSession.springServlet=com.vaadin.flow.spring.SpringVaadinSession@3c4721dd, springServlet.lock=java.util.concurrent.locks.ReentrantLock@64617a3a[Unlocked], org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken@7e593620, clusterKey=249d6e06-c49f-46f8-8bec-a8c5aa7362c4_SOURCE:F3FF33B25DF4AC58D816C327D0D1B344, SPRING_SECURITY_SAVED_REQUEST=DefaultSavedRequest [http://localhost:8080/?continue]})
	End Track ID: 140

Versions

Reproduced on Vaadin 24.3.2, jdk17, spring-boot 3.2.1 . See attached minmal project

@jorgheymans
Copy link
Author

testproject.zip

@mcollovati
Copy link
Collaborator

It looks like a bug in SpringSecurityAutoConfiguration and VaadinWebSecurity. The method that defines the AnnotatedViewAccessChecker bean takes a@Lazy parameter, so Spring creates a proxy for it that is not serializable.

We should probably remove the @Lazy annotation and inject ObjectProvider<NavigationAccessControl> instead of NavigationAccessControl in VaadinWebSecurity.

mcollovati added a commit that referenced this issue Jan 15, 2024
For parameters with Lazy annotation, Spring generates a not-serializable proxy.
Since some security beans are used inside Flow listeners, they should be fully
serializable (or defined transient, if possible).
This change removes the unnecessary Lazy annotaions, moving the lazy evaluation
to VaadinWebSecurity.

Fixes #18458
@mcollovati mcollovati moved this from 🆕 Needs triage to 🔖 Normal Priority (P2) in Vaadin Flow bugs & maintenance (Vaadin 10+) Jan 15, 2024
@mcollovati mcollovati self-assigned this Jan 15, 2024
tltv pushed a commit that referenced this issue Jan 22, 2024
* fix: remove Lazy annotation from Flow security beans

For parameters with Lazy annotation, Spring generates a not-serializable proxy.
Since some security beans are used inside Flow listeners, they should be fully
serializable (or defined transient, if possible).
This change removes the unnecessary Lazy annotaions, moving the lazy evaluation
to VaadinWebSecurity.

Fixes #18458

* Apply suggestions from code review

Co-authored-by: Peter Czuczor <61667986+czp13@users.noreply.github.com>

* set proxyBeanMethods to false

* use try-with-resource for serialization/deserialization

---------

Co-authored-by: Peter Czuczor <61667986+czp13@users.noreply.github.com>
@github-project-automation github-project-automation bot moved this from 🟢Ready to Go to Done in Vaadin Flow ongoing work (Vaadin 10+) Jan 22, 2024
@github-project-automation github-project-automation bot moved this from 🔖 Normal Priority (P2) to ✅ Closed in Vaadin Flow bugs & maintenance (Vaadin 10+) Jan 22, 2024
vaadin-bot pushed a commit that referenced this issue Jan 22, 2024
* fix: remove Lazy annotation from Flow security beans

For parameters with Lazy annotation, Spring generates a not-serializable proxy.
Since some security beans are used inside Flow listeners, they should be fully
serializable (or defined transient, if possible).
This change removes the unnecessary Lazy annotaions, moving the lazy evaluation
to VaadinWebSecurity.

Fixes #18458

* Apply suggestions from code review

Co-authored-by: Peter Czuczor <61667986+czp13@users.noreply.github.com>

* set proxyBeanMethods to false

* use try-with-resource for serialization/deserialization

---------

Co-authored-by: Peter Czuczor <61667986+czp13@users.noreply.github.com>
vaadin-bot added a commit that referenced this issue Jan 22, 2024
* fix: remove Lazy annotation from Flow security beans

For parameters with Lazy annotation, Spring generates a not-serializable proxy.
Since some security beans are used inside Flow listeners, they should be fully
serializable (or defined transient, if possible).
This change removes the unnecessary Lazy annotaions, moving the lazy evaluation
to VaadinWebSecurity.

Fixes #18458

* Apply suggestions from code review



* set proxyBeanMethods to false

* use try-with-resource for serialization/deserialization

---------

Co-authored-by: Marco Collovati <marco@vaadin.com>
Co-authored-by: Peter Czuczor <61667986+czp13@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

2 participants