Configuration of Kerberos with Elytron in WildFly

This tutorial describes how to configure Kerberos authentication in WildFly using Elytron.

Kerberos server

For needs of this tutorial we will suppose you have Kerberos server already running and generated keytab files for services:

where localhost is hostname under which will be your WildFly server accesible and JBOSS.ORG your Kerberos realm.

Testing server

If you don’t have your Kerberos server or you need testing server for your testing, you can use simple Kerberos server and keytab generator by Josef Cacek:

git clone https://github.com/hkalina/kerberos-using-apacheds/
cd kerberos-using-apacheds
mvn install
java -jar target/kerberos-using-apacheds.jar test.ldif

Generate keytab files for WildFly server:

java -classpath target/kerberos-using-apacheds.jar org.jboss.test.kerberos.CreateKeytab HTTP/localhost@JBOSS.ORG httppwd http.keytab
java -classpath target/kerberos-using-apacheds.jar org.jboss.test.kerberos.CreateKeytab remote/localhost@JBOSS.ORG remotepwd remote.keytab

Now you are prepared to start to configure the WildFly server.

Configuring Kerberos authentication

At first you need to specify path to the krb5.conf in java.security.krb5.conf property:

/system-property=java.security.krb5.conf:add(value=/home/jkalina/kerberos-using-apacheds/krb5.conf)

As following you need to create kerberos-security-factory referencing appropriate keytab files for both protocols - HTTP (using web browser) and remote (remote EJB, server CLI):

/subsystem=elytron/kerberos-security-factory=krbSFhttp:add( \
    principal=HTTP/localhost@JBOSS.ORG, \
    path=/home/jkalina/kerberos-using-apacheds/http.keytab, \
    mechanism-names=[KRB5, SPNEGO])

/subsystem=elytron/kerberos-security-factory=krbSFremote:add( \
    principal=remote/localhost@JBOSS.ORG, \
    path=/home/jkalina/kerberos-using-apacheds/remote.keytab, \
    mechanism-names=[KRB5])

Now you can add authentication mechanisms using Kerberos into appropriate authentication factories:

/subsystem=elytron/http-authentication-factory=management-http-authentication:list-add( \
    name=mechanism-configurations, index=0, \
    value={mechanism-name=SPNEGO, credential-security-factory=krbSFhttp})

/subsystem=elytron/http-authentication-factory=application-http-authentication:list-add( \
    name=mechanism-configurations, index=0, \
    value={mechanism-name=SPNEGO, credential-security-factory=krbSFhttp})

/subsystem=elytron/sasl-authentication-factory=management-sasl-authentication:list-add( \
    name=mechanism-configurations, index=1, \
    value={mechanism-name=GS2-KRB5, credential-security-factory=krbSFremote})

/subsystem=elytron/sasl-authentication-factory=application-sasl-authentication:list-add( \
    name=mechanism-configurations, index=1, \
    value={mechanism-name=GS2-KRB5, credential-security-factory=krbSFremote})

Security realm

As Kerberos provides authentication only, you need to provide some source of users for user lookup too. For needs of testing, default properties-realm can be used. Put following to the end of mgmt-users.properties file:

hnelson@JBOSS.ORG=

Blank password is sufficient to be able to authenticate using Kerberos.

LDAP realm

For production should be ldap-realm used instead:

/subsystem=elytron/dir-context=ldap:add( \
    url="ldap://localhost:10389", \
    principal="uid=ldap,ou=Users,dc=jboss,dc=org", \
    credential-reference={clear-text="randall"})

/subsystem=elytron/ldap-realm=ldapRealm:add( \
    dir-context=ldap, \
    identity-mapping={
        search-base-dn="ou=Users,dc=jboss,dc=org", \
        rdn-identifier="uid", \
        filter-name="krb5PrincipalName={0}" \
    })

And replace properties realms:

batch
/subsystem=elytron/security-domain=ManagementDomain:list-remove(name=realms, index=0)
/subsystem=elytron/security-domain=ManagementDomain:list-add(name=realms, index=0, value={realm=ldapRealm})
/subsystem=elytron/security-domain=ManagementDomain:write-attribute(name=default-realm, value=ldapRealm)
run-batch
batch
/subsystem=elytron/security-domain=ApplicationDomain:list-remove(name=realms, index=0)
/subsystem=elytron/security-domain=ApplicationDomain:list-add(name=realms, index=0, value={realm=ldapRealm})
/subsystem=elytron/security-domain=ApplicationDomain:write-attribute(name=default-realm, value=ldapRealm)
run-batch

But you can skip this for testing and use approach above instead.

Enabling Elytron for management authentication

To use authentication factories above we need to switch to them from legacy security realms:

/core-service=management/management-interface=http-interface:write-attribute(name=http-authentication-factory,value=management-http-authentication)
/core-service=management/management-interface=http-interface:write-attribute(name=http-upgrade.sasl-authentication-factory, value=management-sasl-authentication)
/core-service=management/management-interface=http-interface:undefine-attribute(name=security-realm)

(http-upgrade defines parameters for using SASL in HTTP connections)

Testing

At first you need to log-in using kinit:

export KRB5_CONFIG=/home/jkalina/kerberos-using-apacheds/krb5.conf
kinit hnelson@JBOSS.ORG
Password for hnelson@JBOSS.ORG: secret

Afterwords you should be able to authenticate to JBoss CLI using Kerberos:

bin/jboss-cli.sh -c --no-local-auth \
    -Djavax.security.auth.useSubjectCredsOnly=false \
    -Djava.security.krb5.conf=/home/jkalina/kerberos-using-apacheds/krb5.conf \
    :whoami

You can test authentication using CURL alternatively:

curl  --negotiate -u hnelson@JBOSS.ORG --trace-ascii - http://localhost:9990/management

Or using custom client using Elytron client library:

        System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
        System.setProperty("java.security.krb5.conf", "../kerberos-using-apacheds/krb5.conf");

        ModelControllerClient client = ModelControllerClient.Factory
                .create(new ModelControllerClientConfiguration.Builder()
                        .setHostName("localhost").setPort(9990)
                        .setConnectionTimeout(36000).build());

        ModelNode operation = new ModelNode();
        operation.get("operation").set("whoami");
        operation.get("verbose").set("true");
        ModelNode result = client.execute(operation);

Configuring Firefox

In about:config set network.negotiate-auth.trusted-uris to contain localhost - individual hostnames needs to be delimited by comma AND space:

.redhat.com, .fedoraproject.org, localhost

Run Firefox with KRB5_CONFIG property set - you should be logged automatically:

export KRB5_CONFIG=/home/jkalina/Desktop/tutorial/kerberos-using-apacheds/krb5.conf
firefox http://localhost:9990/

Getting debug output

We can specify property to enable Kerberos debug in Oracle JDK:

/system-property=sun.security.krb5.debug:add(value=true)

Trace messages from Elytron and from remoting will be also useful:

/subsystem=logging/logger=org.wildfly.security:add(level=TRACE)
/subsystem=logging/logger=org.jboss.remoting.remote.server:add(level=TRACE)

Often error messages

No server entry found for kerberos principal name HTTP/127.0.0.1@JBOSS.ORG

You are accessing the WildFly server from browser by different hostname (127.0.0.1) then for which kerberos account exists (localhost).

KrbException: Fail to create credential. (63) - No service creds

Probably wrong mapping of hostname to realm in [domain_realm] section of krb5.conf - or wrong path to krb5.conf on client.

GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)

Probably property javax.security.auth.useSubjectCredsOnly not set to false while trying to use local-kerberos credential.

GSSException: Invalid name provided (Mechanism level: KrbException: Cannot locate default realm)

Wrong path to the krb5.conf file.