Tuesday, 26 September 2017

WildFly Elytron - Add Kerberos Authentication To Existing Web Application

When using WildFly Elytron to secure a web application it is possible to customise the authentication policy without modifying the web application, this is something that could be very useful as an application transitions though different environments such as development, testing, staging, and production - in each of these environments a custom authentication policy can be used without requiring a custom build of the web application.

This blog post is going to take a simple web application secured by HTTP BASIC authentication and convert it to use WildFly Elytron using SPNEGO authentication with fallback to BASIC without repackaging the application.

Example Application

This blog post have been written using the following example web application: -

https://github.com/wildfly-security-incubator/elytron-examples/tree/master/simple-webapp

This application contains a single welcome page with a link to a secured servlet that requires the caller have the role 'Users', the resulting deployment contains a web.xml that specifies authentication should use HTTP BASIC authentication.

The example application contains no JBoss or WidFly specific descriptors or annotations and instead depends on the default configuration within the Undertow subsystem using the 'other' security domain which pulls the user information from the application-users.properties and application-roles.properties.

Test User

Within my test Kerberos environment the main user I test with is 'testuser', before proceeding to configure the server I will ensure there is an entry for this user in the properties files with the following command: -

  ./add-user.sh -a -u testuser -p password -g Users

Configuring the Server

These instructions are written using a recent build of WildFly 11 however it should be possible to use them against either the CR1 release or once available the Final release.

Although they are not in use by default the default server configuration of WildFly 11 contains many Elytron components already configured to work with the legacy security properties, the steps here will make use of those as much as is possible and just define new components to achieve SPNEGO authentication as well.

The next set of commands are all executed within the JBoss CLI.

When working with Kerberos in a test environment I tend to find it easier to define the realm and KDC information as system properties: -


./system-property=sun.security.krb5.debug:add(value=true)
./system-property=java.security.krb5.realm:add(value=ELYTRON.ORG)
./system-property=java.security.krb5.kdc:add(value=kdc.elytron.org)


The next command is to define the server's Kerberos identity.

./subsystem=elytron/kerberos-security-factory=test-server:add( \
    path=/home/darranl/src/kerberos/test-server.keytab, \
    principal=HTTP/test-server.elytron.org@ELYTRON.ORG, \
    debug=true) 


The existing 'ApplicationDomain' and the realm it already references are going to be used.

SPNEGO authentication by default results in an identities name containing the Kerberos realm as a suffix so will now define a principal transformer to strip the realm.

 ./subsystem=elytron/regex-principal-transformer= \
    realm-stripper:add( \
    pattern="@ELYTRON.ORG", replacement="")

The final step within the Elytron subsystem is to define a HTTP authentication factory that supports both SPNEGO and BASIC authentication.

./subsystem=elytron/http-authentication-factory=spnego-http-authentication:add(security-domain=ApplicationDomain, \
    http-server-mechanism-factory=global, \
    mechanism-configurations=[ \
    {mechanism-name=SPNEGO, \
    credential-security-factory=test-server, \
    pre-realm-principal-transformer=realm-stripper}, \
    {mechanism-name=BASIC} \
    ])

The ordering of the mechanism names was important here as we want SPNEGO to be the preferred authentication mechanism with fallback to BASIC if the web browser can not respond. 

For this specific example we will be overriding the mechanisms defined within the web.xml so it is important to only list the mechanisms we want to actually use.

The final configuration step is within the Undertow susbystem to configure any deployments that use the 'other' security domain to instead use the HTTP authentication factory defined here and override any defined authentication mechanisms.

/subsystem=undertow/application-security-domain=other:add( \
    http-authentication-factory=spnego-http-authentication, \
    override-deployment-config=true)

Deploy Example Application

If the web application has already been deployed the server should be reloaded / restarted for the new security policy to apply to it, alternatively it can be deployed using the WildFly Maven plug-in.

mvn wildfly:deploy

Access Web Application

For my Kerberos test environment the server is test-server.elytron.org so I can access the web application through the following URL: -

http://test-server.elytron.org:8080/simple-webapp

