Skip to content

Latest commit

 

History

History
223 lines (149 loc) · 11.2 KB

README-WildFly9.md

File metadata and controls

223 lines (149 loc) · 11.2 KB

PBKDF2 - SaltedDatabaseServerLoginModule

A free Java implementation of RFC 2898 / PKCS#5 PBKDF2

I have updated the SaltedDatabaseServerLoginModule to work with WildFly9 (JBoss). This is a Custom Login Module that extends the stock "Database" login module. All database interaction continues to be handled by that stock module, it is just the verification step that is done differently.

Quite frankly, this was a bit of a challenge. Why? There is a load of documentation out there but it's sometimes hard to figure out what is outdated and what is not. Unfortunately, some info does not really relate to the current WildFly9. So, I shall describe in detail how I got this working.

The required steps include

  1. Making the PBKDF2 code available via a JBoss Module

  2. Creating a "Security Domain" that references this module

  3. Create required database table

  • For simplicity, we use the built-in H2 database
  1. Create one or more user entries

  2. Access a protected resource

To ease these last three steps, find a small Web Application provided (PBKDF2-Sample-1.1.0.war, amend the version number as appropriate).

Note that this Web Application is for demonstration only, you do not need to deploy this to use the "SaltedDatabaseServerLoginModule" in your system.

WildFly Setup

Do a clean WildFly install to some folder of your choice. Let's use C:\Server\wildfly-9.0.0.CR2:

unzip wildfly-9.0.0.CR2.zip -d C:\Server

Test-run the server by calling standalone.bat. The log also shows the exact version that we're running here:

C:\Server\wildfly-9.0.0.CR2\bin\standalone.bat
...
... WFLYSRV0025: WildFly Full 9.0.0.CR2 (WildFly Core 1.0.0.CR6) started in ...

Finally, call http://localhost:8080 for WildFly's welcome page.

Integration into WildFly9

Module

As a first step, we need to make the SaltedDatabaseServerLoginModule and PBKDF2 classes known to WildFly. For this , we create a JBoss Module. This module will be referenced from the Security Domain, below

  1. Create a folder C:\Server\wildfly-9.0.0.CR2\modules\de\rtner\PBKDF2\main.

  2. Copy file PBKDF2-1.1.0.jar there.

  3. Create a JBoss module descriptor file named module.xml there that references the JAR

  • Amend the version number as appropriate.
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="de.rtner.PBKDF2">
    <resources>
        <resource-root path="PBKDF2-1.1.0.jar"/>
    </resources>
    <dependencies>
        <module name="org.picketbox"/>
        <module name="javax.api"/>
    </dependencies>
</module>

Create Security Domain

Edit C:\Server\wildfly-9.0.0.CR2\standalone\configuration\standalone.xml and insert a new Security Domain named "PBKDF2DatabaseDomain" in the <security-domains> section, i.e. before the "other" domain.

The name is arbitrary, of course, and will be referenced in below Web Application. The key points here are to state the fully qualified class name and the module that the class is to be loaded from.

Note that the SQL is for illustration only. To keep things simple, we'll use only a single "Users" table, with no user-to-role table. All users will simply be put into the "manager" role, via that 2nd SQL statement.

...
<subsystem xmlns="urn:jboss:domain:security:1.2">
    <security-domains>

        <security-domain name="PBKDF2DatabaseDomain">
            <authentication>
                <login-module code="de.rtner.security.auth.spi.SaltedDatabaseServerLoginModule" flag="required" module="de.rtner.PBKDF2">
                    <module-option name="dsJndiName" value="java:jboss/datasources/ExampleDS" />
                    <module-option name="principalsQuery" value="SELECT password FROM Users WHERE username=?" />
                    <module-option name="rolesQuery" value="SELECT DISTINCT 'manager', 'Roles' FROM Users WHERE username=?" />
                </login-module>
            </authentication>
        </security-domain>

        <security-domain name="other" cache-type="default">
             ...

Web Application Configuration

For demonstration, we use a simply JEE web application. It's main deployment descriptor is WEB-INF/web.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<web-app>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <security-constraint>
        <web-resource-collection>
            <url-pattern>/hello.jsp</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>manager</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <auth-method>BASIC</auth-method>
    </login-config>

    <security-role>
        <role-name>manager</role-name>
    </security-role>

</web-app>

Security Considerations

A key point here is to use "BASIC" authentication. The Login Module needs to have access to the plaintext password. All of the standard authentication methods supported by browsers other than BASIC either supply certificates only or supply the password in a digested form that is not suitable as an input to the PBKDF2 procedure.

It is best to provide access to your login pages via SSL/TLS only. It is generally believed that the risk of plaintext password transmission with BASIC authentication is sufficiently mitigated through the TLS-supplied outer encryption.

