Skip to content

Commit

Permalink
Specify and add TCK test for wrapping constructor for PolicyFactory
Browse files Browse the repository at this point in the history
See issue jakartaee#156

Signed-off-by: Arjan Tijms <arjan.tijms@omnifish.ee>
  • Loading branch information
arjantijms committed Apr 2, 2024
1 parent 1c67b00 commit 2c1e971
Show file tree
Hide file tree
Showing 13 changed files with 413 additions and 16 deletions.
5 changes: 1 addition & 4 deletions 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
Expand Down Expand Up @@ -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.
*
* <p>
* <b>NOTE: DRAFT API. SUBJECT TO CHANGE</b>
*
* @author Arjan Tijms
*/
public interface Policy {
Expand Down
5 changes: 1 addition & 4 deletions 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
Expand All @@ -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.
*
* <p>
* <b>NOTE: DRAFT API. SUBJECT TO CHANGE</b>
*
* @see Policy
*
* @author Arjan Tijms
Expand Down
5 changes: 1 addition & 4 deletions 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
Expand Down Expand Up @@ -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).
*
* <p>
* <b>NOTE: DRAFT API. SUBJECT TO CHANGE</b>
*
* @author Arjan Tijms
*/
public interface PrincipalMapper {
Expand Down
25 changes: 23 additions & 2 deletions spec/src/main/asciidoc/chapters/2_provider-configuration.adoc
Expand Up @@ -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 <<a196>>.


=== Permission Implementation Classes

This contract defines the package, `jakarta.security.jacc`, that contains (among other things) `Permission`
Expand All @@ -31,8 +51,9 @@ default static method, `getPolicyConfigurationFactory` is provided that uses the
container can alternatively set a custom `PolicyConfigurationFactory` using the
`setPolicyConfigurationFactory` method. In that case the `PolicyConfigurationFactory` implementation
can come from a container specific configuration, or in case of the Servlet Container
from the context property `jakarta.security.jacc.PolicyConfigurationFactory.provider`. If the
`PolicyConfigurationFactory` has a public constructor with one argument of type `PolicyConfigurationFactory`,
from the web application's servlet context initialization parameter (context-param in web.xml) `jakarta.security.jacc.PolicyConfigurationFactory.provider`.

If the `PolicyConfigurationFactory` has a public constructor with one argument of type `PolicyConfigurationFactory`,
then the container should call this constructor with as argument the `PolicyConfigurationFactory` instance
that is being replaced. This allows a replacement `PolicyConfigurationFactory` to wrap the existing one
and selectively provide extra functionality.
Expand Down
2 changes: 1 addition & 1 deletion tck/app-custom-policy/pom.xml
Expand Up @@ -47,6 +47,6 @@
</dependencies>

<build>
<finalName>app-mem-policy</finalName>
<finalName>app-custom-policy</finalName>
</build>
</project>
55 changes: 55 additions & 0 deletions tck/app-custom-policyfactory/pom.xml
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2024 Contributors to Eclipse Foundation.
Copyright (c) 2015, 2020 Oracle and/or its affiliates. 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
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
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.eclipse.ee4j.authorization.tck</groupId>
<artifactId>jakarta-authorization-tck</artifactId>
<version>4.0.0-SNAPSHOT</version>
</parent>

<artifactId>app-custom-policyfactory</artifactId>
<packaging>war</packaging>

<description>
Like app-custom-policy, but uses a custom PolicyFactory defined in web.xml to supply a custom Policy.
Note that this only tests for the PolicyFactory being replaceable and wrappable, and
is not an example of how to easily supply a custom Policy or how to write a realistic
PolicyFactory.
</description>

<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>

<dependencies>
<dependency>
<groupId>org.eclipse.ee4j.authorization.tck</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>

<build>
<finalName>app-custom-policyfactory</finalName>
</build>
</project>
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2024 Contributors to Eclipse Foundation.
* Copyright (c) 2015, 2020 Oracle and/or its affiliates. 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
* 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.annotation.security.DeclareRoles;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.HttpConstraint;
import jakarta.servlet.annotation.ServletSecurity;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* Protected Servlet that prints out the name of the authenticated caller and whether
* this caller is in any of the roles {foo, bar, kaz}
*
* <p>
* 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");
}

}
@@ -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");
}

}
@@ -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.
*
* <p>
* This factort is solely used to test for replacement and wrapping of the PolicyFactory.
* It ignores the <code>contextId</code> 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);
}
}
24 changes: 24 additions & 0 deletions tck/app-custom-policyfactory/src/main/webapp/WEB-INF/beans.xml
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2024 Contributors to Eclipse Foundation.
Copyright (c) 2015, 2020 Oracle and/or its affiliates. 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
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
-->
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"
bean-discovery-mode="all" version="3.0">
</beans>
33 changes: 33 additions & 0 deletions tck/app-custom-policyfactory/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
-->
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">

<context-param>
<param-name>jakarta.security.jacc.PolicyFactory.provider</param-name>
<param-value>ee.jakarta.tck.authorization.test.TestPolicyFactory</param-value>
</context-param>

<login-config>
<auth-method>BASIC</auth-method>
<realm-name>file</realm-name>
</login-config>
</web-app>

0 comments on commit 2c1e971

Please sign in to comment.