At this point if I access the web application after obtaining a Kerberos ticket for 'testuser' and subsequently click on the 'Access Secured Servlet' link SPNEGO authentication will silently take place for me as I have already configured my web browser to enable SPNEGO authentication.

If I don't have a local Kerberos ticket or if my web browser does not have SPNEGO authentication enabled I will receive the BASIC authentication prompt and will be able to use the username and password I defined at the start of this blog post.

One point to keep in mind, SPNEGO authentication is cached by default against the HTTP session - if switching from having a ticket to not having a ticket restart either the browser or the server.











Friday, 8 September 2017

Using WildFly Elytron with Undertow Standalone

The WildFly Elytron project has been developed to provide the security requirements of the WildFly application server, however the development of WildFly Elytron has produced a security framework which does not depend on the application and can be used outside of the application server.

This means that it is possible to use WildFly Elytron in situations outside of the application server, this blog post demonstrates how WildFly Elytron can be used to secure an embedded Undertow server.

If you visit the main page for Undertow towards the bottom of the page is a code example showing how to start a simple HelloWorld server using Async IO.

http://undertow.io/

This blog post goes one step further and illustrates how WildFly Elytron can be added to the example to secure access to the HttpHandler using HTTP Basic authentication.

The components demonstrated in this example are the same components we use within the application server, the difference being that they are programatically configured and wired together rather than using the subsystem for configuration.

The code for the example can be found in the project called 'undertow-standalone' in the Git repository https://github.com/wildfly-security-incubator/elytron-examples.

Dependencies

The example project has the following key dependencies although these will pull in some additional dependencies.

io.undertow:undertow-core
This is the main dependency on Undertow, this example is only demonstrating with the core Undertow APIs so the servlet dependency is not required.

org.wildfly.security:wildfly-elytron
This is the dependency on the WildFly Elytron security framework.

org.wildfly.security.elytron-web:undertow-server
The Undertow project does not have a dependency on WildFly Elytron and the Elytron project does not have a dependency on Undertow, the Elytron Web project acts as an intermediate project to join the two together.

In future releases of Elytron Web we may also be able to look into integration with other servers following a similar pattern to how we have integrated with Undertow.

Example

The initial example is very similar to the example on undertow.io, the main difference being the call to a method 'wrap' to wrap the HttpHandler.

    public static void main(String[] args) throws Exception {
        final SecurityDomain securityDomain = createSecurityDomain();

        Undertow server = Undertow.builder()
                .addHttpListener(8080, "localhost")
                .setHandler(wrap(new HttpHandler() {

          public void handleRequest(HttpServerExchange exchange) 
               throws Exception {
                                            
exchange.getResponseHeaders().
  put(Headers.CONTENT_TYPE, "text/plain");                       
exchange.getResponseSender().
  send("Hello " + securityDomain.getCurrentSecurityIdentity().getPrincipal().getName());
                    }
                 }, securityDomain)).build();
        server.start();
    }

The first thing to happen during wrapping is an Elytron security domain is assembled, this domain contains a single user 'elytron' with a password of 'Coleoptera'.

    private static SecurityDomain createSecurityDomain() throws Exception {
        PasswordFactory passwordFactory = PasswordFactory.getInstance(ALGORITHM_CLEAR, elytronProvider);

        Map<String, SimpleRealmEntry> passwordMap = new HashMap<>();
        passwordMap.put("elytron", new SimpleRealmEntry(Collections.singletonList(new PasswordCredential(passwordFactory.generatePassword(new ClearPasswordSpec("Coleoptera".toCharArray()))))));

        SimpleMapBackedSecurityRealm simpleRealm = new SimpleMapBackedSecurityRealm(() -> new Provider[] { elytronProvider });
        simpleRealm.setPasswordMap(passwordMap);

        SecurityDomain.Builder builder = SecurityDomain.builder()
                .setDefaultRealmName("TestRealm");

        builder.addRealm("TestRealm", simpleRealm).build();
        builder.setPermissionMapper((principal, roles) -> PermissionVerifier.from(new LoginPermission()));

        return builder.build();
    }

In this example a simple in memory security realm backed by a Map is used, however any of the other Elytron security realms could be used or even a custom security realm implementation if desired.

