diff --git a/api/src/main/java/jakarta/security/jacc/Policy.java b/api/src/main/java/jakarta/security/jacc/Policy.java index 05ebed2..cb27f33 100644 --- a/api/src/main/java/jakarta/security/jacc/Policy.java +++ b/api/src/main/java/jakarta/security/jacc/Policy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Contributors to Eclipse Foundation. All rights reserved. + * Copyright (c) 2023, 2024 Contributors to Eclipse Foundation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -37,9 +37,6 @@ * a given policy context. In a Jakarta EE Servlet environment these contain the transformed security constraints as expressed by XML * in web.xml, via annotations, or which are programmatically set using the Jakarta Servlet APIs. * - *
- * NOTE: DRAFT API. SUBJECT TO CHANGE - * * @author Arjan Tijms */ public interface Policy { diff --git a/api/src/main/java/jakarta/security/jacc/PolicyFactory.java b/api/src/main/java/jakarta/security/jacc/PolicyFactory.java index 9183a93..f4ee5eb 100644 --- a/api/src/main/java/jakarta/security/jacc/PolicyFactory.java +++ b/api/src/main/java/jakarta/security/jacc/PolicyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Contributors to Eclipse Foundation. All rights reserved. + * Copyright (c) 2023, 2024 Contributors to Eclipse Foundation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -19,9 +19,6 @@ * Abstract factory and finder class for obtaining the instance of the class that implements the * PolicyFactory of a provider. The factory will be used to instantiate Policy objects. * - *
- * NOTE: DRAFT API. SUBJECT TO CHANGE - * * @see Policy * * @author Arjan Tijms diff --git a/api/src/main/java/jakarta/security/jacc/PrincipalMapper.java b/api/src/main/java/jakarta/security/jacc/PrincipalMapper.java index 0f84798..f0d60d4 100644 --- a/api/src/main/java/jakarta/security/jacc/PrincipalMapper.java +++ b/api/src/main/java/jakarta/security/jacc/PrincipalMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Contributors to Eclipse Foundation. All rights reserved. + * Copyright (c) 2023, 2024 Contributors to Eclipse Foundation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -37,9 +37,6 @@ * A PrincipalMapper is intended to be used by a {@link Policy}, but should work * outside a {@link Policy} (for instance, during request processing in a Servlet container). * - *
- * NOTE: DRAFT API. SUBJECT TO CHANGE
- *
* @author Arjan Tijms
*/
public interface PrincipalMapper {
diff --git a/spec/src/main/asciidoc/chapters/2_provider-configuration.adoc b/spec/src/main/asciidoc/chapters/2_provider-configuration.adoc
index 8873a96..9e67049 100644
--- a/spec/src/main/asciidoc/chapters/2_provider-configuration.adoc
+++ b/spec/src/main/asciidoc/chapters/2_provider-configuration.adoc
@@ -14,6 +14,26 @@ An application server that supports this contract must allow replacement of the
`jakarta.security.jacc.Policy` object used by the application server for all applications running on it,
in addition to supporting a `jakarta.security.jacc.Policy` object for individual applications.
+Replacement is done via the `jakarta.security.jacc.PolicyFactory` abstract factory class. A
+default static method, `getPolicyFactory` is provided that uses the system property
+`jakarta.security.jacc.PolicyFactory.provider` to locate a concrete implementation. The
+container or an application can alternatively set a custom `PolicyFactory` using the
+`setPolicyFactory` method. In that case the `PolicyFactory` implementation
+can come from a container specific configuration, or in case of the Servlet Container
+from the web application's servlet context initialization parameter (context-param in web.xml) `jakarta.security.jacc.PolicyFactory.provider`.
+
+If the `PolicyFactory` has a public constructor with one argument of type `PolicyFactory`,
+then the container should call this constructor with as argument the
+ `PolicyFactory` instance that is being replaced. This allows a replacement `PolicyFactory` to wrap
+ the existing one and selectively provide extra functionality.
+
+From this factory class a concrete implementation of the Policy of type `jakarta.security.jacc.Policy` can be
+obtained using the method `getPolicy`.
+
+In addition to replacing the `PolicyFactory`, the default `PolicyFactory` must also allow replacing just the
+`Policy` instance. This is detailed below in <
+ * The role "foo" is required to access this Servlet. "bar" is a role assigned by the
+ * native identity store, "kaz" doesn't exist (but we should still be able to test for it).
+ *
+ */
+@WebServlet("/protectedServlet/*")
+@DeclareRoles("bar")
+@ServletSecurity(@HttpConstraint(rolesAllowed = "foo"))
+public class ProtectedServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ response.getWriter().write("This is a servlet \n");
+
+ String webName = null;
+ if (request.getUserPrincipal() != null) {
+ webName = request.getUserPrincipal().getName();
+ }
+
+ response.getWriter().write("web username: " + webName + "\n");
+
+ response.getWriter().write("web user has role \"foo\": " + request.isUserInRole("foo") + "\n");
+ response.getWriter().write("web user has role \"bar\": " + request.isUserInRole("bar") + "\n");
+ response.getWriter().write("web user has role \"kaz\": " + request.isUserInRole("kaz") + "\n");
+ }
+
+}
diff --git a/tck/app-custom-policyfactory/src/main/java/ee/jakarta/tck/authorization/test/TestPolicy.java b/tck/app-custom-policyfactory/src/main/java/ee/jakarta/tck/authorization/test/TestPolicy.java
new file mode 100644
index 0000000..23739d4
--- /dev/null
+++ b/tck/app-custom-policyfactory/src/main/java/ee/jakarta/tck/authorization/test/TestPolicy.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+package ee.jakarta.tck.authorization.test;
+
+import jakarta.security.jacc.Policy;
+import jakarta.security.jacc.WebResourcePermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.util.logging.Logger;
+import javax.security.auth.Subject;
+
+/**
+ * Policy implementation that uses a custom permission check
+ * to grant access to {@code /protectedServlet/[*]/test} to
+ * the unauthenticated caller.
+ */
+public class TestPolicy implements Policy {
+
+ private static final Logger LOGGER = Logger.getLogger(TestPolicy.class.getName());
+
+ private final Policy originalPolicy;
+
+ public TestPolicy(Policy policy) {
+ this.originalPolicy = policy;
+ }
+
+ public boolean implies(Permission permissionToBeChecked, Subject subject) {
+ LOGGER.info(permissionToBeChecked.toString());
+ LOGGER.info(subject.toString());
+
+ // First try our custom permission checking
+ if (impliesCustom(permissionToBeChecked)) {
+ return true;
+ }
+
+ // If custom doesn't grant access, try the original policy so we
+ // keep all normal checks in place.
+ return originalPolicy.implies(permissionToBeChecked, subject);
+ }
+
+ public PermissionCollection getPermissionCollection(Subject subject) {
+ return originalPolicy.getPermissionCollection(subject);
+ }
+
+ private boolean impliesCustom(Permission permissionToBeChecked) {
+ return
+ permissionToBeChecked instanceof WebResourcePermission &&
+ permissionToBeChecked.getName().startsWith("/protectedServlet/") &&
+ permissionToBeChecked.getName().endsWith("/test");
+ }
+
+}
diff --git a/tck/app-custom-policyfactory/src/main/java/ee/jakarta/tck/authorization/test/TestPolicyFactory.java b/tck/app-custom-policyfactory/src/main/java/ee/jakarta/tck/authorization/test/TestPolicyFactory.java
new file mode 100644
index 0000000..e664102
--- /dev/null
+++ b/tck/app-custom-policyfactory/src/main/java/ee/jakarta/tck/authorization/test/TestPolicyFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2024 Contributors to Eclipse Foundation.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+package ee.jakarta.tck.authorization.test;
+
+import jakarta.security.jacc.Policy;
+import jakarta.security.jacc.PolicyFactory;
+
+/**
+ * Test policy configuration factory.
+ *
+ *
+ * This factort is solely used to test for replacement and wrapping of the PolicyFactory.
+ * It ignores the contextId
which is not something real factories should
+ * do in most cases, and therefor should not be used as an example of how to create
+ * a custom PolicyFactory.
+ */
+public class TestPolicyFactory extends PolicyFactory {
+
+ private Policy policy;
+
+ public TestPolicyFactory(PolicyFactory policyFactory) {
+ super(policyFactory);
+ policy = new TestPolicy(policyFactory.getPolicy());
+ }
+
+ public Policy getPolicy(String contextId) {
+ return policy;
+ }
+
+ @Override
+ public void setPolicy(String contextId, Policy policy) {
+ this.policy = new TestPolicy(policy);
+ }
+}
diff --git a/tck/app-custom-policyfactory/src/main/webapp/WEB-INF/beans.xml b/tck/app-custom-policyfactory/src/main/webapp/WEB-INF/beans.xml
new file mode 100644
index 0000000..7b7b7ad
--- /dev/null
+++ b/tck/app-custom-policyfactory/src/main/webapp/WEB-INF/beans.xml
@@ -0,0 +1,24 @@
+
+
+