Skip to content

Commit

Permalink
refactor: Make ViewAccessControl more extensible
Browse files Browse the repository at this point in the history
Makes it possible to fetch the principal and roles from other sources than the HTTP request
  • Loading branch information
Artur- committed May 4, 2022
1 parent 05994fd commit 60183cb
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,24 @@
*/
package com.vaadin.flow.server.auth;

import java.security.Principal;
import java.util.function.Function;

import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpSession;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterListener;
import com.vaadin.flow.router.NotFoundException;
import com.vaadin.flow.server.VaadinRequest;
import com.vaadin.flow.server.VaadinServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Checks access to views using an {@link AccessAnnotationChecker}.
* <p>
Expand Down Expand Up @@ -141,28 +146,20 @@ public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
return;
}
Class<?> targetView = beforeEnterEvent.getNavigationTarget();
VaadinRequest request = VaadinRequest.getCurrent();

VaadinServletRequest vaadinServletRequest = VaadinServletRequest
.getCurrent();
if (vaadinServletRequest == null) {
// This is in a background thread and we cannot access the request
// to check access
getLogger().warn("Preventing navigation to " + targetView.getName()
+ " because no HTTP request is available for checking access.");
beforeEnterEvent.rerouteToError(NotFoundException.class);
return;
}
Principal principal = getPrincipal(request);
Function<String, Boolean> rolesChecker = getRolesChecker(request);

HttpServletRequest httpServletRequest = vaadinServletRequest
.getHttpServletRequest();
getLogger().debug("Checking access for view {}", targetView.getName());
if (loginView != null && targetView == loginView) {
getLogger().debug("Allowing access for login view {}",
targetView.getName());
return;
}

boolean hasAccess = accessAnnotationChecker.hasAccess(targetView,
httpServletRequest);
principal, rolesChecker);

if (hasAccess) {
getLogger().debug("Allowed access to view {}",
Expand All @@ -171,10 +168,23 @@ public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
}

getLogger().debug("Denied access to view {}", targetView.getName());
if (httpServletRequest.getUserPrincipal() == null) {
httpServletRequest.getSession()
.setAttribute(SESSION_STORED_REDIRECT, beforeEnterEvent
.getLocation().getPathWithQueryParameters());
if (principal == null) {
HttpSession session = (request instanceof VaadinServletRequest)
? ((VaadinServletRequest) request).getSession()
: null;
if (session != null) {
session.setAttribute(SESSION_STORED_REDIRECT, beforeEnterEvent
.getLocation().getPathWithQueryParameters());
} else {
if (request == null) {
getLogger().debug(
"Unable to store redirect in session because no request is available");
} else {
getLogger().debug(
"Unable to store redirect in session because request is of type {}",
request.getClass().getName());
}
}
if (loginView != null) {
beforeEnterEvent.forwardTo(loginView);
} else {
Expand All @@ -199,6 +209,40 @@ public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
}
}

/**
* Gets a function for checking roles for the currently logged in user.
*
* @param request
* the current request or {@code null} if no request is in
* progress (e.g. in a background thread)
* @return a function which takes a role name and returns {@code true} if
* the user is included in that role
*/
protected Function<String, Boolean> getRolesChecker(VaadinRequest request) {
if (request == null) {
return role -> false;
}

return request::isUserInRole;
}

/**
* Gets the principal for the currently logged in user.
*
* @param request
* the current request or {@code null} if no request is in
* progress (e.g. in a background thread)
* @return a representation of the currently logged in user or {@code null}
* if no user is currently logged in
*
*/
protected Principal getPrincipal(VaadinRequest request) {
if (request == null) {
return null;
}
return request.getUserPrincipal();
}

private boolean isProductionMode(BeforeEnterEvent beforeEnterEvent) {
return beforeEnterEvent.getUI().getSession().getConfiguration()
.isProductionMode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,6 @@ public void init() {
this.viewAccessChecker.setLoginView(TestLoginView.class);
}

@Test
public void cannotUseWithoutServlet() {
Result request = setupRequest(AnonymousAllowedView.class, null, true);
CurrentInstance.clearAll();
this.viewAccessChecker.beforeEnter(request.event);
Assert.assertEquals(NotFoundException.class, request.getRerouteError());
}

@Test
public void anonymousAccessToAnonymousViewAllowed() {
Result result = checkAccess(AnonymousAllowedView.class, null);
Expand Down Expand Up @@ -456,7 +448,8 @@ public void loggedInUserRoleAccess_to_noAnnotationAnonymousAllowedByGrandParentV
public void loggedInUserRoleAccess_to_noAnnotationPermitAllByGrandParentView_allowed() {
Result result = checkAccess(
NoAnnotationPermitAllByGrandParentView.class, User.NORMAL_USER);
Assert.assertTrue(result.wasTargetViewRendered());
Assert.assertTrue("Target view should have been rendered",
result.wasTargetViewRendered());
}

@Test
Expand Down Expand Up @@ -660,6 +653,8 @@ private Result setupRequest(Class navigationTarget, User user,
.createRequest(principal, roles);
Mockito.when(vaadinServletRequest.getHttpServletRequest())
.thenReturn(httpServletRequest);
Mockito.when(vaadinServletRequest.getUserPrincipal())
.thenReturn(httpServletRequest.getUserPrincipal());
CurrentInstance.set(VaadinRequest.class, vaadinServletRequest);

Router router = Mockito.mock(Router.class);
Expand Down

0 comments on commit 60183cb

Please sign in to comment.