After assembling the security domain the next step is creating a HttpAuthenticationFactory, the HttpAuthenticationFactory is the overall authentication policy that makes authentication mechanisms backed by the security domain available.

    private static HttpAuthenticationFactory createHttpAuthenticationFactory(final SecurityDomain securityDomain) {
        HttpServerAuthenticationMechanismFactory providerFactory = new SecurityProviderServerMechanismFactory(() -> new Provider[] {elytronProvider});
        HttpServerAuthenticationMechanismFactory httpServerMechanismFactory = new FilterServerMechanismFactory(providerFactory, true, "BASIC");

        return HttpAuthenticationFactory.builder()
                .setSecurityDomain(securityDomain)
                .setMechanismConfigurationSelector(MechanismConfigurationSelector.constantSelector(
                        MechanismConfiguration.builder()
                                .addMechanismRealm(MechanismRealmConfiguration.builder().setRealmName("Elytron Realm").build())
                                .build()))
                .setFactory(httpServerMechanismFactory)
                .build();
    }

At this stage we can see how the original HttpHandler is wrapped using the resulting HttpAuthenticationFactory and some additional Elytron and Undertow APIs to enable security.

    private static HttpHandler wrap(final HttpHandler toWrap, final SecurityDomain securityDomain) {
        HttpAuthenticationFactory httpAuthenticationFactory = createHttpAuthenticationFactory(securityDomain);

        HttpHandler rootHandler = new ElytronRunAsHandler(toWrap);

        rootHandler = new AuthenticationCallHandler(rootHandler);
        rootHandler = new AuthenticationConstraintHandler(rootHandler);

        return ElytronContextAssociationHandler.builder()
                .setNext(rootHandler)
                .setMechanismSupplier(() -> {
                    try {
                        return Collections.singletonList(httpAuthenticationFactory.createMechanism("BASIC"));
                    } catch (HttpAuthenticationException e) {
                        throw new RuntimeException(e);
                    }
        }).build();
    }

Build and Run

The example project is a standard Maven project so provided Maven is installed along with Java 8 the project can be built using 'mvn install'.

Once built the server can be started using the exec plug-in 'mvn exec:exec'.  This should result in the server starting and listening on port 8080 for incoming requests.

Note: As an example project there is not a lot of output from the project to the console, feel free to add more output if desired to see each stage as it occurs.

After starting the project you should be able to access the server using curl.

undertow-standalone]$ curl -v http://127.0.0.1:8080/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.53.1
> Accept: */*
< HTTP/1.1 401 Unauthorized
< Connection: keep-alive
< WWW-Authenticate: Basic realm="Elytron Realm"
< Content-Length: 0
< Date: Fri, 08 Sep 2017 15:16:30 GMT
* Connection #0 to host 127.0.0.1 left intact

At this stage curl was not supplied with any user details so we can see the HTTP Basic authentication challenge and the request ends.

If we now provide a username and enter the password when prompted we see a full HTTP exchange.

undertow-standalone]$ curl -v http://127.0.0.1:8080/ --user elytron
Enter host password for user 'elytron':
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
* Server auth using Basic with user 'elytron'
> GET / HTTP/1.1
> Host: 127.0.0.1:8080
> Authorization: Basic ZWx5dHJvbjpDb2xlb3B0ZXJh
> User-Agent: curl/7.53.1
> Accept: */*
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-Type: text/plain
< Content-Length: 13
< Date: Fri, 08 Sep 2017 15:17:45 GMT
* Connection #0 to host 127.0.0.1 left intact
Hello elytron

The 'Hello elytron' returned at the end is the message from the HttpHandler where 'elytron' is the name of the authenticated principal calling the HttpHandler.




Friday, 14 July 2017

WildFly Elytron - Principal Transformers, Realm Mappings, and Principal Decoders

Within the WildFly Elytron configuration it is possible to specify multiple principal transformers, realm mappers, and a principal decoder - this blog post is to describe how they all fit together during the authentication process.

During the authentication process the principal transformers and principal decoders form a very similar function in that they are both used to map principals from one form to another, principal transformers can also be used to validate a principal as an example double check the formatting so authentication can be terminated early if an invalid principal is detected.

