-
Notifications
You must be signed in to change notification settings - Fork 99
feat: Always use the security context from VaadinSession when one is available #907
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
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
b0cb13a
Always use the security context from VaadinSession when one is availa…
Artur- 0484d59
Maybe fix some test issues
Artur- d6450cc
Fix test
Artur- bec48b8
Fix test
Artur- 36e6f6f
Merge branch 'master' into use-security-context-from-access
mshabarov 3d8932d
Apply suggestions from code review
Artur- 8bf6e8a
Docs
Artur- File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
...ng-security-flow/src/main/java/com/vaadin/flow/spring/flowsecurity/views/Broadcaster.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| /* | ||
| * Copyright 2000-2021 Vaadin Ltd. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
| * use this file except in compliance with the License. You may obtain a copy of | ||
| * the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
| * License for the specific language governing permissions and limitations under | ||
| * the License. | ||
| */ | ||
| package com.vaadin.flow.spring.flowsecurity.views; | ||
|
|
||
| import com.vaadin.flow.component.Component; | ||
| import com.vaadin.flow.component.ComponentEvent; | ||
| import com.vaadin.flow.component.ComponentEventBus; | ||
| import com.vaadin.flow.component.ComponentEventListener; | ||
| import com.vaadin.flow.component.html.Div; | ||
| import com.vaadin.flow.shared.Registration; | ||
|
|
||
| public class Broadcaster { | ||
|
|
||
| private static Broadcaster instance = new Broadcaster(); | ||
|
|
||
| private ComponentEventBus router = new ComponentEventBus(new Div()); | ||
|
|
||
| public static class RefreshEvent extends ComponentEvent<Component> { | ||
| public RefreshEvent() { | ||
| super(new Div(), false); | ||
| } | ||
| } | ||
|
|
||
| public static void sendMessage() { | ||
| instance.router.fireEvent(new RefreshEvent()); | ||
| } | ||
|
|
||
| public static Registration addMessageListener( | ||
| ComponentEventListener<RefreshEvent> listener) { | ||
| return instance.router.addListener(RefreshEvent.class, listener); | ||
| } | ||
|
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,23 +3,34 @@ | |
| import java.io.ByteArrayInputStream; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.math.BigDecimal; | ||
| import java.time.LocalDateTime; | ||
| import java.util.concurrent.Executor; | ||
|
|
||
| import javax.annotation.security.PermitAll; | ||
|
|
||
| import com.vaadin.flow.component.AttachEvent; | ||
| import com.vaadin.flow.component.ClickEvent; | ||
| import com.vaadin.flow.component.DetachEvent; | ||
| import com.vaadin.flow.component.Text; | ||
| import com.vaadin.flow.component.UI; | ||
| import com.vaadin.flow.component.button.Button; | ||
| import com.vaadin.flow.component.dialog.Dialog; | ||
| import com.vaadin.flow.component.html.H4; | ||
| import com.vaadin.flow.component.html.Image; | ||
| import com.vaadin.flow.component.html.Paragraph; | ||
| import com.vaadin.flow.component.html.Span; | ||
| import com.vaadin.flow.component.notification.Notification; | ||
| import com.vaadin.flow.component.orderedlayout.VerticalLayout; | ||
| import com.vaadin.flow.component.upload.Upload; | ||
| import com.vaadin.flow.router.PageTitle; | ||
| import com.vaadin.flow.router.Route; | ||
| import com.vaadin.flow.server.StreamResource; | ||
| import com.vaadin.flow.shared.Registration; | ||
| import com.vaadin.flow.spring.flowsecurity.SecurityUtils; | ||
| import com.vaadin.flow.spring.flowsecurity.service.BankService; | ||
|
|
||
| import org.springframework.security.concurrent.DelegatingSecurityContextExecutor; | ||
|
|
||
| @Route(value = "private", layout = MainView.class) | ||
| @PageTitle("Private View") | ||
| @PermitAll | ||
|
|
@@ -28,15 +39,27 @@ public class PrivateView extends VerticalLayout { | |
| private BankService bankService; | ||
| private Span balanceSpan = new Span(); | ||
| private SecurityUtils utils; | ||
| private DelegatingSecurityContextExecutor executor; | ||
| private Registration registration; | ||
|
|
||
| public PrivateView(BankService bankService, SecurityUtils utils) { | ||
| public PrivateView(BankService bankService, SecurityUtils utils, | ||
| Executor executor) { | ||
| this.bankService = bankService; | ||
| this.utils = utils; | ||
| this.executor = new DelegatingSecurityContextExecutor(executor); | ||
|
|
||
| updateBalanceText(); | ||
| balanceSpan.setId("balanceText"); | ||
| add(balanceSpan); | ||
| add(new Button("Apply for a loan", this::applyForLoan)); | ||
| add(new Button("Apply for a huge loan", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah it is for manual testing only. At least for now |
||
| this::applyForHugeLoanUsingExecutor)); | ||
|
|
||
| Button globalRefresh = new Button("Send global refresh event", | ||
| e -> Broadcaster.sendMessage()); | ||
| globalRefresh.setId("sendRefresh"); | ||
| add(globalRefresh); | ||
|
|
||
| Upload upload = new Upload(); | ||
| ByteArrayOutputStream imageStream = new ByteArrayOutputStream(); | ||
| upload.setReceiver((filename, mimeType) -> { | ||
|
|
@@ -57,16 +80,57 @@ public PrivateView(BankService bankService, SecurityUtils utils) { | |
| add(upload); | ||
| } | ||
|
|
||
| @Override | ||
| protected void onAttach(AttachEvent attachEvent) { | ||
| super.onAttach(attachEvent); | ||
| attachEvent.getUI().setPollInterval(1000); | ||
| registration = Broadcaster.addMessageListener(e -> { | ||
| getUI().get().access(() -> this.updateBalanceText()); | ||
| }); | ||
| } | ||
|
|
||
| @Override | ||
| protected void onDetach(DetachEvent detachEvent) { | ||
| super.onDetach(detachEvent); | ||
| detachEvent.getUI().setPollInterval(-1); | ||
| registration.remove(); | ||
| } | ||
|
|
||
| private void updateBalanceText() { | ||
| String name = utils.getAuthenticatedUserInfo().getFullName(); | ||
| BigDecimal balance = bankService.getBalance(); | ||
| this.balanceSpan.setText(String.format( | ||
| "Hello %s, your bank account balance is $%s.", name, balance)); | ||
|
|
||
| } | ||
|
|
||
| private void applyForLoan(ClickEvent<Button> e) { | ||
| bankService.applyForLoan(); | ||
| updateBalanceText(); | ||
| } | ||
|
|
||
| private void applyForHugeLoanUsingExecutor(ClickEvent<Button> e) { | ||
| Dialog waitDialog = new Dialog(); | ||
| waitDialog.add(new Text("Processing loan application...")); | ||
| waitDialog.open(); | ||
| UI ui = getUI().get(); | ||
| Runnable runnable = new Runnable() { | ||
| @Override | ||
| public void run() { | ||
| try { | ||
| bankService.applyForHugeLoan(); | ||
| } catch (Exception e) { | ||
| getUI().get().access(() -> { | ||
| Notification | ||
| .show("Application failed: " + e.getMessage()); | ||
| }); | ||
|
|
||
| } | ||
| ui.access(() -> { | ||
| updateBalanceText(); | ||
| waitDialog.close(); | ||
| }); | ||
| } | ||
| }; | ||
| executor.execute(runnable); | ||
| } | ||
| } | ||
122 changes: 122 additions & 0 deletions
122
...st-spring-security-flow/src/test/java/com/vaadin/flow/spring/flowsecurity/AbstractIT.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| /* | ||
| * Copyright 2000-2021 Vaadin Ltd. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
| * use this file except in compliance with the License. You may obtain a copy of | ||
| * the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
| * License for the specific language governing permissions and limitations under | ||
| * the License. | ||
| */ | ||
| package com.vaadin.flow.spring.flowsecurity; | ||
Artur- marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| import com.vaadin.flow.component.login.testbench.LoginFormElement; | ||
| import com.vaadin.flow.component.login.testbench.LoginOverlayElement; | ||
| import com.vaadin.flow.testutil.ChromeBrowserTest; | ||
| import com.vaadin.testbench.TestBenchElement; | ||
|
|
||
| import org.junit.After; | ||
| import org.junit.Assert; | ||
| import org.openqa.selenium.WebDriver; | ||
|
|
||
| public abstract class AbstractIT extends ChromeBrowserTest { | ||
|
|
||
| private static final String ROOT_PAGE_HEADER_TEXT = "Welcome to the Java Bank of Vaadin"; | ||
| private static final String ANOTHER_PUBLIC_PAGE_HEADER_TEXT = "Another public view for testing"; | ||
| private static final int SERVER_PORT = 8888; | ||
|
|
||
| @Override | ||
| protected int getDeploymentPort() { | ||
| return SERVER_PORT; | ||
| } | ||
|
|
||
| @Override | ||
| protected String getRootURL() { | ||
| return super.getRootURL(); // + "/context"; | ||
| } | ||
|
|
||
| @After | ||
| public void tearDown() { | ||
| if (getDriver() != null) { | ||
| checkForBrowserErrors(); | ||
| } | ||
| } | ||
|
|
||
| private void checkForBrowserErrors() { | ||
| checkLogsForErrors(msg -> { | ||
| return msg.contains( | ||
| "admin-only/secret.txt - Failed to load resource: the server responded with a status of 403"); | ||
| }); | ||
| } | ||
|
|
||
| protected void open(String path) { | ||
| open(path, getDriver()); | ||
| } | ||
|
|
||
| protected void open(String path, WebDriver driver) { | ||
| driver.get(getRootURL() + "/" + path); | ||
| } | ||
|
|
||
| protected void loginUser() { | ||
| login("john", "john"); | ||
| } | ||
|
|
||
| protected void loginAdmin() { | ||
| login("emma", "emma"); | ||
| } | ||
|
|
||
| protected void login(String username, String password) { | ||
| assertLoginViewShown(); | ||
|
|
||
| LoginFormElement form = $(LoginOverlayElement.class).first() | ||
| .getLoginForm(); | ||
| form.getUsernameField().setValue(username); | ||
| form.getPasswordField().setValue(password); | ||
| form.submit(); | ||
| waitUntilNot(driver -> $(LoginOverlayElement.class).exists()); | ||
| } | ||
|
|
||
| protected void assertLoginViewShown() { | ||
| assertPathShown("login"); | ||
| waitUntil(driver -> $(LoginOverlayElement.class).exists()); | ||
| } | ||
|
|
||
| protected void assertRootPageShown() { | ||
| waitUntil(drive -> $("h1").attribute("id", "header").exists()); | ||
| String headerText = $("h1").id("header").getText(); | ||
| Assert.assertEquals(ROOT_PAGE_HEADER_TEXT, headerText); | ||
| } | ||
|
|
||
| protected void assertAnotherPublicPageShown() { | ||
| waitUntil(drive -> $("h1").attribute("id", "header").exists()); | ||
| String headerText = $("h1").id("header").getText(); | ||
| Assert.assertEquals(ANOTHER_PUBLIC_PAGE_HEADER_TEXT, headerText); | ||
| } | ||
|
|
||
| protected void assertPrivatePageShown(String fullName) { | ||
| assertPathShown("private"); | ||
| waitUntil(driver -> $("span").attribute("id", "balanceText").exists()); | ||
| String balance = $("span").id("balanceText").getText(); | ||
| Assert.assertTrue(balance.startsWith( | ||
| "Hello " + fullName + ", your bank account balance is $")); | ||
| } | ||
|
|
||
| protected void assertAdminPageShown(String fullName) { | ||
| assertPathShown("admin"); | ||
| TestBenchElement welcome = waitUntil(driver -> $("*").id("welcome")); | ||
| String welcomeText = welcome.getText(); | ||
| Assert.assertEquals("Welcome to the admin page, " + fullName, | ||
| welcomeText); | ||
| } | ||
|
|
||
| protected void assertPathShown(String path) { | ||
| waitUntil(driver -> driver.getCurrentUrl() | ||
| .equals(getRootURL() + "/" + path)); | ||
| } | ||
|
|
||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.