From 201b057003d731f7b99895f40ac11c2d96cc12a7 Mon Sep 17 00:00:00 2001 From: Ondro Mihalyi Date: Thu, 28 Mar 2024 14:43:02 +0100 Subject: [PATCH] Fixes #262: Clarify using hasAccessToWebResource with no methods Signed-off-by:Ondro Mihalyi --- .../security/enterprise/SecurityContext.java | 45 +++++++++----- spec/src/main/asciidoc/securityContext.adoc | 60 ++++++++++++++++++- 2 files changed, 86 insertions(+), 19 deletions(-) diff --git a/api/src/main/java/jakarta/security/enterprise/SecurityContext.java b/api/src/main/java/jakarta/security/enterprise/SecurityContext.java index 4758259..3e0b494 100644 --- a/api/src/main/java/jakarta/security/enterprise/SecurityContext.java +++ b/api/src/main/java/jakarta/security/enterprise/SecurityContext.java @@ -22,6 +22,10 @@ import jakarta.security.enterprise.authentication.mechanism.http.AuthenticationParameters; import jakarta.security.enterprise.authentication.mechanism.http.HttpAuthenticationMechanism; +import jakarta.servlet.annotation.HttpConstraint; +import jakarta.servlet.annotation.HttpMethodConstraint; +import jakarta.servlet.annotation.ServletSecurity; +import jakarta.servlet.annotation.ServletSecurity.TransportGuarantee; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -34,10 +38,17 @@ * and Jakarta Enterprise Beans containers. * */ +@ServletSecurity( + value = @HttpConstraint(rolesAllowed = "foo"), + httpMethodConstraints = { + @HttpMethodConstraint(value = "GET", rolesAllowed = "admin"), + @HttpMethodConstraint(value = "POST", rolesAllowed = "admin", + transportGuarantee = TransportGuarantee.CONFIDENTIAL), + }) public interface SecurityContext { /** - * Retrieve the platform-specific java.security.Principal that represents + * Retrieve the platform-specific {@code java.security.Principal} that represents * the name of authenticated caller, or null if the current caller is not authenticated. * * @return Principal representing the name of the current authenticated user, or null if not authenticated. @@ -57,7 +68,7 @@ public interface SecurityContext { * Modifications to the returned Set will not affect the internal Principal Set. * * @param pType Class object representing the type of Principal to return. - * @param The actual type represented by the pType argument + * @param The actual type represented by the {@code pType} argument * * @return Set of Principals of the given type, or an empty set. */ @@ -65,21 +76,21 @@ public interface SecurityContext { /** * Checks whether the authenticated caller is included in the specified logical application "role". - * If the caller is not authenticated, this always returns false. + * If the caller is not authenticated, this always returns {@code false}. * *

* This method can not be used to test for roles that are mapped to specific named Jakarta Servlets or - * named Jakarta Enterprise Beans. For a Servlet an example of this would be the role-name nested in a - * security-role-ref element nested in a servlet element in web.xml. + * named Jakarta Enterprise Beans. For a Servlet an example of this would be the {@code role-name} nested in a + * {@code security-role-ref} element nested in a {@code servlet} element in {@code web.xml}. * *