At the appropriate state in the process that is being described in this blog post the realm mappers will then operate on the mapped principal to identify which security realm should be used to load the identity.

Here are a couple of diagrams to illustrate how these concepts fit together, the remainder of this blog post will describe the steps in more detail.

The first diagram illustrates the general states the authentication process undergoes to map the Principal used for authentication.

Identity Assignment States 
The next diagram illustrates how the various transformers, decoders, and mappers can be configured for Elytron authentication.

Configuration Relationships

Resolve Mechanism Configuration

When the authentication processes commences for a single authentication mechanism the first step is to resolve the MechanismConfiguration that should be used, this is resolved by taking into account the name of the selected mechanism, the host name, and the protocol.

During this stage the mechanism realm configuration will also be resolved, the authentication mechanism will either request this by name or if the mechanism does not request this then the first one in the list is used.

Note: The mechanism realm is specifically in relation to the realm name negotiated by the authentication mechanism if applicable and is independent of the security realm representing the identity store.

Pre Realm Mapping

The purpose of this state is to take the Principal from the form that was provided by the authentication mechanism and map it to the form that can be used to identify which security realm to use to load the identity.

At the very end of the authentication process the identity is represented by a SecurityIdentity which contains a single Principal, the Principal will be the one created by this mapping stage.

The principal transformers and principal decoder will be called in the following order: -

1. Mechanism Realm - pre-realm principal-transformer
2. Mechanism Configuration - pre-realm principal transformer
3. Security Domain - principal-decoder
4. Security Domain - pre-realm-principal-transformer

If the end result is a null principal and error will be reported and authentication will terminate.

Realm Mapping

The next stage is to take the mapping principal and map it to a realm name to identify the name of the Security Realm to use to load the identity.

Note:  At this stage the realm name is the name of the SecurityRealm as referenced by the SecurityDomain and is not the mechanism realm name.

The configuration will be inspected for the first realm mapper that can be found in the following locations: -

A. Mechanism Realm - realm-mapper
B. Mechanism Configuration - realm-mapper
C. Security Domain - realm-mapper

If a RealmMapper is identified but that mapper returns null when mapping the Principal then the default-realm specified on the Security Domain will be used instead.

If no RealmMapper is available then the default-realm on the SecurityDomain will be used.

Post Realm Mapping

After the realm has been identified a further round of principal transformation happens, this time the following transformers are called: -

5. Mechanism Realm - post-realm principal-transformer
6. Mechanism Configuration - post-realm principal-transformer
7. Security Domain - post-realm principal-transformer

As before if the result is a null principal an error will be reported and authentication will be terminated.

Final Principal Transformation

After the post realm mapping stage one final round of principal transforming takes place, this time the following transformers are called in order.

8. Mechanism Realm - final principal-transformer
9. Mechanism Configuration - final principal-transformer
10. Realm Mapping - principal-transformer

Once again a null principal will result in an error being reported and authentication being terminated.

Having to transformations after the realm has been identified allows for mechanism specific transformations to be applied both before and after domain specific transformations, if this is not required then either the post-realm principal transformers or the final principal-transformers can be used to obtain the same result.

The End

It is only now at the very end of principal transformation that the security realm previously identified will be call to obtain the RealmIdentity that is now used for authentication to continue.

The key points to keep in mind are: -

  • The Principal created by the pre-realm-principal-transformers is: -
    • The Principal used to map the SecurityRealm
    • The Principal that will be associated with the resulting SecurityIdentity.
  • The Principal created after the final principal transformers is: -
    • The Principal that will be passed to the SecurityRealm to obtain the RealmIdentity.


Wednesday, 24 February 2016

WildFly Elytron - SSL Configuration

One of the features being delivered by the upcoming WildFly Elytron integration within WildFly is the ability to provide SSL definitions centrally and then reference these definitions from elsewhere in the configuration.  This blog post demonstrates how to centrally configure SSL resources and subsequently use them to enable SSL both for web applications deployed to Undertow and for management of the server.  This blog post will also demonstrate how the same approach can be taken in domain mode to enable SSL to manage the server.

Environment

