Enabling Java Security Manager for WSO2 products

Why Java Security Manager is needed?


In Java, the Security Manager is available for applications to have various security policies. The Security Manager helps to prevent untrusted code from doing malicious actions on the system. 

You need to enable Security Manager, if you plan to host any untrusted user applications in WSO2 products, especially in products like WSO2 Application Server.

The security policies should explicitly allow actions performed by the code base. If any of the actions are not allowed by the security policy, there will be a SecurityException

For more information on this, you can refer Java SE 7 Security Documentation.

Security Policy Guidelines for WSO2 Products


When enabling Security Manager for WSO2 products, it is recommended to give all permissions to all jars inside WSO2 product. For that, we plan to sign all jars using a common key and grant all permissions to the signed code by using "signedBy" grant as follows.

grant signedBy "<signer>" {
  permission java.security.AllPermission;
};

We also recommend to allow all property reads and WSO2 has a customized Carbon Security Manager to deny certain system properties.

One of the main reasons is that in Java Security Policy, we need to explicitly mention which properties are allowed and if there are various user applications, we cannot have a pre-defined list of System Properties. Therefore Carbon Security Manager's approach is to define a list of denied properties using the System Property "denied.system.properties". This approach basically changes Java Security Manager's rule of "Deny all, allow specified" to "Allow all, deny specified".

There is another system property named "restricted.packages" to control the package access. However this "restricted.packages" system property is not working in latest Carbon and I have created CARBON-14967 JIRA to fix that properly in a future Carbon release.

Signing all JARs inside WSO2 product.


To sign the jars, we need a key. We can use the keytool command to generate a key.

$ keytool -genkey -alias signFiles -keyalg RSA -keystore signkeystore.jks -validity 3650 -dname "CN=Isuru,OU=Engineering, O=WSO2, L=Colombo, ST=Western, C=LK"
Enter keystore password:  
Re-enter new password: 
Enter key password for
 (RETURN if same as keystore password):

Above keytool command creates a new keystore file. If you omit -dname argument, all key details will be prompted.

Now extract the WSO2 product. I will be taking WSO2 Application Server as an example.

$ unzip -q  ~/wso2-packs/wso2as-5.2.1.zip


Let's create two scripts to sign the jars. First script will find all jars and the second script will be used to sign a jar using the keystore we created earlier.

signJars.sh script:

#!/bin/bash
if [[ ! -d $1 ]]; then
    echo "Please specify a target directory"
    exit 1
fi
for jarfile in `find . -type f -iname \*.jar`
do
   ./signJar.sh $jarfile
done 


signJar.sh script:

#!/bin/bash

set -e

jarfile=$1

keystore_file="signkeystore.jks"
keystore_keyalias='signFiles'
keystore_storepass='wso2123'
keystore_keypass='wso2123'

signjar="$JAVA_HOME/bin/jarsigner -sigalg MD5withRSA -digestalg SHA1 -keystore $keystore_file -storepass $keystore_storepass -keypass $keystore_keypass"
verifyjar="$JAVA_HOME/bin/jarsigner -keystore $keystore_file -verify"

echo "Signing $jarfile"
$signjar $jarfile $keystore_keyalias

echo "Verifying $jarfile"
$verifyjar $jarfile

# Check whether the verification is successful.
if [ $? -eq 1 ]
then
    echo "Verification failed for $jarfile"
fi


Now we can see following files.

$ ls -l
-rwxrwxr-x  1 isuru isuru    602 Dec  9 13:05 signJar.sh
-rwxrwxr-x  1 isuru isuru    174 Dec  9 12:56 signJars.sh
-rw-rw-r--  1 isuru isuru   2235 Dec  9 12:58 signkeystore.jks
drwxr-xr-x 11 isuru isuru   4096 Dec  6  2013 wso2as-5.2.1

When we run signJars.sh, all JARs found inside WSO2 Application Server will be signed using the "signFiles" key.

$ ./signJars.sh wso2as-5.2.1/ > log

Configuring WSO2 Product to use Java Security Manager


To configure Java Security Manager, we need to pass few arguments to the main Java process. 

Java Security Manager can be enabled by using "java.security.manager" system property. We will specify the WSO2 Carbon Security Manager using this argument.

We also need to specify the security policy file using "java.security.policy" system property.

As I mentioned earlier, we will also set "restricted.packages" & "denied.system.properties" system properties.

