Archive

Posts Tagged ‘security’
  • Signing and verifying a standalone JAR

    Seal

    :revdate: 2017-02-05 16:00:00 +0100 :page-liquid: :icons: font :experimental:

    link:{% post_url 2017-02-05-proposal-java-policy-files-crafting-process %}[Last week^], I wrote about the JVM policy file that explicitly lists allowed sensitive API calls when running the JVM in sandboxed mode. This week, I’d like to improve the security by signing the JAR.

    == The nominal way


    This way doesn’t work. Readers more interested in the solution than the process should skip it. **

    === Create a keystore

    The initial step is to create a keystore if none is already available. There are plenty of online tutorials showing how to do that.

    [source,bash]

    keytool -genkey -keyalg RSA -alias selfsigned -keystore /path/to/keystore.jks -storepass password -validity 360 —-

    Fill in information accordingly.

    === Sign the application JAR

    Signing the application JAR must be part of the build process. With Maven, the https://maven.apache.org/plugins/maven-jarsigner-plugin/[JAR signer plugin^] is dedicated to that. Its usage is quite straightforward:

    [source,xml]

    maven-jarsigner-plugin 1.4 sign sign /path/to/keystore.jks selfsigned ${store.password} ${key.password}

    To create the JAR, invoke the usual command-line and pass both passwords as system properties:

    [source,bash]

    mvn package -Dstore.password=password -Dkey.password=password —-

    Alternatively, Maven’s https://maven.apache.org/guides/mini/guide-encryption.html[encryption capabilities^] can be used to store passwords in a dedicated settings-security.xml to further improve security.

    === Configure the policy file

    Once the JAR is signed, the policy file can be updated to make use of it. This requires only the following configuration steps:

    1. Point to the keystore
    2. Configure the allowed alias

    [source]

    keystore “keystore.jks”;

    grant signedBy “selfsigned” codeBase “file:target/spring-petclinic-1.4.2.jar” { … } —-

    Notice the signedBy keyword followed by the alias name - the same one as in the keystore above.

    === Launching the JAR with the policy file

    The same launch command can be used without any change:

    [source,bash]

    java -Djava.security.manager -Djava.security.policy=jvm.policy -jar target/spring-petclinic-1.4.2.jar —-

    Unfortunately, it doesn’t work though this particular permission had already been configured!

    [source]

    Caused by: java.security.AccessControlException: access denied (“java.lang.reflect.ReflectPermission” “suppressAccessChecks”) at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) at java.security.AccessController.checkPermission(AccessController.java:884) at java.lang.SecurityManager.checkPermission(SecurityManager.java:549) at java.lang.reflect.AccessibleObject.setAccessible(AccessibleObject.java:128) at org.springframework.util.ReflectionUtils.makeAccessible(ReflectionUtils.java:475) at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:141) at org.springframework.boot.SpringApplication.createSpringFactoriesInstances(SpringApplication.java:420) —-

    The strangest part is that permissions requested before this one work all right. The reason is to be found in the particular structure of the JAR created by the Spring Boot plugin: JAR dependencies are packaged untouched in a BOOT-INF/lib folder in the executable JAR. Then Spring Boot code uses custom class-loading magic to load required classes from there.

    JAR signing works by creating a specific hash for each class, and by writing them into the JAR manifest file. During the verification phase, the hash of a class is computed and compared to the hash of the manifest. Hence, permissions related to classes located in the BOOT-INF/classes folder work as expected.

    However, the org.springframework.boot.SpringApplication class mentioned in the stack trace above is part of the spring-boot.jar located under BOOT-INF/lib: verification fails as there’s no hash available for the class in the manifest.

    Thus, usage of the Spring Boot plugin for JAR creation/launch is not compatible with JAR signing.

    == The workaround

    Aside from Spring Boot, there’s a legacy way to create standalone JARs: the https://maven.apache.org/plugins/maven-shade-plugin/[Maven Shade plugin^]. This will extract every class of every dependency in the final JAR. This is possible with Spring Boot apps, but it requires some slight changes to the POM:

    1. In the POM, remove the Spring Boot Maven plugin
    2. Configure the main class in the Maven JAR plugin: + [source,xml] —-
    maven-jar-plugin 3.0.2 org.springframework.samples.petclinic.PetClinicApplication
    1. Finally, add the Maven Shade plugin to work its magic: + [source,xml] —-
    maven-shade-plugin 2.4.3 true package shade

    WARNING: The command-line to launch the JAR doesn’t change but permissions depend on the executed code, coupled to the JAR structure. Hence, the policy file should be slightly modified.

    == Lessons learned

    While it requires to be a little creative, it’s entirely possible to sign Spring Boot JARs by using the same techniques as for any other JARs.

    To go further:

    • https://maven.apache.org/plugins/maven-jarsigner-plugin/[Jarsigner Plugin^]
    • https://maven.apache.org/plugins/maven-shade-plugin/[Shade Plugin^]
    • http://docs.spring.io/spring-boot/docs/current/maven-plugin/[Spring Boot plugin^]
    • http://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html[Spring Boot executable JAR format^]
    Categories: Java Tags: JVMsecurityJARSpring Bootpolicy
  • Proposal for a Java policy files crafting process

    Security guy on an escalator

    :revdate: 2017-02-05 16:00:00 +0100 :page-liquid: :icons: font :experimental:

    I’ve link:{% post_url 2016-01-17-java-security-manager %}[already^] link:{% post_url 2017-01-29-compilation-java-code-on-the-fly %}[written] about the JVM security manager, and why it should be used - despite it being rarely the case, if ever. However, just advocating for it won’t change the harsh reality unless some guidelines are provided to do so. This post has the ambition to be the basis of such guidelines.

    As a reminder, the JVM can run in two different modes, standard and sandboxed. In the former, all API are available with no restriction; in the later, some API calls deemed sensitive are forbidden. In that case, explicit permissions to allow some of those calls can be configured in a dedicated policy file.

    NOTE: Though running the JVM in sandbox mode is important, it doesn’t stop there .e.g. executing only digitally-signed code is also part of securing the JVM. This post is the first in a 2 parts-serie regarding JVM security.

    == Description

    The process is based on the https://en.wikipedia.org/wiki/Principle_of_least_privilege[principle of least privilege^]. That directly translates into the following process:

    1. Start with a blank policy file
    2. Run the application
    3. Check the thrown security exception
    4. Add the smallest-grained permission possible in the policy file that allows to pass step 2
    5. Return to step 2 until the application can be run normally

    Relevant system properties include:

    • java.security.manager: activates the Java Security manager
    • java.security.policy: points to the desired policy file
    • java.security.debug: last but not least, activates debugging information when an absent privilege is required. There are a ton of https://docs.oracle.com/javase/8/docs/technotes/guides/security/troubleshooting-security.html[options^].

    That sounds easy enough but let’s go detail how it works with an example.

    == A case study

    As a sample application, we will be using the https://github.com/spring-projects/spring-petclinic[Spring Pet Clinic^], a typical albeit small-sized Spring Boot application.

    === First steps

    Once the application has been built, launch it with the security manager:

    [source,bash]

    java -Djava.security.manager -Djava.security.policy=jvm.policy -jar target/spring-petclinic-1.4.2.jar —-

    This, of course, fails. The output is the following:


    Exception in thread “main” java.lang.IllegalStateException: java.security.AccessControlException: access denied (“java.lang.RuntimePermission” “getProtectionDomain”) at org.springframework.boot.loader.ExecutableArchiveLauncher.(ExecutableArchiveLauncher.java:43) at org.springframework.boot.loader.JarLauncher.(JarLauncher.java:37) at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:58) Caused by: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "getProtectionDomain") at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) at java.security.AccessController.checkPermission(AccessController.java:884) at java.lang.SecurityManager.checkPermission(SecurityManager.java:549) at java.lang.Class.getProtectionDomain(Class.java:2299) at org.springframework.boot.loader.Launcher.createArchive(Launcher.java:117) at org.springframework.boot.loader.ExecutableArchiveLauncher.(ExecutableArchiveLauncher.java:40) ... 2 more ----

    Let’s add the permission relevant to the above “access denied” exception to the policy file:

    [source]

    grant codeBase “file:target/spring-petclinic-1.4.2.jar” { permission java.lang.RuntimePermission “getProtectionDomain”; }; —-

    Notice the path pointing to the JAR. It prevents other potentially malicious archives to execute critical code. Onto the next blocker.


    Exception in thread “main” java.security.AccessControlException: access denied (“java.util.PropertyPermission” “java.protocol.handler.pkgs” “read”) —-

    This can be fixed by adding the below line to the policy file:

    [source]

    grant codeBase “file:target/spring-petclinic-1.4.2.jar” { permission java.lang.RuntimePermission “getProtectionDomain”; permission java.util.PropertyPermission “java.protocol.handler.pkgs”, “read”; }; —-

    Next please.


    Exception in thread “main” java.security.AccessControlException: access denied (“java.util.PropertyPermission” “java.protocol.handler.pkgs” “read”) —-

    Looks quite similar, but it needs a write permission in addition to the read one. Sure it can be fixed by adding one more line, but there’s a shortcut available. Just specify all necessary attributes of the permission on the same line:

    [source]

    grant codeBase “file:target/spring-petclinic-1.4.2.jar” { permission java.lang.RuntimePermission “getProtectionDomain”; permission java.util.PropertyPermission “java.protocol.handler.pkgs”, “read,write”; }; —-

    Rinse and repeat. Without further ado, the (nearly) final policy can be found https://gist.github.com/nfrankel/309df7198d37db1df08153c3c5415c67[online^]: a whooping ~1800 lines of configuration for the Spring Boot Pet Clinic as an executable JAR.

    Now that the general approach has been explained, it just needs to be followed until the application functions properly. The next section describe some specific glitches along the way.

    === Securing Java logging

    At some point, nothing gets printed in the console anymore. The command-line just returns, that’s it. Comes the java.security.debug system property - described above, that helps resolve the issue:

    [source,bash]

    java -Djava.security.manager -Djava.security.policy=jvm.policy -Djava.security.debug=access,stacktrace -jar target/spring-petclinic-1.4.2.jar —-

    That yields the following stack:


    java.lang.Exception: Stack trace at java.lang.Thread.dumpStack(Thread.java:1329) at java.security.AccessControlContext.checkPermission(AccessControlContext.java:419) at java.security.AccessController.checkPermission(AccessController.java:884) at java.lang.SecurityManager.checkPermission(SecurityManager.java:549) at java.util.logging.LogManager.checkPermission(LogManager.java:1586) at java.util.logging.Logger.checkPermission(Logger.java:422) at java.util.logging.Logger.setLevel(Logger.java:1688) at java.util.logging.LogManager.resetLogger(LogManager.java:1354) at java.util.logging.LogManager.reset(LogManager.java:1332) at java.util.logging.LogManager$Cleaner.run(LogManager.java:239) —-

    It’s time for some real software engineering (also known as Google Search). The LogManager’s https://docs.oracle.com/javase/8/docs/api/java/util/logging/LogManager.html#checkAccess–[Javadoc^] tells about the LoggingPermission that needs to be added to the existing list of permissions:

    [source]

    grant codeBase “file:target/spring-petclinic-1.4.2.jar” { permission java.lang.RuntimePermission “getProtectionDomain”; … permission java.util.PropertyPermission “PID”, “read,write”; permission java.util.logging.LoggingPermission “control”; }; —-

    That makes it possible to go further.

    === Securing the reading of system properties and environment variables

    It’s even possible to watch Spring Boot log… until one realizes it’s made entirely of error messages about not being able to read a bunchload of system properties and environment variables. Here’s an excerpt:


    2017-01-22 00:30:17.118 INFO 46549 — [ main] o.s.w.c.s.StandardServletEnvironment : Caught AccessControlException when accessing system environment variable [logging.register_shutdown_hook]; its value will be returned [null]. Reason: access denied (“java.lang.RuntimePermission” “getenv.logging.register_shutdown_hook”) 2017-01-22 00:30:17.118 INFO 46549 — [ main] o.s.w.c.s.StandardServletEnvironment : Caught AccessControlException when accessing system property [logging_register-shutdown-hook]; its value will be returned [null]. Reason: access denied (“java.util.PropertyPermission” “logging_register-shutdown-hook” “read”) —-

    I will spare you dear readers a lot of trouble: there’s no sense in configuring every property one by one as JCache requires read and write permissions on all properties. So just remove every fine-grained PropertyPermission so far and replace it with a catch-all coarse-grained one:

    [source]

    permission java.util.PropertyPermission “*”, “read,write”; —-

    [NOTE]

    Seems like security was not one of JCache developers first priority. The following snippet is the http://grepcode.com/file/repo1.maven.org/maven2/javax.cache/cache-api/1.0.0/javax/cache/Caching.java#Caching.CachingProviderRegistry.getCachingProviders%28%29[code excerpt] for javax.cache.Caching.CachingProviderRegistry.getCachingProviders():

    [source,java]

    if (System.getProperties().containsKey(JAVAX_CACHE_CACHING_PROVIDER)) { String className = System.getProperty(JAVAX_CACHE_CACHING_PROVIDER); … } —-

    Wow, it reads all properties! Plus the next line makes it a little redundant, no?

    As for environment variables, the Spring team seem to try to avoid developers configuration issues related to case and check every possible case combination, so there is a lot of different options.

    === Variables and subdirectories

    At one point, Spring’s embedded Tomcat attempts - and fails, to create a subfolder into the java.io.tmpdir folder.


    java.lang.SecurityException: Unable to create temporary file at java.io.File.createTempFile(File.java:2018) ~[na:1.8.0_92] at java.io.File.createTempFile(File.java:2070) ~[na:1.8.0_92] at org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory.createTempDir(…) at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getEmbeddedServletContainer(…) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(…) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(…) … 16 common frames omitted —-

    One could get away with that by “hard-configuring” the path, but that would just be a major portability issue. Permissions are able to use System properties.

    The second issue is the subfolder: there’s no way of knowing the folder name, hence it’s not possible to configure it beforehand. However, file permissions accept any direct children or any descendant in the hierarachy; the former is set with jokers, and the second with dashes. The final configuration looks like this:

    [source]

    permission java.io.FilePermission “${java.io.tmpdir}/-“, “read,write,delete”; —-

    === CGLIB issues

    CGLIB is used heavily in the Spring framework to extend classes at compile-time. By default, the name of a generated class:

    [quote] […] is composed of a prefix based on the name of the superclass, a fixed string incorporating the CGLIB class responsible for generation, and a hashcode derived from the parameters used to create the object.

    Consequently, one if faced with the following exception:

    java.security.AccessControlException: access denied ("java.io.FilePermission"
        "[...]/boot/autoconfigure/web/MultipartAutoConfiguration$$EnhancerBySpringCGLIB$$cb1b157aCustomizer.class"
        "read")
      at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) ~[na:1.8.0_92]
      at java.security.AccessController.checkPermission(AccessController.java:884) [na:1.8.0_92]
      at java.lang.SecurityManager.checkPermission(SecurityManager.java:549) ~[na:1.8.0_92]
      at java.lang.SecurityManager.checkRead(SecurityManager.java:888) ~[na:1.8.0_92]
      at java.io.File.exists(File.java:814) ~[na:1.8.0_92]
      at org.apache.catalina.webresources.DirResourceSet.getResource(...)
      at org.apache.catalina.webresources.StandardRoot.getResourceInternal(...)
      at org.apache.catalina.webresources.Cache.getResource(Cache.java:62) ~[tomcat-embed-core-8.5.6.jar!/:8.5.6]
      at org.apache.catalina.webresources.StandardRoot.getResource(...)
      at org.apache.catalina.webresources.StandardRoot.getClassLoaderResource(...)
      at org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(...)
      at org.apache.catalina.loader.WebappClassLoaderBase$PrivilegedFindClassByName.run(...)
      at org.apache.catalina.loader.WebappClassLoaderBase$PrivilegedFindClassByName.run(...)
      at java.security.AccessController.doPrivileged(Native Method) [na:1.8.0_92]
      at org.apache.catalina.loader.WebappClassLoaderBase.findClass()
      at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedWebappClassLoader.findClassIgnoringNotFound()
      at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedWebappClassLoader.loadClass()
      at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(...)
      at java.lang.Class.forName0(Native Method) [na:1.8.0_92]
      at java.lang.Class.forName(Class.java:348) [na:1.8.0_92]
    

    It looks quite an easy file permission fix, but it isn’t: for whatever reason, the hashcode used by CGLIB to extend MultipartAutoConfiguration changes at every compilation. Hence, a more lenient generic permission is required:

    permission java.io.FilePermission "src/main/webapp/WEB-INF/classes/org/springframework/boot/autoconfigure/web/*", "read";
    

    === Launching is not the end

    Unfortunately, once the application has been successfully launched doesn’t mean it stops there. Browsing the home page yields a new bunch of security exceptions.

    For example, Tomcat needs to bind to port 8080, but this is a potential insecure action:

    java.security.AccessControlException: access denied ("java.net.SocketPermission" "localhost:8080" "listen,resolve")
    

    The permission to fix it is pretty straightforward:

    permission java.net.SocketPermission "localhost:8080", "listen,resolve";
    

    However, actually browsing the app brings a new exception:

    java.security.AccessControlException: access denied ("java.net.SocketPermission" "[0:0:0:0:0:0:0:1]:56733" "accept,resolve")
    

    That wouldn’t be bad if the port number didn’t change with every launch. A few attempts reveal that it seems to start from around 55400. Good thing that the socket permission allows for a port range:

    permission java.net.SocketPermission "[0:0:0:0:0:0:0:1]:55400-", "accept,resolve";
    

    == Lessons learned

    Though it was very fulfilling to have created the policy file, the true value lies in the lessons learned.

    • The crafting of a custom policy file for a specific application is quite trivial, but very time-consuming. I didn’t finish completely and spent around one day for a small-sized application. Time might be a valid reason why policy files are never in use.
    • For large applications, I believe it’s not only possible but desirable to automate the crafting process: run the app, read the exception, create the associated permission, and update the policy file accordingly.
    • Patterns are recognizable in the policy file: sets of permissions are dedicated to a specific library, such as Spring Boot’s actuator. If each framework/library would provide the minimum associated policy file that allows it to work correctly, crafting a policy file for an app would just mean aggregating all files for every library.
    • Randomness (such as random port number) and bad coding practices (such as JCache’s) require more coarse-grained permissions. On one hand, it speeds up the crafting process; on the other hand, it increases the potential attack surface.

    In all cases, running the JVM in sandbox mode is not an option in security-aware environments.

    To go further:

    • https://docs.oracle.com/javase/8/docs/technotes/guides/security/PolicyFiles.html[Policy file syntax^]
    • https://docs.oracle.com/javase/8/docs/technotes/guides/security/permissions.html[Permissions in the JDK^]
    • https://docs.oracle.com/javase/8/docs/technotes/guides/security/spec/security-specTOC.fm.html[Security documentation^]
    • https://gist.github.com/nfrankel/309df7198d37db1df08153c3c5415c67[End result policy file] (nearly finished)
    Categories: Java Tags: JVMsecuritySpring Bootpolicy
  • Compilation of Java code on the fly

    Rusty machine

    Java makes it possible to compile Java code at runtime… any Java code.

    The entry-point to the compilation is the ToolProvider class. From its Javadoc:

    Provides methods for locating tool providers, for example, providers of compilers. This class complements the functionality of ServiceLoader.

    This class is available in Java since version 1.6 - released 10 years ago, but seems to have been largely ignored.

    The code

    Here’s a snippet that allows that:

    {% highlight java linenos %} public class EvilExecutor {

    private String readCode(String sourcePath) throws FileNotFoundException {
        InputStream stream = new FileInputStream(sourcePath);
        String separator = System.getProperty("line.separator");
        BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
        return reader.lines().collect(Collectors.joining(separator));
    }
    
    private Path saveSource(String source) throws IOException {
        String tmpProperty = System.getProperty("java.io.tmpdir");
        Path sourcePath = Paths.get(tmpProperty, "Harmless.java");
        Files.write(sourcePath, source.getBytes(UTF_8));
        return sourcePath;
    }
    
    private Path compileSource(Path javaFile) {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        compiler.run(null, null, null, javaFile.toFile().getAbsolutePath());
        return javaFile.getParent().resolve("Harmless.class");
    }
    
    private void runClass(Path javaClass)
            throws MalformedURLException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        URL classUrl = javaClass.getParent().toFile().toURI().toURL();
        URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{classUrl});
        Class<?> clazz = Class.forName("Harmless", true, classLoader);
        clazz.newInstance();
    }
    
    public void doEvil(String sourcePath) throws Exception {
        String source = readCode(sourcePath);
        Path javaFile = saveSource(source);
        Path classFile = compileSource(javaFile);
        runClass(classFile);
    }
    
    public static void main(String... args) throws Exception {
        new EvilExecutor().doEvil(args[0]);
    } } {% endhighlight %}
    

    Some explanations are in order:

    • readCode(): reads the source code from an arbitrary file on the file system, and returns it as a string. An alternative implementation would get the source from across the network.
    • saveSource(): creates a new file from the source code in a read-enabled directory. The file name is hard-coded, more refined versions would parse the code parameter to create a file named according to the class name it contains.
    • compileSource(): compiles the class file out of the java file.
    • runClass: loads the compiled class and instantiates a new object. To be independent from any cast, the to-be-executed code should be set in the constructor of the external source code class.

    The issue

    From a feature point of view, compiling code on the fly boosts the value of the Java language compared to others that don’t provide this feature. From a security point of view, this is a nightmare. The thought of being able to execute arbitrary code in production should send shivers down anyone’s spine who is part of any IT organization, developers included, if not mostly.

    Seasoned developers/ops or regular readers probably remember about the Java security manager and how to activate it:

    java -Djava.security.manager -cp target/classes ch.frankel.blog.runtimecompile.EvilExecutor harmless.txt
    

    Executing the above command-line will yield the following result:

    java.lang.SecurityManager@4e25154f
    Exception in thread "main" java.security.AccessControlException:
        access denied ("java.io.FilePermission" "harmless.txt" "read")
      at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
      at java.security.AccessController.checkPermission(AccessController.java:884)
      at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
      at java.lang.SecurityManager.checkRead(SecurityManager.java:888)
      at java.io.FileInputStream.<init>(FileInputStream.java:127)
      at java.io.FileInputStream.<init>(FileInputStream.java:93)
      at ch.frankel.blog.runtimecompile.EvilExecutor.readCode(EvilExecutor.java:19)
      at ch.frankel.blog.runtimecompile.EvilExecutor.doEvil(EvilExecutor.java:47)
      at ch.frankel.blog.runtimecompile.EvilExecutor.main(EvilExecutor.java:56)
    

    Conclusion

    The JVM offers plenty of features. A with any tool, they can be used for good or bad. It’s up to everyone to feel responsible about properly securing one’s JVM, doubly so in sensitive fields - banking, military, etc.

    Categories: Java Tags: security
  • Why you shouldn't trust the HTML password input

    This week, I wanted to make a simple experiment. For sure, all applications we develop make use of HTTPS to encrypt the login/password but what happens before?

    Let’s say I typed my login/password but before sending them, I’m called by my colleague and I leave my computer open. My password is protected by the HTML password input, right? It shows stars instead of the real characters. Well, it’s stupidly easy to circumvent this. If you use a developer workstation and have developer tools on your browser, just live edit the page and change type="password" to type="text". Guess what? It works and displays the password in clear text. You have been warned!

    Categories: Development Tags: HTMLsecurity
  • The Java Security Manager: why and how?

    Generally, security concerns are boring for developers. I hope this article is entertaining enough for you to read it until the end since it tackles a very serious issue on the JVM.

    Quizz

    Last year, at Joker conference, my colleague Volker Simonis showed a snippet that looked like the following:

    public class StrangeReflectionExample {
    
        public Character aCharacter;
    
        public static void main(String... args) throws Exception {
            StrangeReflectionExample instance = new StrangeReflectionExample();
            Field field = StrangeReflectionExample.class.getField("aCharacter");
            Field type = Field.class.getDeclaredField("type");
            type.setAccessible(true);
            type.set(field, String.class);
            field.set(instance, 'A');
            System.out.println(instance.aCharacter);
        }
    }
    

    Now a couple of questions:

    1. Does this code compile?
    2. If yes, does it run?
    3. If yes, what does it display?

    Answers below (dots to let you think before checking them).

    .

    ..

    ….

    …..

    ……

    …….

    ……..

    ………

    ……….

    ………..

    …………

    ………….

    …………..

    ……………

    …………….

    ……………..

    This code compiles just fine. In fact, it uses the so-called reflection API (located in the java.lang.reflect package) which is fully part of the JDK.

    Executing this code leads to the following exception:

    Exception in thread "main" java.lang.IllegalArgumentException:
            Can not set java.lang.String field ch.frankel.blog.securitymanager.StrangeReflectionExample.aCharacter
                to java.lang.Character
    	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    	at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
    	at java.lang.reflect.Field.set(Field.java:764)
    	at ch.frankel.blog.securitymanager.StrangeReflectionExample.main(StrangeReflectionExample.java:15)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:497)
    	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
    

    So, despite the fact that we defined the type of the aCharacter attribute as a Character at development time, the reflection API is able to change its type to String at runtime! Hence, trying to set it to 'A' fails.

    Avoiding nasty surprises with the Security Manager

    Reflection is not the only risky operation one might want to keep in check on the JVM. Reading a file or writing one also belong to the set of potentially dangerous operations. Fortunately, the JVM has a system to restrict those operations. Unfortunately, it’s not set by default.

    In order to activate the SecurityManager, just launch the JVM with the java.security.manager system property i.e. java -Djava.security.manager. At this point, the JVM will use the default JRE policy. It’s configured in the file located at %JAVA_HOME%/lib/security/java.policy (for Java 8). Here’s a sample of this file:

    grant codeBase "file:${{java.ext.dirs}}/*" {
            permission java.security.AllPermission;
    };
    
    grant {
            permission java.lang.RuntimePermission "stopThread";
            permission java.net.SocketPermission "localhost:0", "listen";
            permission java.util.PropertyPermission "java.version", "read";
            permission java.util.PropertyPermission "java.vendor", "read";
            ...
    }
    

    The first section - grant codeBase, is about which code can be executed; the second - grant, is about specific permissions.

    Regarding the initial problem regarding reflection mentioned above, the second part is the most relevant. One can read the source of the AccessibleObject.setAccessible() method:

    SecurityManager sm = System.getSecurityManager();
    if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
    setAccessible0(this, flag);
    

    Every sensitive method to a Java API has the same check through the Security Manager. You can verify that for yourself in the following code:

    • Thread.stop()
    • Socket.bind()
    • System.getProperty()
    • etc.

    Using an alternate java.policy file

    Using the JRE’s policy file is not convenient when one uses the same JRE for different applications. Given the current micro-service trend, this might not be the case. However, with automated provisioning, it might be more convenient to always provision the same JRE over and over and let each application provides its own specific policy file.

    To add another policy file in addition to the default JRE’s, thus adding more permissions, launch the JVM with:

    java -Djava.security.manager -Djava.security.policy=/path/to/other.policy

    To replace the default policy file with your own, launch the JVM with:

    java -Djava.security.manager -Djava.security.policy==/path/to/other.policy

    Note the double equal sign.

    Configuring your own policy file

    Security configuration can be either based on a:

    Black list
    In a black list scenario, everything is allowed but exceptions can be configured to disallow some operations.
    White list
    On the opposite, in a white list scenario, only operations that are explicitly configured are allowed. By default, all operations are disallowed.

    If you want to create your own policy file, it’s suggested you start with a blank one and then launch your app. As soon, as you get a security exception, add the necessary permission is the policy. Repeat until you have all necessary permissions. Following this process will let you have only the minimal set of permissions to run the application, thus implementing the least privilege security principle.

    Note that if you’re using a container or a server, you’ll probably require a lot of those permissions, but this is the price to pay to secure your JVM against abuses.

    Conclusion

    I never checked policy files in production, but since I never had any complain, I assume the JVM’s policy was never secured. This is a very serious problem! I hope this article will raise awareness regarding that lack of hardening - especially since with the latest JVM, you can create and compile Java code on the fly, leading to even more threats.

    To go further:

    Categories: Java Tags: JVMsecurity
  • Sanitizing webapp outputs as an an afterthought

    For sure, software security should be part of every developer’s requirements: they should be explained and detailed before development. Unfortunately, it happens in real life that this is not always the case. Alternatively, even when it is, developers make mistakes and/or have to make with tight (read impossible) plannings. In the absence of security checks automated tools, sooner or later, an issue will appear.

    I’ve been thinking about a way to sanitize the output of a large-scale legacy Spring MVC application in a reliable way (i.e. not go on each page to fix issues). Basically, there are 4 ways output is displayed in the HTML page.

    # Name Sample snippet Description
    1 Form taglib <form:input path="firstName"> Outputs a bean attribute
    2 Spring taglib <spring:message code="label.name.first"> Outputs a message from a properties file
    3 Java Standard Taglib Library <c:out value="${pageContext.request.requestURI}" /> Outputs a value
    4 Expression Language <span>${pageContext.request.requestURI}</span> Outputs a value

    Spring taglibs

    Spring taglibs are a breeze to work with. Basically, Spring offers multiple ways to sanitize the output, each scope parameter having a possibility to be overridden by a narrower one:

    1. Application scoped, with the boolean defaultHtmlEscape context parameter {% highlight xml %} defaultHtmlEscape true {% endhighlight %}
    2. Page scoped (i.e. all forms on page), with the <spring:defaultHtmlEscape> tag
    3. Tag scoped, with the htmlEscape attribute of the tag

    There’s only one catch; the <spring:message> tag can take not only a code (the key in the property file) but also arguments - however, those are not escaped:

    Hello, ${0} ${1}
    

    A possible sanitization technique consists of the following steps:

    1. Create a new SanitizeMessageTag:
      • Inherit from Spring's MessageTag
      • Override the relevant revolveArguments(Object) method
      • Use the desired sanitization technique (Spring uses its own HtmlUtils.htmlEscape(String))
    2. Copy the existing Spring TagLib Descriptor and create a new one out of it
    3. Update it to bind the message tag to the newly created SanitizeMessageTag class
    4. Last but not least, override the configuration of the taglib in the web deployment descriptor: {% highlight xml %} http://www.springframework.org/tags /WEB-INF/tld/sanitized-spring-form.tld {% endhighlight %} By default, the JavaEE specifications mandates for the container to look for TLDs insides JARs located under the WEB-INF/lib directory. It is also possible to configure them in the web deployment descriptor. However, the configuration takes precedence over automatic scanning.

    This way, existing JSP using the Spring taglib will automatically benefit from the new tag with no page-to-page update necessary.

    JSTL

    The <c:out> tag works the same way as the <spring:message> one, the only difference being there’s no global configuration parameter, only a escapeXml tag attribute which defaults to false.

    The same technique as above can be used to default to true instead.

    EL

    The EL syntax enables output outside any taglib so that the previous TLD override technique cannot be used to solve this.

    Not known to many developers, EL snippets are governed by so-called EL resolvers. Standard application servers (including servlet containers like Tomcat) provide standard EL resolvers, but it is also possible to add others at runtime.

    Note: though only a single EL resolver can be set in the JSP context, the resolver hierarchy implements the Composite pattern, so it’s not an issue.

    Steps required to sanitize EL syntax by default are:

    1. Subclasses relevant necessary EL resolvers - those are ScopedAttributeELResolver, ImplicitObjectELResolver and BeanELResolver, since they may return strings
    2. For each, override the getValue() method:
      • Call super.getValue()
      • Check the return value
      • If it is a string, sanitize the value before returning it, otherwise, leave it as it is
    3. Create a ServletContextListener to register these new EL resolvers {% highlight java %} public class SanitizeELResolverListener implements ServletContextListener { public void contextInitialized(ServletContextEvent event) { ServletContext context = event.getServletContext(); JspFactory jspFactory = JspFactory.getDefaultFactory(); JspApplicationContext jspApplicationContext = jspFactory.getJspApplicationContext(context); ELResolver sber = new SanitizeBeanELResolver(); jspApplicationContext.addELResolver(sber); // Register other EL resolvers } } {% endhighlight %}

    Summary

    Trying to sanitize the output of an application after it has been developed is not the good way to raise developers concerns about security. However, dire situations require dire solutions. When the application has already been developed, the above approaches - one for taglibs, one for EL, show how to achieve this in a way that does not impact existing code and get the job done.

    Categories: JavaEE Tags: JSTLsecuritySpring MVC
  • Choosing a password manager

    I’ve been thinking about having a more secure password management since ages. At first, my only concern was to share my bookmarks and history between my different computers (at that time, phones were conveniently left out of my scope). Since Firefox was my browser of choice, I decided to go for Foxmarks (now called XMarks and available for more browsers).

    However, it soon became apparent that my natural lazyness came back and I synchronized my passwords too… in the cloud. After Firefox brought out-of-the-box synchronization through Sync, I continued to use the feature, not listening to the little voice in my head telling me it was a big security problem. I mean, Mozilla could secure the storage the way it wanted, I still felt not really safe… but lazyness prevailed. It was not until I had to change the way I synchronized stuff thanks to Firefox new Sync feature that I decided it was more than enough: I searched for a better way for my passwords to be available on all my devices.

    The heart of the matter of choosing a good password is the following: I want my passwords to be easy to remember and easy to type while at the same time I want them to be impossible to either guess or crack. Usability versus security. This is somewhat summarized in this xkcd comis:

    Password Strength

    Some online service providers (such as Google and Dropbox) offer an interesting feature to defeat the natural tendency of users to choose easy-to-guess passwords, 2-steps authentication. This means you not only have to enter the password, you also have to provide another mean of authentication. Both previous providers use a code generated from some parameters known by both parties (provider and customer) but also time, so that guessing the code is only possible during a short amount of time (generally a minute). Another form of 2nd step is offered by banks as they send a code on your phone while you make an online transaction with your credit card, and then you have to enter it on the site to prove you’re the cardholder.

    Some other providers even delegate authentication to third-party providers such as Google (always it) or Github. A well known process to do that is OAuth2. OAuth2 could solve the many passwords problem if all service providers would offer delegation. Unfortunately, most of them prefer to do authentication on their own (as well as keep identities their own, but that’s a story for another day). Even more unfortunate is the fact that they only offer traditional login/password authentication challenges. Back to square one…

    Of course, I could make an effort to create a single hard-to-crack password… but with so many applications around, this is completely out of the question (or even impossible) to craft such a password for each one. None will advise to use the same password for all applications - as a hacker discovering the password on a site will be able to access all of them, but some advocate to prepend or append the domain name to the password. Alas, any simple automatic rule can easily be defeated by the means of automation cracking on the other side, so this should never ever been done - if you value the security of your accounts.

    The answer is very simple: for each application, create a dedicated hard-to-crack and impossible-to-remember password and store them somewhere safe. This place of safety can then be secured with a a-little-easier-to-crack and possible-to-remember master password - the key to the Holy Grail. In essence, this describes a solution known as a password manager. I had a couple of requirements for such a software:

    • Open Source: I prefer having an Open Source solution when possible as I think that qualified people can (at least in theory) perform a security audit on it. A closed source solution means security through obfuscation and this just doesn't work against real threats.
    • Multi-devices: yes, I'm one of those people that not only have multiple computers (office, desktop, laptop) with different Operating Systems (Windows and OSX) but also 2 phones and a tablet. So I want a solution that is compatible with all of those.
    • Configurable authentication: this requirement is very important as it not only let me choose how to authenticate into the store (e.g. password or key) but also increases the security of the solution.
    • Best practices: last but not least, I require security best practices to be implemented, such as hashing, salting, a slow hashing algorithm, etc.

    Having chosen my password manager, now comes the hard part: should I keep my password store on a USB key I always keep by me (and a copy in a secure location, just to be sure), on my laptop I carry everywhere or in the cloud? This amounts to the same problem as before, security or usability? I’ve decided to store it the cloud, on a provider infrastructure secured by 2-steps authentication. I’ve also ensured that this store is made avalaible on my different devices, though I’m not unaware that a chain is as strong as its weakest link. With my current setup, I’m not sure I’m completely free of any prying effort by 3 letters agencies, or more precisely I’m sure I’m not. However, I believe I’ve increased my robustness to online intrusion by several degrees of magnitude and that should prevent script kiddies to play some nasty tricks on me. Your turn, now…

    Categories: Technical Tags: security
  • Trust stores and Java versions

    My debugging contest of the week happened to take place on a IBM AIX system. The bug happened when we upgraded from Java version 1.4 to version 6 (which I admit is a pretty big step). Suddenly, an old application stopped working and its log displayed NoSuchAlgorithmException.

    A bit of context: when Java applications have to connect to hosts with SSL over HTTP, they must trust the host - it’s the same as when you browse a site with HTTPS. If the site can provide a SSL certificate that can proves its trustworthiness by tracing it back to a trust authority (Verisign and others), all is well. However, when browsing, you can always force the browser to trust a certificate that is not backed by a trusted authority. Such a luxury is not permitted when running an application, there’s no callback.

    Therefore, you can add certificates to the JVM truststore, which is located under the $JRE_HOME/security/lib. Alternatively, you can also pass a truststorewith the -Djavax.net.ssl.trustStore=<path/to/store> Java launch parameter. Before this problem, I was foolish to think you could keep the same truststore between different Java versions without a glitch. This is not the case: going back and forth a few times, we finally located the root problem.

    It seems that between Java version 1.4 and 6, the good people at IBM decided to completely change their security providers. This means that when a certificate is stored by a Java 1.4 JVM, the Java 6 JVM has no chance to read it.If you’ve had told me that before then, I would have laughed in your face. Reality is weirder than fiction.

    Conclusion: for Ops, it may be a good idea to consider always using the same security provider regardless of the operating system. Bouncy Castle is one of such providers, others surely exist.

    Note: Sun may be defunct, but their engineers kept the same security providers between Java 1.4 and 6

    Categories: Java Tags: security
  • SSL your Tomcat 7

    One thing I’m doing very often and always searching on the Internet is how to obtain a self-signed SSL certificate and install it in both my client browsers and my local Tomcat.

    Sure enough there are enough resources available online, but since it’s a bore to go looking for the right one (yes, some do not work), I figured let’s do it right once and document it so that it will always be there.

    Create the keystore

    Keystores are, guess what, files where your store your keys. In our case, we need to create one that will be used by both Tomcat and for the certificat generation.

    The command-line is:

    >keytool -genkey -keyalg RSA -alias blog.frankel.ch -keystore keystore.jks -validity 999 -keysize 2048
    

    The parameters are as follow:

    Parameter Value Description
    -genkey   Requests the keytool to generate a key. For all provided features, type keytool -help
    -keyalg RSA Wanted algorithm. The specified algorithm must be made available by one of the registered cryptographic service providers
    -keysize 2048 Key size
    -validity  999 Validity in days
    -alias blog.frankel.ch Entry in the keystore
    -keystore keystore.jks Keystore. If the keystore doesn’t exist yet, it will be created and you’ll be prompted for a new password; otherwise, you’ll prompted for the current store’s password

    Configure Tomcat

    Tomcat’s SSL configuration is done in the ${TOMCAT_HOME}/conf/server.xml file. Locate the following snippet:

    <!--
    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
        maxThreads="150" scheme="https" secure="true"
        clientAuth="false" sslProtocol="TLS" />
    -->
    

    Now, uncomment it and add the following attributes:

    • keystoreFile="/path/to/your/keystore.jks"
    • keystorePass="Your password"

    Note: if the store only contains a single entry, fine; otherwise, you’ll need to configure the entry’s name with keyAlias="blog.frankel.ch"

    Starting Tomcat and browsing to https://localhost:8443/ will show you Tomcat’s friendly face. Additionnaly, the logs will display:

    28 june 2011 20:25:14 org.apache.coyote.AbstractProtocolHandler init
    INFO: Initializing ProtocolHandler ["http-bio-8443"]
    

    Export the certificate

    The certificate is created from our previous entry in the keystore.

    The command-line is:

    >keytool -export -alias blog.frankel.ch -file blog.frankel.ch.crt -keystore keystore.jks
    

    Even simpler, we are challenged for the keystore’s password and that’s all. The newly created certificate is now available in the filesystem. We just have to distribute it to all browsers that will connect to Tomcat in order to bypass security warnings (since it’s a self-signed certificate).

    Spread the word

    The last step is to put the self-signed certificate in the list of trusted certificates in Firefox. For a quick and dirty way, import it in your own Firefox (Options -> Advanced -> Show certificates -> Import…) and distribute the %USER_HOME%"/Application Data/Mozilla/Firefox/Profiles/xzy.default/cert8.db file. It has to be copied to the %FIREFOX_HOME%/defaults/profile folder so that every single profile on the target machine is updated. Note that this way of doing will lose previously individually accepted certificates (in short, we’re overwriting the whole certificate database). For a more industrial process, look at the next section.

    To go further:

    Categories: JavaEE Tags: securityssltomcat
  • New declarative security features in Servlet 3.0

    Servlet 3.0 is not only about the replacement of the web.xml deployment descriptor by annotations. In this article, we’ll see what improvement it makes in the realm of security.

    In Servlet 2.5 (and before that), declarative security was about the following features:

    • authentication method (BASIC, FORM, etc)
    • authorization to differents parts of the application (web application resources)
    • data confidentiality and integrity
    • session time-out

    Servlet 3.0 adds standardized ways regarding two configuration items.

    The first parameter is how the session id is sent from the client to the server, so as for the latter to recognize the same session. Earlier in my carreer, I learnt that the first time an application server sends a response back to the client, it passes a cookie back and also appends to the URL, both referencing the unique jsessionid. Now, as soon as the second request is passed to the server, the latter knows the client accepts cookie or not and uses the appropriate mechanism: in essence, the strategy can be sumed up by “cookies first but fallback to URL rewriting if not possible”. Granted, there was a time when you couldn’t count on your client’s browsers to have cookies allowed. Nowadays, URL rewriting is first seen as a way to makes session hijacking easy as pie - even with HTTPS - since the id belongs to the URL. Hell, you’ll even find it in the logs! Servlet 3.0 aims to allow us to force the cookie strategy. The web.xml fragment to take care of this is the following:

    <session-config>
      <cookie-config>
        <secure>true</secure>
      </cookie-config>
    </session-config>
    

    Moreover, cookies themselves can be unsafe since they can be accessed by most browsers JavaScript engine, thus allowing client code to read it. Yet, a subset of browsers let us configure the engine so as to disable JavaScript access (read and/or write) for this cookie. Servlet 3.0 let compliant application server mark cookies as HttpCookie, which does the trick. Even if this feature is completely implementation dependent, it helps cover a part of our security worries. It’s achieved with the nex web.xml snippet:

    <session-config>
      <cookie-config>
        <http-only>true</http-only>
      </cookie-config>
    </session-config>
    

    Need for security are most often rediscoverd at the end of the development phase, when it costs much to implement. Moreover, some (if not most) securing nodes are a sysadmin’s responsibilities (configuring the 3rd-party LDAP, HTTPS, etc.). For example, the two previous capabilities were implementation dependent. This leaves security a very obscure field for young (and not-so-young) developers. I think that enhancements such as those provided by Servlet 3.0 tend to increase mutual understanding between developers and sysadmins.

    Categories: JavaEE Tags: securityservlet
  • Next book review: Spring Security 3

    My next book review will be on Spring Security 3 from Packt. I’ve heard of Spring Security since it was previously named Acegi Security but I hadn’t the chance to play with it. A book on the Spring Security model will let me dive into the subject, providing me with the means to see if it warrants further investigation on my part.

    The shipment is on its way, the rest is on my shoulders!

    Categories: Bookreview Tags: securityspring
  • Securing middleware products

    My work is IT architecture, meaning I focus on the early steps of a project. Once the application is in production, I usually leave it to systems and production engineers. For example, for JVM fine tuning, most of the clients I worked for have people that have the right skills to do that.

    Nevertheless, I need sometimes to sully my nails. This happens in two cases: when the client is too small to have such dedicated teams or when its production team are not experienced enough to handle the problem at hand. Believe it or not, it happened to me that I had to show WebSphere administrators how to connect JAAC connectors to a LDAP server.

    Anyway, I always value information on how to handle cases out of my usual scope: first, it never hurts to know more. Second, it is sometimes handy to sort what production teams tell you: some is real stuff, some is bulls. Likewise, I invite production teams to learn about development so that they may sort what is told to them too. Learning the other’s craft let you increase comprehension between different teams.

    Free checklist audits

    This week, I learned about a site that propose free benchmarks to audit your infrastructure’s security. This site is the Center for Internet Security. Proposed benchmarks are two-fold: part document about what is audited, part benchmarking tool. The former is freely downloadable; as for the second part, you must register. The rest of this article will focus on the document.

    Though many subjects will always be beyond my reach (I will never accept to secure an Oracle Database), one document is of utmost interest to me: the benchmark on Apache  Tomcat.

    This file include rules that, once you comply with them, will make your product more secure. Even if most of them are no-nonsense and you could think about it yourself, the document make a nice check-list. Some rules are really interesting in that I am afraid they are seldom enforced, some because of neglect, some because of lack of knowledge of the product.

    Enhancements

    Checklists provided by the CIS do lack some things though:

    • risk correlated to statistics. Some security holes aren't used by many hackers. How should I prioritize?
    • risk correlated to damage. What's the potential damage of not underdoing this action? For example, session hijacking will compromize users interactions with my application, not my server
    • trade-off. Many security features are not always desirable, and most have a trade-off, often in terms of performance. When I browse a merchant site, crypting my communications is overkill. Only during the payment phase is a real need to keep information secret.

    Rules examples

    For Tomcat, here’s is a sample of the audited rules.

    Separate Web content directory from Tomcat's system files

    Tomcat comes with its own file structure, including a webapp directory where webapps should reside. Yet, nothing prevents webapps to be outside this directory, even on another partition. From a security point-of-view, this will avoid directory traversal exploits: if a malicious user gains access to the webapps directory, he will not have access to the server.

    Moreover, from a maintenance point-of-view, you are able to upgrade Tomcat without redeploying your applications.

    Disable session façade recycling

    Tomcat’s model is to use façade on every entity of the HTTP model: request, response, session, etc. By default, Tomcat’s façades over sessions are reused when processing new requests in order to optimize memory use. Thus, this could lead a new request to have access to informations on sessions that are not tied to it. This is a security risk and should be turned off if one’s want to secure the server.

    Disable auto-deployment

    Tomcat’s default behaviour is to have a running thread that watches the webapps directory. Once a new war is detected by this thread, it deploys it automatically. Such action is very enjoyable in a development environment. In a production environment, users that have access to the directory could potentially put malicious webapps in it and have it deployed automatically. Thus, disabling auto-deployment increases the security of the Tomcat’ server.

    Conclusion

    Checklists provided by the CIS are very nice to have for production and security engineers. However, one should carefully evaluate the cost of enforcing the rule agains the risk of not enforcing it. Those are either not detailed enough in the documentation, or not provided at all.

    To go further:

    Categories: Technical Tags: middlewaresecurity
  • Custom LoginModule in Tomcat

    Tomcat manages application security through the concept of realm. A realm is a coherent package of name password pairs that identify valid users for a web application.

    Tomcat’s default realm is MemoryRealm. This realm reads the famous conf/tomcat-users.xml file and uses it check for name password pair validity. Tomcat also provides realms to check against pairs stored in a database, either through a direct connection, or through a configured datasource. The main disadvantage of these all these realms is that they force you to adopt Tomcat’ expected data structure. In most organizations, these constraints will be enough for the architect to rely upon custom or 3rd-party security components.

    In order to use your enterprise database structure, you would code a custom realm. Tomcat provides the org.apache.catalina.Realm interface. The drawback of implementing your own realm is that if you change your application server afterwards, all of your code would have been for naught. Yet, if you check Tomcat documentation thoroughly, you will see Tomcat also provides a JAASRealm. JAAS is the Java security feature and enable you to write custom security modules in a portable way. Tomcat’s JAASRealm performs as a adapter between realms and login modules so you only have to write a LoginModule and Tomcat will know how and when to call it.

    A LoginModule main method is login(). This is an example of a very basic module implementation:

    package ch.frankel.blog.loginmodule;
    
    import java.io.IOException;
    import java.util.Map;
    import javax.security.auth.Subject;
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.NameCallback;
    import javax.security.auth.callback.PasswordCallback;
    import javax.security.auth.callback.UnsupportedCallbackException;
    import javax.security.auth.login.LoginException;
    import javax.security.auth.spi.LoginModule;
    
    /**
     * Login module that simply matches name and password to perform authentication.
     * If successful, set principal to name and credential to "admin".
     *
     * @author Nicolas Fränkel
     * @since 2 avr. 2009
     */
    public class PlainLoginModule implements LoginModule {
    
        /** Callback handler to store between initialization and authentication. */
        private CallbackHandler handler;
    
        /** Subject to store. */
        private Subject subject;
    
        /** Login name. */
        private String login;
    
        /**
         * This implementation always return false.
         *
         * @see javax.security.auth.spi.LoginModule#abort()
         */
        @Override
        public boolean abort() throws LoginException {
            return false;
        }
    
        /**
         * This is where, should the entire authentication process succeeds,
         * principal would be set.
         *
         * @see javax.security.auth.spi.LoginModule#commit()
         */
        @Override
        public boolean commit() throws LoginException {
    
            try {
                PlainUserPrincipal user = new PlainUserPrincipal(login);
                PlainRolePrincipal role = new PlainRolePrincipal("admin");
                subject.getPrincipals().add(user);
                subject.getPrincipals().add(role);
                return true;
            } catch (Exception e) {
                throw new LoginException(e.getMessage());
            }
        }
    
        /**
         * This implementation ignores both state and options.
         * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject,
         *      javax.security.auth.callback.CallbackHandler, java.util.Map,
         *      java.util.Map)
         */
        @Override
        public void initialize(Subject aSubject, CallbackHandler aCallbackHandler, Map aSharedState, Map aOptions) {
            handler = aCallbackHandler;
            subject = aSubject;
        }
    
        /**
         * This method checks whether the name and the password are the same.
         * @see javax.security.auth.spi.LoginModule#login()
         */
        @Override
        public boolean login() throws LoginException {
            Callback[] callbacks = new Callback[2];
            callbacks[0] = new NameCallback("login");
            callbacks[1] = new PasswordCallback("password", true);
            try {
                handler.handle(callbacks);
                String name = ((NameCallback) callbacks[0]).getName();
                String password = String.valueOf(((PasswordCallback) callbacks[1]).getPassword());
                if (!name.equals(password)) {
                    throw new LoginException("Authentication failed");
                }
                login = name;
                return true;
            } catch (IOException e) {
                throw new LoginException(e.getMessage());
            } catch (UnsupportedCallbackException e) {
                throw new LoginException(e.getMessage());
            }
        }
    
        /**
         * Clears subject from principal and credentials.
         *
         * @see javax.security.auth.spi.LoginModule#logout()
         */
        @Override
        public boolean logout() throws LoginException {
            try {
                PlainUserPrincipal user = new PlainUserPrincipal(login);
                PlainRolePrincipal role = new PlainRolePrincipal("admin");
                subject.getPrincipals().remove(user);
                subject.getPrincipals().remove(role);
                return true;
            } catch (Exception e) {
                throw new LoginException(e.getMessage());
            }
        }
    }
    

    Once your login module is ready, you have to configure Tomcat to use it. JAASRealms, like any other realms can be configured for the whole Tomcat engine, for a specific virtual host or for a single web application. The simplest is to configure the realm for our application. It may happen in the Servers/Tomcat localhost config/server.xml if you work under Eclipse or in you /conf/.xml</code> if you cleanly deploy your web application but the following lines should be added between the Context tags:

    <Realm className="org.apache.catalina.realm.JAASRealm" appName="CustomLogin"
        userClassNames="ch.frankel.blog.loginmodule.PlainUserPrincipal"
        roleClassNames="ch.frankel.blog.loginmodule.PlainRolePrincipal"
    </Realm>
    

    Now that Tomcat knows it should use a JAASRealm, the final step is to configure JAAS itself. The first thing to do is to create a jaas.config file. This file has a very specific structure. Let’s take a look:

    CustomLogin {
        ch.frankel.blog.loginmodule.PlainLoginModule
        sufficient;
    };
    

    The first line references the login module class and corresponds to appName in the server.xml. The second line tells JAAS how to use this module. There are 4 acceptable values:

    Required
    This module must authenticate the user. But if it fails, the authentication nonetheless continues with the other login modules in the list.
    Requisite
    If the login fails then the control returns back to the application, and no other login modules will execute.
    Sufficient
    If the login succeeds then the overall login succeeds, and control returns to the application. If the login fails then it continues to execute the other login modules in the list.
    Optional
    The authentication process continues down the list of login modules irrespective of the success of this module.
    Now, you have to reference this file. Just launch Tomcat with this VM property: -Djava.security.auth.login.config=<JAAS_CONFIG>. From this point, if you correctly configure declarative security in you web application web.xml, it will use your login module. Of course, in a real-world case, you would check against a database, a LDAP server or a web-service to authentify your users but this small example provide you with the base to create such a complex code. Sources for this very basic example can be found here.
    Categories: JavaEE Tags: jaasloginmodulerealmsecuritytomcat