As WildFly 10 has been prepared for release the WildFly Elytron development has continued in parallel, to run the examples described here build the following three tags in order: -

https://github.com/wildfly-security-incubator/wildfly/tree/10.0.0.Final-Elytron1

The resulting server is the equivalent of a little before the WildFly 10 release but with the addition of the integration with WildFly Elytron.

After the WildFly build you will find a usable distribution in: -
 'wildfly/dist/target/wildfly-10.0.0.Final-Elytron1'.

Configuring SSL

For this example I am using a JKS KeyStore which contains a single entry which contains a private key and self signed certificate, certificate authority signed certificates would also be usable here.

To start up the application server with the WildFly Elytron subsystem included in the default configuration use the following command: -

bin/standalone.sh -c standalone-elytron.xml

Next start up the CLI and connect to the running server.

The approach taken with the WildFly Elytron subsystem is that different components required for security are defined independently of each other and then are assembled together for the final solution - this approach is taken to make it a lot easier to integrate custom implementations of the different components and to even allow other subsystems to advertise their own implementations within the application server so they can be used either with or in place of the Elytron implementations.

Within the CLI we next need to define three new resources within the Elytron subsystem: -
  1. KeyStore
  2. KeyManager(s)
  3. Server SSL Context
A new KeyStore can be added with the following command: -

./subsystem=elytron/keystore=server:add(type=jks, 
    path=/home/darranl/server.keystore, 
    password=keystore_password)

The arguments to this command should be fairly self explanatory.

The KeyManagers resource is then added with: -

./subsystem=elytron/key-managers=server:add(algorithm=SunX509, 
    keystore=server, 
    password=keystore_password)

In this command the 'keystore' argument is a reference to the KeyStore defined in the first command.

Then the Server SSL Context is defined: -

./subsystem=elytron/server-ssl-context=server:add(
    key-managers=server, 
    protocols=[TLSv1_2])

The 'key-managers' argument is a reference back to the KeyManagers resource defined in the previous command.

The server-ssl-context resource is where all policy information related to SSL will be defined, in this example however as this is a bare minimum definition we just reference the previously defined key-managers and specify that the protocol should be TLS 1.2.

Enable SSL With Undertow

Now that the resources are defined the next step is to enable the use of this resource within Undertow so the following command adds a https-listener referencing the previously defined server-ssl-context: -

./subsystem=undertow/server=default-server/
    https-listener=https:add(
        ssl-context=server, 
        socket-binding=https)

It should now be possible to connect a web browser to port 8443 and the previously defined SSL configuration within the Elytron subsystem will be used.

Enable SSL for Management over HTTP

Within the CLI with a couple more commands the same SSL resources can be used to enable SSL for access to the HTTP management interface: -

./core-service=management/management-interface=http-interface:
    write-attribute(
        name=ssl-context, 
        value=server)

The first command adds a reference to the previously defined server-ssl-context.

./core-service=management/management-interface=http-interface:
    write-attribute(
        name=secure-socket-binding, 
        value=management-https)

This second command then just enables HTTPS access on port 9993.

This last command will also require you to execute :reload for the changes to take effect.

Now you can connect to https://localhost:9993 and this will also be using the same previously defined SSL resources.

Enable SSL for Management over HTTP - Domain Mode

For this next step we now need to shut down the standalone server and start up domain mode with the host controller configured to enable Elytron.

bin/domain.sh --host-config=host-elytron.xml

When running within domain mode the host controller process can now contain it's own subsystems, first we need to repeat the three commands to add SSL resources but this time to the host controllers own Elytron subsystem.


./host=master//subsystem=elytron/keystore=server:
    add(
        type=jks, 
        path=/home/darranl/server.keystore, 
        password=keystore_password)

./host=master/subsystem=elytron/key-managers=server:
    add(
        algorithm=SunX509, 
        keystore=server, 
        password=keystore_password)

./host=master//subsystem=elytron/server-ssl-context=server:
    add(
        key-managers=server, 
        protocols=[TLSv1_2])

The only difference to the previous commands is in each of these the address has been prefixed with 'host=master' - this is so that the Elytron subsystem definition specific to the host controller is configured - apart from that it is exactly the same subsystem.

