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

feat: add documentation on impersonation #4098

Open
wants to merge 1 commit into
base: latest
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions articles/flow/security/enabling-security.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -517,4 +517,72 @@

Vaadin strongly recommends not to mix Spring's URL-pattern-based HTTP security and this view-based access control mechanism targeting the same views. Doing so might cause unwanted access configurations, and would be an unnecessary complication in the authorization of views.

== Spring Impersonation With Vaadin

Check warning on line 520 in articles/flow/security/enabling-security.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.HeadingCase] 'Spring Impersonation With Vaadin' should be in title case. Raw Output: {"message": "[Vaadin.HeadingCase] 'Spring Impersonation With Vaadin' should be in title case.", "location": {"path": "articles/flow/security/enabling-security.adoc", "range": {"start": {"line": 520, "column": 4}}}, "severity": "WARNING"}

A common use-case for secured applications is that a user has an issue and that the admin/super users can log in as the user to see the issue and help.
It can be helpful for use cases such as customer support analysis where the analyst can access the system as the real user.

As the insecure (security breach) solution would be asking for the customer's password or getting it from the database should not be used, Spring Security has the impersonation feature that can be used instead.
By using this the system knows who has really logged in and it can be used to track the impersonators action if there's an audit log in place.

To add the impersonation for a Vaadin application create the [classname]`SwitchUserFilter` bean as follows:

[source,java]
----
@Bean
@DependsOn("VaadinSecurityContextHolderStrategy")
public SwitchUserFilter switchUserFilter() {
SwitchUserFilter filter = new SwitchUserFilter();
filter.setUserDetailsService(userDetailsService());
filter.setSwitchUserMatcher(antMatcher(HttpMethod.GET, "/impersonate"));
filter.setExitUserMatcher(antMatcher(HttpMethod.GET, "/impersonate/exit"));
filter.setTargetUrl("/");
return filter;
}
----

[NOTE]
The bean should depend on `VaadinSecurityContextHolderStrategy` bean.
If the [classname]`SwitchUserFilter` is initialized first the wrong security holder is used and the feature does not work.

To secure the impersonation endpoints add to the [classname]`VaadinWebSecurity` implementation [methodname]`configure(HttpSecurity http)` the matchers:

[source,java]
----
@Override
protected void configure(HttpSecurity http) throws Exception {
// Authorize impersonation for admin/impersonated admin
http.authorizeHttpRequests(auth -> auth.requestMatchers(new AntPathRequestMatcher("/impersonate")).hasAnyRole("ADMIN", "PREVIOUS_ADMINISTRATOR"));
http.authorizeHttpRequests(auth -> auth.requestMatchers(new AntPathRequestMatcher("/impersonate/exit")).hasRole("PREVIOUS_ADMINISTRATOR"));

// Set default security policy that permits Vaadin internal requests and
// denies all other
super.configure(http);
// Other configurations
}
----

This allows users with the `ADMIN` role (or impersonating admin) to call the impersonate endpoint.

To impersonate a user, a call to the `impersonate` url needs to be done.

Check failure on line 567 in articles/flow/security/enabling-security.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'url'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'url'?", "location": {"path": "articles/flow/security/enabling-security.adoc", "range": {"start": {"line": 567, "column": 52}}}, "severity": "ERROR"}

[source,java]
----
Button impersonate = new Button("Impersonate user", e ->
getUI().ifPresent(ui -> ui.getPage().setLocation("/impersonate?username=user"))
);
----

This would have the admin impersonate the `user` account without the need to have knowledge of the password.

To exit impersonation just call the exit url:

Check warning on line 578 in articles/flow/security/enabling-security.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.JustSimply] Avoid using 'just'. It may be insensitive. Raw Output: {"message": "[Vaadin.JustSimply] Avoid using 'just'. It may be insensitive.", "location": {"path": "articles/flow/security/enabling-security.adoc", "range": {"start": {"line": 578, "column": 23}}}, "severity": "WARNING"}

Check failure on line 578 in articles/flow/security/enabling-security.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'url'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'url'?", "location": {"path": "articles/flow/security/enabling-security.adoc", "range": {"start": {"line": 578, "column": 42}}}, "severity": "ERROR"}

[source,java]
----
Button exitImpersonation = new Button("Exit impersonation", e ->
getUI().ifPresent(ui -> ui.getPage().setLocation("/impersonate/exit"))
);
----


[discussion-id]`4C8D835D-4E6E-4D81-BEA1-A865FEB17BAD`
Loading