* Should code in either such Jakarta Servlet or Jakarta Enterprise Bean wish to take such mapped (aka referenced, linked) * roles into account, the facilities for that specific container should be used instead. For instance for Servlet that * would be {@link HttpServletRequest#isUserInRole(String)} and for Jakarta Enterprise Beans that would be - * jakarta.ejb.SessionContext#isCallerInRole(String). + * {@code jakarta.ejb.SessionContext#isCallerInRole(String)}. * - * @param role a String specifying the name of the logical application role - * @return true if the authenticated caller is in the given role, false if the caller is not authentication or + * @param role a {@code String} specifying the name of the logical application role + * @return {@code true} if the authenticated caller is in the given role, false if the caller is not authentication or * is not in the given role. */ boolean isCallerInRole(String role); @@ -109,12 +120,14 @@ public interface SecurityContext { * A caller has access if the web resource is either not protected (constrained), or when it is protected by a role * and the caller is in that role. * - * @param resource the name of the web resource to test access for. This is a URLPatternSpec that - * identifies the application specific web resources to which the permission pertains. For a full specification of this - * pattern see {@link jakarta.security.jacc.WebResourcePermission#WebResourcePermission(String, String)}. - * @param methods one or more methods to check for whether the caller has access to the web resource using one of those methods. + * @param resource the name of the web resource to test access for. This is a {@code URLPatternSpec} that identifies + * the application specific web resources to which the permission pertains. For a full specification of this pattern + * see {@link jakarta.security.jacc.WebResourcePermission#WebResourcePermission(String, String)}. + * @param methods HTTP methods to check for whether the caller has access to the web resource using one of those + * methods. If no methods are provided, this method will return {@code true} only if the caller can access the resource using all HTTP methods * - * @return true if the caller has access to the web resource using one of the given methods, false otherwise. + * @return {@code true} if the caller has access to the web resource using one of the given methods, or using all + * supported HTTP methods, if no method is provided. Otherwise returns {@code false}. */ boolean hasAccessToWebResource(String resource, String... methods); @@ -130,14 +143,14 @@ public interface SecurityContext { * Whether the authentication dialog is to be started or continued depends on the (logical) state of the authentication dialog. If * such dialog is currently in progress, a call to this method will continue it. If such dialog is not in progress a new one will be * started. A new dialog can be forced to be started regardless of one being in progress or not by providing a value of - * true for the {@link AuthenticationParameters#newAuthentication} parameter with this call. + * {@code true} for the {@link AuthenticationParameters#newAuthentication} parameter with this call. * *

* This method requires an {@link HttpServletRequest} and {@link HttpServletResponse} argument to be passed in, and * can therefore only be used in a valid Servlet context. * - * @param request The HttpServletRequest associated with the current web resource invocation. - * @param response The HttpServletResponse associated with the given HttpServletRequest. + * @param request The {@code HttpServletRequest} associated with the current web resource invocation. + * @param response The {@code HttpServletResponse} associated with the given {@code HttpServletRequest}. * @param parameters The parameters that are provided along with a programmatic authentication request, for instance the credentials. * collected by the application for continuing an authentication dialog. * diff --git a/spec/src/main/asciidoc/securityContext.adoc b/spec/src/main/asciidoc/securityContext.adoc index 5820530..b815525 100644 --- a/spec/src/main/asciidoc/securityContext.adoc +++ b/spec/src/main/asciidoc/securityContext.adoc @@ -59,14 +59,68 @@ As an example, consider the following Servlet definition: public class ProtectedServlet extends HttpServlet { ... } ---- -And the following call to _hasAccessToWebResource()_: +And the following calls to _hasAccessToWebResource()_: [source,java] ---- -securityContext.hasAccessToWebResource("/protectedServlet", GET) +securityContext.hasAccessToWebResource("/protectedServlet") ---- -The above _hasAccessToWebResource()_ call would return true if and only if the caller is in role "foo". +[source,java] +---- +securityContext.hasAccessToWebResource("/protectedServlet", "GET") +---- + +[source,java] +---- +securityContext.hasAccessToWebResource("/protectedServlet", "GET", "POST") +---- + +All the above _hasAccessToWebResource()_ calls would return `true` if and only if the caller is in role "foo". + +''' + +As another example, consider the following definition, which gives access to the resource: + +* for the role "bar" only via the GET method +* for the role "foo" via all methods except the GET method + +[source,java] +---- +@WebServlet("/protectedServlet") +@ServletSecurity( + value = @HttpConstraint(rolesAllowed = "foo"), + httpMethodConstraints = { + @HttpMethodConstraint(value = "GET", rolesAllowed = "bar"), + }) +public class ProtectedServlet extends HttpServlet { ... } +---- + +And the following calls to _hasAccessToWebResource()_: + +[source,java] +---- +securityContext.hasAccessToWebResource("/protectedServlet", "GET") +---- + +The above _hasAccessToWebResource()_ call would return `true` if and only if the caller is in role "bar". + +[source,java] +---- +securityContext.hasAccessToWebResource("/protectedServlet", "POST", "PUT") +---- + +The above _hasAccessToWebResource()_ call would return `true` if and only if the caller is in role "foo". + +On the other hand, the following call, with no method arguments: + +[source,java] +---- +securityContext.hasAccessToWebResource("/protectedServlet") +---- + +would always return `false` because no role has access via all HTTP methods - role "bar" has access via the GET method, roles "foo" has access via all other methods but not via the GET. + === Triggering the Authentication Process