As before apart from a difference in address this SSL definition can be referenced in the same way: -

./host=master/core-service=management/
    management-interface=http-interface:
        write-attribute(
            name=ssl-context, 
            value=server)

How the port is specified in domain mode is slightly different so this is specified with: -

./host=master/core-service=management/
    management-interface=http-interface:
        write-attribute(
            name=secure-port, 
            value=9993)

The host controller can then be restarted with: -

./host=master:reload

At this point connections to https://localhost:9993 will be using this SSL definition.

Summary

The end result of this development will mean that administrators can learn how to define and tweak SSL policies all within the context of Elytron and the Elytron subsystem and then these policies can be applied across the application server where subsystems reference these resources - the aim being so that administrators do not need to learn how to configure SSL within each subsystem independently.

Advanced Configuration.

This blog post has focussed on the minimal steps required to get SSL enabled, I will follow up with some additional blog posts to cover the following features.

  • Alias Filtering
  • Cipher Suite Selection
  • Client Cert Authentication
  • Inspecting the KeyStore contents using the management model.
  • Inspecting (and invalidating) active sessions from the configured SSL resources.

Monday, 3 August 2015

WildFly Elytron 1.0.0.Alpha3 Released

At the end of last week we released WildFly Elytron 1.0.0.Alpha3

http://repo1.maven.org/maven2/org/wildfly/security/wildfly-elytron/1.0.0.Alpha3/

WildFly Elytron will be providing both SASL and HTTP authentication mechanisms for use within the application server, where possible stronger authentication mechanisms will be preferred over weaker mechanisms - there are challenges in achieving this but our ideal situation is to have no re-usable password representations transmitted over the network and also no passwords stored in reversible format on the local file system.

The 1.0.0.Alpha3 release has primarily been focussed on adding capabilities to the project to enable administrators to define policies to use when selecting SASL mechanisms and also some custom settings for when a mechanism is actually created.


  • Ability to specify protocol passed into the mechanism.
  • Ability to specify server-name passed into the mechanism.
  • Definition of properties to pass into mechanism for available mechanism evaluation and mechanism creation.
  • Filtering of mechanisms by name.
  • Filtering of mechanisms by name and provider.
  • Mechanism loading from a Provider[]
  • Service loader based mechanism loading from a provided ClassLoader.
  • Mechanism filtering based on supported credentials.


For the final item in that list at it's core the APIs that are being developers within WildFly Elytron are to enable a closer integration between the repositories that hold identity information and the authentication mechanisms.  A SecurityRealm is essentially the API used to interact with the repository of identities, from this we also obtain a RealmIdentity to represent an individual identity: -

As you can see from the above example both of these interfaces have a getCredentialSupport method, this method allows us to verify which credential types are supported in different situations and subsequently the mechanism filtering added in this release allows us to tailor the available authentication mechanisms to those actually compatible with the underlying realms.

In addition to the work on SASL based mechanisms selection the following Jira issues have also been resolved this release.

Release Notes - WildFly Elytron - Version 1.0.0.Alpha3


  • [ELY-247] - NullPointerException in SecurityProviderSaslServerFactory (Not all providers return services)
  • [ELY-227] - Add attribute mapping to Jdbc Security Realm
  • [ELY-175] - SASL mechanism availability should take into account credential support.
  • [ELY-189] - Support One-Time-Password SASL Mechanism
  • [ELY-197] - Add mechanism selection policies to the security domains.
  • [ELY-237] - Make it possible to configure the realm used on the client
  • [ELY-238] - Recognise realm callback on digest server, and make authorize callback come last
  • [ELY-239] - Make Anonumous auth set the anonymous principal name
  • [ELY-242] - Delegating SaslServerFactory supporting properties
  • [ELY-250] - Release WildFly Elytron 1.0.0.Alpha3
  • [ELY-33] - Identity Loading
  • [ELY-198] - Allow the association of Provider[] with a security domain and add support for mechanism loading.
  • [ELY-219] - Process subject roles in JaasAuthorizationIdentity
  • [ELY-223] - Add tests for the filesystem-backed realm
  • [ELY-244] - The properties map in the sasl factories should be Map<String, ?> not Map<String, Object>
  • [ELY-246] - Add github references to the pom

