One feature of Java EE not known by every developer is the Java EE Permission declaration. As a matter of fact, every Java EE product must be now capable of running with a Java security manager that enforces Java security permissions, and that prevents application components from executing operations for which they have not been granted the required permissions.
What is a Permission?
In Java terms, a permission represents access to a system resource. When running in a Security Manager context, in order for a resource access to be allowed the corresponding permission must be explicitly granted to the code attempting the access. A sample policy file entry that grants code from the /home/jboss directory read access to the file /tmp/abc is
grant codeBase "file:/home/jboss/" { permission java.io.FilePermission "/tmp/abc", "read"; };
Let’s see now how to apply the same concepts also to a Managed environment, like the application server.
Running JBoss / WildFly with a Security Manager
The first step for using a Security Manager in the applicaiton server is activating it. In order to do that, you can either set the -secmgr flag to the startup script or set the SECMGR variable to true, by uncommenting in your standalone.conf the following line:
# Uncomment this to run with a security manager enabled SECMGR="true"
Start the Application server. Now try to deploy a sample Servlet which tries to save a files on the disk:
PrintWriter writer = new PrintWriter("file.txt", "UTF-8"); writer.println("The first line"); writer.println("The second line"); writer.close();
Once you deploy the Servlet, you will manage to meet the Security Manager!
java.security.AccessControlException: WFSM000001: Permission check failed (permission “(“java.io.FilePermission” “file.txt” “write”)” in code source “(vfs:/content/Security.war/WEB-INF/classes )” of “null”)
So how do we grant permission to write to our application. Mostly like we do with a Java S2E application, we declare the list of permissions in a file. This file, named permission.xml needs to be placed in the META-INF folder of your application:
<permissions xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/permissions_7.xsd" version="7"> <permission> <class-name>java.io.FilePermission</class-name> <name>*</name> <actions>read,write</actions> </permission> </permissions>
Notice the read,write action, which will authorize us to perform read and write actions on a File for every class which is part of the Deployment. Deploy the application and check that it works now.
Another kind of resource which is typically shielded by the Security Manager is reading/writing a System Property. You can check by yourself that reading a System Property now returns a Security Exception:
String home = System.getProperty("java.home");
2016-10-10 09:33:26,306 ERROR [io.undertow.request] (default task-59) UT005023: Exception handling request to /Security/test: java.security.AccessControlException: WFSM000001: Permission check failed (permission "("java.util.PropertyPermission" "java.home" "read")" in code source "(vfs:/content/Security.war/WEB-INF/classes )" of "null")
Just like we did for the File, we can let an application read/write a System Property via a permission block:
<permission> <class-name>java.util.PropertyPermission</class-name> <name>*</name> <actions>read,write</actions> </permission>
Coding Permissions in the configuration file
Besides adding a deployment descriptor, it is also possible to define security policies at Subsystem level. This implies that Security checks could be valid for multiple applications using a particular class. Out of the box, the application server contains a subsystem named security-manager which defines just the upper limit of Permission policies which can be deployed on the application server:
<subsystem xmlns="urn:jboss:domain:security-manager:1.0"> <deployment-permissions> <maximum-set> <permission class="java.security.AllPermission"/> </maximum-set> </deployment-permissions> </subsystem>
In order to define permissions for a specific class, we need to add an entry to the minimum-permission element: the following CLI command, reproduces the same permission you needed to read/write on a file:
/subsystem=security-manager/deployment-permissions=default:write-attribute(name=minimum-permissions,value=[{class="java.io.FilePermission",name="*",actions="read,write"}])
The result, will be the following security-manager configuration:
<subsystem xmlns="urn:jboss:domain:security-manager:1.0"> <deployment-permissions> <minimum-set> <permission class="java.io.FilePermission" name="*" actions="read,write"/> </minimum-set> <maximum-set> <permission class="java.security.AllPermission"/> </maximum-set> </deployment-permissions> </subsystem>
Restricting permissions at module level
Finally, it is worth mentioning that permissions which you have defined via permission.xml or the configuration file, can be narrowed through the module.xml file which contains a set of classes which are loaded by the application server. For example, let’s say we want to impose a write restriction at module level for our Servlet, then within the module.xml file of the javax.servlet.api module we would need to code the following permissions block:
<module xmlns="urn:jboss:module:1.3" name="javax.servlet.api"> <resources> <resource-root path="jboss-servlet-api_3.1_spec-1.0.0.Final.jar"/> </resources> <permissions> <grant permission="java.io.FilePermission" name="/home/jboss/wildfly-10.1.0.Final/modules/system/layers/base/javax/servlet/api/main/jboss-servlet-api_3.1_spec-1.0.0.Final.jar" actions="read"/> </permissions> </module>
As you can see from the following log, if you try to violate the restriction imposed by the module permission, a different error log, related to the specificmodule will be issued:
2016-10-10 09:38:51,295 ERROR [io.undertow.request] (default task-28) UT005023: Exception handling request to /Security/test: java.security.AccessControlException: WFSM000001: Permission check failed (permission "("java.io.FilePermission" "file-name.txt" "write")" in code source "(jar:file:/home/jboss/wildfly-10.1.0.Final/modules/system/layers/base/javax/servlet/api/main/jboss-servlet-api_3.1_spec-1.0.0.Final.jar!/ )" of "null")