Skip to content

Commit

Permalink
feat: Add helpers for using current request and simplify naming (#10767
Browse files Browse the repository at this point in the history
…) (#10860)

Co-authored-by: Artur <artur@vaadin.com>
  • Loading branch information
vaadin-bot and Artur- committed Apr 30, 2021
1 parent 7def22d commit f11deec
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import javax.annotation.security.RolesAllowed;
import javax.servlet.http.HttpServletRequest;

import com.vaadin.flow.server.VaadinServletRequest;

/**
* Checks if a given user has access to a given method.
* <p>
Expand All @@ -52,6 +54,46 @@
*/
public class AccessAnnotationChecker implements Serializable {

/**
* Checks if the user defined by the current active servlet request (using
* {@link HttpServletRequest#getUserPrincipal()} and
* {@link HttpServletRequest#isUserInRole(String)} has access to the given
* method.
*
* @param method
* the method to check access to
* @return {@code true} if the user has access to the given method,
* {@code false} otherwise
*/
public boolean hasAccess(Method method) {
VaadinServletRequest request = VaadinServletRequest.getCurrent();
if (request == null) {
throw new IllegalStateException(
"No request is available. This method can only be used with an active VaadinServletRequest");
}
return hasAccess(method, request);
}

/**
* Checks if the user defined by the current active servlet request (using
* {@link HttpServletRequest#getUserPrincipal()} and
* {@link HttpServletRequest#isUserInRole(String)} has access to the given
* class.
*
* @param cls
* the class to check access to
* @return {@code true} if the user has access to the given method,
* {@code false} otherwise
*/
public boolean hasAccess(Class<?> cls) {
VaadinServletRequest request = VaadinServletRequest.getCurrent();
if (request == null) {
throw new IllegalStateException(
"No request is available. This method can only be used with an active VaadinServletRequest");
}
return hasAccess(cls, request);
}

/**
*
* Checks if the user defined by the request (using
Expand All @@ -66,9 +108,11 @@ public class AccessAnnotationChecker implements Serializable {
* @return {@code true} if the user has access to the given method,
* {@code false} otherwise
*/
public boolean annotationAllowsAccess(Method method,
HttpServletRequest request) {
return annotationAllowsAccess(method, request.getUserPrincipal(),
public boolean hasAccess(Method method, HttpServletRequest request) {
if (request == null) {
throw new IllegalArgumentException("The request cannot be null");
}
return hasAccess(method, request.getUserPrincipal(),
request::isUserInRole);
}

Expand All @@ -86,10 +130,12 @@ public boolean annotationAllowsAccess(Method method,
* @return {@code true} if the user has access to the given method,
* {@code false} otherwise
*/
public boolean annotationAllowsAccess(Class<?> cls,
HttpServletRequest request) {
return annotationAllowsAccess(getSecurityTarget(cls),
request.getUserPrincipal(), request::isUserInRole);
public boolean hasAccess(Class<?> cls, HttpServletRequest request) {
if (request == null) {
throw new IllegalArgumentException("The request cannot be null");
}
return hasAccess(cls, request.getUserPrincipal(),
request::isUserInRole);
}

/**
Expand All @@ -105,10 +151,27 @@ public boolean annotationAllowsAccess(Class<?> cls,
* @return {@code true} if the user has access to the given method,
* {@code false} otherwise
*/
public boolean annotationAllowsAccess(Method method, Principal principal,
public boolean hasAccess(Method method, Principal principal,
Function<String, Boolean> roleChecker) {
return annotationAllowsAccess(getSecurityTarget(method), principal,
roleChecker);
return hasAccess(getSecurityTarget(method), principal, roleChecker);
}

/**
* Checks if the user defined by the given {@link Principal} and role
* checker has access to the given class.
*
* @param cls
* the class to check access to
* @param principal
* the principal of the user
* @param roleChecker
* a function that can answer if a user has a given role
* @return {@code true} if the user has access to the given method,
* {@code false} otherwise
*/
public boolean hasAccess(Class<?> cls, Principal principal,
Function<String, Boolean> roleChecker) {
return hasAccess(getSecurityTarget(cls), principal, roleChecker);
}

/**
Expand Down Expand Up @@ -145,9 +208,8 @@ public AnnotatedElement getSecurityTarget(Class<?> cls) {
return cls;
}

private boolean annotationAllowsAccess(
AnnotatedElement annotatedClassOrMethod, Principal principal,
Function<String, Boolean> roleChecker) {
private boolean hasAccess(AnnotatedElement annotatedClassOrMethod,
Principal principal, Function<String, Boolean> roleChecker) {
if (annotatedClassOrMethod.isAnnotationPresent(DenyAll.class)) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

import javax.servlet.http.HttpServletRequest;

import com.vaadin.flow.internal.CurrentInstance;
import com.vaadin.flow.server.VaadinRequest;
import com.vaadin.flow.server.VaadinServletRequest;
import com.vaadin.flow.server.auth.AccessControlTestClasses.AnonymousAllowedClass;
import com.vaadin.flow.server.auth.AccessControlTestClasses.DenyAllClass;
import com.vaadin.flow.server.auth.AccessControlTestClasses.NoAnnotationClass;
Expand Down Expand Up @@ -298,6 +301,43 @@ public void adminRoleAccessAllowed() throws Exception {
false);
}

@Test(expected = IllegalStateException.class)
public void hasClassAccessNoCurrentRequest() {
CurrentInstance.clearAll();
accessAnnotationChecker.hasAccess(AnonymousAllowedClass.class);
}

@Test(expected = IllegalStateException.class)
public void hasMethodAccessNoCurrentRequest() throws Exception {
CurrentInstance.clearAll();
accessAnnotationChecker
.hasAccess(AnonymousAllowedClass.class.getMethod("permitAll"));
}

@Test
public void hasClassAccessUsingCurrentRequest() {
try {
CurrentInstance.set(VaadinRequest.class, new VaadinServletRequest(
createRequest(USER_PRINCIPAL), null));
Assert.assertTrue(
accessAnnotationChecker.hasAccess(PermitAllClass.class));
} finally {
CurrentInstance.clearAll();
}
}

@Test
public void hasMethodAccessUsingCurrentRequest() throws Exception {
try {
CurrentInstance.set(VaadinRequest.class, new VaadinServletRequest(
createRequest(USER_PRINCIPAL), null));
Assert.assertTrue(accessAnnotationChecker
.hasAccess(PermitAllClass.class.getMethod("permitAll")));
} finally {
CurrentInstance.clearAll();
}
}

private HttpServletRequest createRequest(Principal userPrincipal,
String... roles) {
Set<String> roleSet = new HashSet<>();
Expand All @@ -323,8 +363,8 @@ private void verifyMethodAccessAllowed(Class<?> endpointClass,
Assert.assertEquals("Expected " + endpointClass.getSimpleName()
+ "." + endpointMethod + " to "
+ (expectedResult ? "be" : "NOT to be") + " accessible",
expectedResult, accessAnnotationChecker
.annotationAllowsAccess(method, request));
expectedResult,
accessAnnotationChecker.hasAccess(method, request));
}
}

Expand All @@ -335,7 +375,7 @@ private void verifyClassAccessAllowed(Class<?> cls,
"Expected " + cls.getSimpleName() + " to "
+ (expectedResult ? "be" : "NOT to be") + " accessible",
expectedResult,
accessAnnotationChecker.annotationAllowsAccess(cls, request));
accessAnnotationChecker.hasAccess(cls, request));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public boolean isAnonymousEndpoint(HttpServletRequest request) {
}

return accessChecker.getAccessAnnotationChecker()
.annotationAllowsAccess(method.get(), null, role -> false);
.hasAccess(method.get(), null, role -> false);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public String check(Method method, HttpServletRequest request) {
return ACCESS_DENIED_MSG;
}

if (accessAnnotationChecker.annotationAllowsAccess(method, request)) {
if (accessAnnotationChecker.hasAccess(method, request)) {
return null;
}

Expand Down

0 comments on commit f11deec

Please sign in to comment.