Next Release

The next release will be 1.0.0.Alpha4, the main feature to be included in that release will be the new APIs for HTTP authentication and an equivalent set of mechanism selection policies to allow an administrator control over HTTP authentication for their application server.

Wednesday, 8 July 2015

Upcomming WildFly Security Changes

For those of you that follow the WildFly development discussions you may be aware that we have a number of engineers currently engaged in a project called WildFly Elytron, for those not following essentially WildFly Elytron is a set of APIs and SPIs for application server security.  Although being developed to meet current requirements identified for the WildFly application server WildFly Elytron is a stand-alone library that could theoretically be used in other Java server environments.

The Need for Change

Historically application server security had been provided by making use of JAAS with the use of JAAS LoginModule implementations to verify a callers principal and credential combination, in the early stages of application servers this met the requirements fairly well - however in the modern age as increasing focus is given to security we find that this simple principal / credential pairing becomes harder and harder to use effectively.

As JBoss AS7 was developed our preference was to switch to stronger authentication mechanisms, for our native communication this meant a switch to SASL based authentication bound to the connection.  Due to incompatibility with JAAS this led us to a situation where we have two different security solutions within the application server, one focussed on SASL compatibility and one focussed on the legacy approach of principal / credential validation with integration between the two.

Having two different security solutions solving the same problem from completely different perspectives has let to a lot of confusion amongst users and from our perspective has left it difficult to provide new features - this has led to the initiation of the Elytron project to provide a single unified security solution across the whole application server.

Triangle of Compromises

Over the years working on security software within the application server I have come to the conclusion that whatever you do is always going to be bound by a triangle of compromises, enhance one node of the triangle and you risk reducing one or both of the other two.


Looking at a couple of examples.

Say you address how the passwords are stored, a common approach used here is a strong one way salted hash, if the storage is compromised at worst an attacker has an irreversible representation of the password that is next to useless to them without an expensive brute force search to attempt to identity the original password.  In the context of the triangle however the authentication mechanism you use for this password will now need to have dropped to plain text transmission, this may be countered buy using TLS on the connection but within the heap of the application server a plain text copy of the password will reside for some time.

Another option may be that some form of one time password is used instead, this improves the situation for both storage security and network security as the whole point of these passwords is that even if they are intercepted they can only be used once - the compromise however now is that usability is affected.

When an application server is deployed it is the role of the administrator to review these options in the context of their own installation, as an application server vendor it is not our role to prescribe the solution to be used instead our role is to provide the capabilities and options to allow the administrator to make these decisions and that is one of the main aims of the Elytron project.

What will Elytron Provide?

As mentioned above there are two predominant requirements of this project: -

  1. Provide a unified security solution across the application server.
  2. Give administrators the tools they need so that they can make decisions to configure their own environment effectively.
This is not an exhaustive list but here are some of the key areas we are looking to address: -
  1. Consistent use of terminology across the application server including consistent configuration across the server.
  2. Closer relationship between TLS configuration and authentication.
  3. A unified re-usable approach to configuration 
  4. Better client side control of the identity used to execute requests.
  5. Propagation of identities within different deployments in the same application server.
  6. Propagation of identities to a remote application server.

Underlying all of this is the emphasis on making sure stronger approaches to security are made available whilst simplifying the steps needed to achieve them.

What Next?

Following on from this will be a series of blog posts looking both at the APIs and SPIs of the Elytron project and how these will be represented in the application server in the form of the new subsystem currently being developed to expose this.

Related Links


Thursday, 27 November 2014

WildFly 9 - Kerberos Authentication with Remoting - Part 1

This blog post is in relation to a new feature added to WildFly 9 under WFCORE-106, however it is not currently included in a release so for now you will need to build WildFly yourself or use one of the nightly builds.

If you are not familiar with building WildFly have a look at HackingOnWildFly.

If you want to access a nightly build they are available from WildFly-latest-master.

Introduction

This blog post is the first part of a two part article on how to enable Keberos authentication for Remoting within WildFly 9, in Part 1 I discuss how to enable Keberos authentication for use with the CLI for managing the application server which makes use of JBoss Remoting to communicate with the server.