Following is the recommended set of values to be used in wso2server.sh (Edit the startup script and add following lines just before the line " org.wso2.carbon.bootstrap.Bootstrap $*"


    -Djava.security.manager=org.wso2.carbon.bootstrap.CarbonSecurityManager \
    -Djava.security.policy=$CARBON_HOME/repository/conf/sec.policy \
    -Drestricted.packages=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,org.wso2.carbon. \
    -Ddenied.system.properties=javax.net.ssl.trustStore,javax.net.ssl.trustStorePassword,denied.system.properties \


Exporting signFiles public key certificate and importing it to wso2carbon.jks


We need to import the signFiles public key certificate to the wso2carbon.jks as the security policy file will be referring the signFiles signer certificate from the wso2carbon.jks (as specified by the first line).

$ keytool -export -keystore signkeystore.jks -alias signFiles -file sign-cert.cer
$ keytool -import -alias signFiles -file sign-cert.cer -keystore wso2as-5.2.1/repository/resources/security/wso2carbon.jks

Note: wso2carbon.jks' keystore password is "wso2carbon".

The Security Policy File


As specified in the system property "java.security.policy", we will keep the security policy file at $CARBON_HOME/repository/conf/sec.policy

Following policy file should be enough for starting up WSO2 Application Server and deploying a sample JSF & CXF webapps.


keystore "file:${user.dir}/repository/resources/security/wso2carbon.jks", "JKS";

// ========= Carbon Server Permissions ===================================
grant {
    // Allow socket connections for any host
    permission java.net.SocketPermission "*:1-65535", "connect,resolve";

    // Allow to read all properties. Use -Ddenied.system.properties in wso2server.sh to restrict properties
    permission java.util.PropertyPermission "*", "read";
    
    permission java.lang.RuntimePermission "getClassLoader";
    
    // CarbonContext APIs require this permission
    permission java.lang.management.ManagementPermission "control";

    // Required by any component reading XMLs. For example: org.wso2.carbon.databridge.agent.thrift:4.2.1.
    permission java.lang.RuntimePermission "accessClassInPackage.com.sun.xml.internal.bind.v2.runtime.reflect";

    // Required by org.wso2.carbon.ndatasource.core:4.2.0. This is only necessary after adding above permission. 
    permission java.lang.RuntimePermission "accessClassInPackage.com.sun.xml.internal.bind";
};

// ========= Platform signed code permissions ===========================
grant signedBy "signFiles" {
  permission java.security.AllPermission;
};

// ========= Granting permissions to webapps ============================
grant codeBase "file:${carbon.home}/repository/deployment/server/webapps/-" {

    // Required by webapps. For example JSF apps.
    permission java.lang.reflect.ReflectPermission "suppressAccessChecks";

    // Required by webapps. For example JSF apps require this to initialize com.sun.faces.config.ConfigureListener
    permission java.lang.RuntimePermission "setContextClassLoader";

    // Required by webapps to make HttpsURLConnection etc.
    permission java.lang.RuntimePermission "modifyThreadGroup";

    // Required by webapps. For example JSF apps need to invoke annotated methods like @PreDestroy
    permission java.lang.RuntimePermission "accessDeclaredMembers";

    // Required by webapps. For example JSF apps
    permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.compiler";

    // Required by webapps. For example JSF EL
    permission java.lang.RuntimePermission "getClassLoader";

    // Required by CXF app. Needed when invoking services
    permission javax.xml.bind.JAXBPermission "setDatatypeConverter";

    // File reads required by JSF (Sun Mojarra & MyFaces require these)
    // MyFaces has a fix https://issues.apache.org/jira/browse/MYFACES-3590   
    permission java.io.FilePermission "/META-INF", "read";
    permission java.io.FilePermission "/META-INF/-", "read";

    // OSGi permissions are requied to resolve bundles. Required by JSF
    permission org.osgi.framework.AdminPermission "*", "resolve,resource";
};

The security policies may vary depending on your requirements. I recommend to test your application thoroughly in a development environment.

NOTE: There are risks in allowing some Runtime Permissions. Please look at the java docs for RuntimePermission. See Concerns below.

Troubleshooting Java Security


Java provides the "java.security.debug" system property to set various debugging options and monitor security access.

I recommend to add following line to wso2server.sh whenever you need to troubleshoot some issue with Java Security.

    -Djava.security.debug="access,failure"

After adding that line, all the debug information will be printed to standard output. To check the logs, we can start the server using nohup.

$ nohup ./wso2server.sh &

Then we can grep the nohup.out and look for access denied messages.

$ tailf nohup.out | grep denied

Concerns with Java Security Policy


There are few concerns with current permission model in WSO2 products.

  • Use of ManagementPermission instead of Carbon specific permissions. The real ManagementPermission is used for a different purpose. I created CARBON-14966 jira to fix that.
  • Ideally the permission 'java.lang.management.ManagementPermission "control"' should not be specified in policy file as it is only required for privileged actions in Carbon. However due to indirect usage of such privileged actions within Carbon code, we need to specify that permission. This also needs to be fixed.
  • In above policy file, the JSF webapps etc require some risky runtime permissions. I recommend to use a Custom Runtime Environment (CRE) in WSO2 Application Server for JSF webapps etc and sign the jars inside CRE. You can also grant permissions based on the jar names (Use grant codeBase). However signing jars and using a CRE is a better approach with WSO2 AS.
If you also encounter any issues when using Java Security Manager, please discuss those issues in our developer mailing list.




Comments

Popular posts from this blog

Specifying a custom Event Settings file for Java Flight Recorder

Flame Graphs with Java Flight Recordings

Benchmarking Java Locks with Counters