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.
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)
mvn wildfly:deploy
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.
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.