In Part 2 I will be looking at how to take an existing secured EJB deployment from within the quickstarts and enable Kerberos based authentication.

In a previous blog post WildFly 9 - Kerberos Authentication for Domain Management Over HTTP I have already described a lot of the steps required to enable Kerberos authentication for HTTP, for the steps that are also applicable for authentication with Remoting I will briefly mention them but will not duplicate the descriptions here.

Service Principals

One important aspect of Kerberos based authentication is that the service requiring authentication needs to be represented by it's own service principal, the naming of this principal is in the form '{service_name}/{hostname}' - where HTTP servers are secured using Kerberos the service_name is 'HTTP' - however for Remoting the service_name is expected to be 'remote'.

My Environment

My test environment that I am using for the basis of this blog post is the same as I described previously, the main difference here is that now I have a service principal called remote/web.dal.wildfly.org@DAL.WILDFLY.ORG which is in a keytab called remote.keytab.

As before any example commands will need to be updated to reflect your own environment.

Configuration Updates

As with the previous blog post system properties can be set as an easy way to define the realm name and the address of the KDC, after that similar updates also need to be made to the ManagementRealm: -


  1. Add a server identity for Kerberos.
  2. Add the keytab for the remote service principal.
  3. Add kerberos to the authentication resource of the security domain.
  4. Reload the server.
Steps 1, 3, and 4 are identical to those performed previously but in this example I would use the following command to add my remote keytab.


[standalone@web.dal.wildfly.org:9990 /] ./core-service=management/security-realm=ManagementRealm/server-identity=kerberos/keytab=remote\/web.dal.wildfly.org@DAL.WILDFLY.ORG:add(path=remote.keytab, relative-to=jboss.server.config.dir, debug=true)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}


Running the CLI

As before I have used the kinit command to obtain my own ticket granting ticket from the KDC: -


[darranl@localhost bin]$ kinit darranl@DAL.WILDFLY.ORG
Password for darranl@DAL.WILDFLY.ORG: 
[darranl@localhost bin]$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: darranl@DAL.WILDFLY.ORG

Valid starting     Expires            Service principal
27/11/14 17:44:50  28/11/14 17:44:47  krbtgt/DAL.WILDFLY.ORG@DAL.WILDFLY.ORG
renew until 04/12/14 17:44:47


The next step is to start the CLI, as I start the CLI I set three system properties: -
  1. -Djava.security.krb5.realm=DAL.WILDFLY.ORG
  2. -Djava.security.krb5.kdc=kdc.dal.wildfly.org
  3. -Djavax.security.auth.useSubjectCredsOnly=false
The first two could be optional depending on local environmental settings but the third one is important as this allows the GSSAPI implementation to make use of the identity managed at the OS level.

In the case of my testing I am running the CLI on the same machine that I am running the application server so it is also important to ensure I disable local authentication otherwise Kerberos authentication will not get a chance to be used so I add the argument --no-local-auth.

This means the resulting command is: -

[darranl@localhost bin]$ ./jboss-cli.sh -c --controller=web.dal.wildfly.org \
    --no-local-auth -Djava.security.krb5.realm=DAL.WILDFLY.ORG \
    -Djava.security.krb5.kdc=kdc.dal.wildfly.org \
    -Djavax.security.auth.useSubjectCredsOnly=false [standalone@web.dal.wildfly.org:9990 /]

I can execute the :whoami command to double check the user I am authenticated as.


[standalone@web.dal.wildfly.org:9990 /] :whoami
{
    "outcome" => "success",
    "result" => {"identity" => {
        "username" => "darranl",
        "realm" => "ManagementRealm"
    }}
}

Additional Config

The example above is making use of a lot of default behaviour within the CLI, if you would prefer to control the Kerberos identity further it is possible to override the JAAS security domain used internally by adding the following system property to point to your own JAAS configuration -Djava.security.auth.login.config={config}, this configuration should contain a security domain called 'com.sun.security.jgss.initiate' that contains a Krb5LoginModule definition for your own environment. One example of a reason you may want to do this is if your clients identity can also be obtained from a keytab.