The key advantage when using PBKDF2 to the server side is that your user/password database can hold iterated password hashes, whereas DIGEST authentication only supports a non-iterated hash. An attacker will find it much more difficult to brute-force user passwords in case of unauthorized retrieval of the user database.

The random salt will effectively thwart the use of pre-computed password hashes. The iteration will multiply the effort to brute-force single-user passwords.

The above system could further be improved:

  1. The supplied user name itself could be subjected to PBKDF2. The database will then not contain cleartext user names. Only if you know a user name can you determine if an entry for that user name exists in the database.

  2. The password iterated hash could be made to depend on the user name. This prevents substitution of one known PBKDF2 password hash into the password record of another user.

  3. The salt used in all computations could be further enhanced by concatenation with a random server configuration value of sufficient length that would not be stored in the database. This effectively works as another HMAC layer. Leaking the database without that configuration value would make brute-forcing infeasible even for weak user passwords.

  4. Obviously, a web application that only has a single protected resource while at the same time failing to protect its password-entry mechanism is, well, sub-optimal. Ideally, the "Users" table will be made read-only on database level for your front-end system, with updates / new user registrations being done exclusively through an independent internal system.

Connection the Web App to the Domain

Put a WEB-INF/jboss-web.xml file into the Web App. This links the Web App to the security domain. Note that earlier JBoss versions required a prefix to the domain name. WildFly9 does not use a prefix, just specify the domain name as defined above in "standalone.xml".

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
    <security-domain>PBKDF2DatabaseDomain</security-domain>
</jboss-web>

Trying it out

  1. Deploy the Web Application by copying file PBKDF2-Sample-1.1.0.war to C:\Server\wildfly-9.0.0.CR2\standalone\deployments. Note: You may re-build the Web Application locally using the build-web.gradle script.

  2. Re-start WildFly to make the deployment and changes to standalone.xml have effect.

  3. Access the web application as http://localhost:8080/PBKDF2-Sample-1.1.0/index.jsp

  4. Hit the "Create Users Table" button. Press "Back". After the WildFly restart, the H2 starts out empty. This creates the user table that we'll fill and use in the next steps.

  5. Press the "Add User" button (you may keep the filled-in default password value). This puts a line into the "Users" table. Adding another value to an existing user replaces the entry. Adding an empty password removes the user. Press "Back".

  6. Now we're all set. Click the "secured resource" http://localhost:8080/PBKDF2-Sample-1.1.0/hello.jsp. This should open you browser's "BASIC" password entry dialog. Enter "john" / "password" and enjoy the greeting presented by the "hello.jsp" page.

Server Logging

Can't log in? Duh. Works, but you want to see what's going on? Cool. First thing you want to do is enable logging for the security subsystem. Enable TRACE logging for "org.jboss.security". Also make sure to bump the appender level to TRACE to see something in the log file. Do this by editing logging section of standalone.xml and restarting the server:

<server xmlns="urn:jboss:domain:3.0">
    ...
    <profile>
        <subsystem xmlns="urn:jboss:domain:logging:3.0">
            ...
            <periodic-rotating-file-handler name="FILE" autoflush="true">
                <level name="TRACE"/>
                ...
            </periodic-rotating-file-handler>
            ...
            <logger category="org.jboss.security">
                <level name="TRACE"/>
            </logger>

Now check the log file (C:\Server\wildfly-9.0.0.CR2\standalone\log\server.log) for Picketbox output ("PBOXxxxxx"), such as:

2015-06-14 00:40:26,658 TRACE [org.jboss.security] (default task-1) PBOX00224: End getAppConfigurationEntry(PBKDF2DatabaseDomain), AuthInfo: AppConfigurationEntry[]:
[0]
LoginModule Class: de.rtner.security.auth.spi.SaltedDatabaseServerLoginModule
ControlFlag: LoginModuleControlFlag: required
Options:
name=dsJndiName, value=java:jboss/datasources/ExampleDS
name=principalsQuery, value=SELECT password FROM Users WHERE username=?
name=rolesQuery, value=SELECT DISTINCT 'manager', 'Roles' FROM Users WHERE username=?

Database Details

The "Users" table in the sample database has just two columns:

  1. A clear text username column
  • Sample value: "john"
  1. A String-valued holder of the PBKDF2-processed password. This token contains the entry-specific salt and the entry-specific iteration count.
  • Sample value: "7008119CDC9AD6D9:1000:D213E20E346F4A762350C530BBBAD375ABA3FEB6" ("your password")
  • The desired encoding to use when converting that password string to bytes can be specified using security domain module options. See SaltedDatabaseServerLoginModule JavaDoc.

The sample configuration shown above does not make use of a second/further database table(s) to store user-to-role (-group) associations. See virtually all other examples on the 'net - they all use multiple database tebles.

References

http://stackoverflow.com/questions/22291407/jboss-wildfly-database-login-module

http://rtner.de/software/PBKDF2.html