[[Security_Realms_Plugins]]
= Plug Ins

Within WildFly {wildflyVersion} for communication with the management interfaces and
for other services exposed using Remoting where username / password
authentication is used the use of Digest authentication is preferred
over the use of HTTP Basic or SASL Plain so that we can avoid the
sending of password in the clear over the network. For validation of the
digests to work on the server we either need to be able to retrieve a
users plain text password or we need to be able to obtain a ready
prepared hash of their password along with the username and realm.

Previously to allow the addition of custom user stores we have added an
option to the realms to call out to a JAAS domain to validate a users
username and password, the problem with this approach is that to call
JAAS we need the remote user to send in their plain text username and
password so that a JAAS LoginModule can perform the validation, this
forces us down to use either the HTTP Basic authentication mechanism or
the SASL Plain mechanism depending on the transport used which is
undesirable as we can not longer use Digest.

To overcome this we now support plugging in custom user stores to
support loading a users password, hash and roles from a custom store to
allow different stores to be implemented without forcing the
authentication back to plain text variant, this article describes the
requirements for a plug in and shows a simple example plug-in for use
with WildFly {wildflyVersion}.

When implementing a plug in there are two steps to the authentication
process, the first step is to load the users identity and credential
from the relevant store - this is then used to verify the user
attempting to connect is valid. After the remote user is validated we
then load the users roles in a second step. For this reason the support
for plug-ins is split into the two stages, when providing a plug-in
either of these two steps can be implemented but there is no requirement
to implement the other side.

When implementing a plug-in the following interfaces are the bare
minimum that need to be implemented so depending on if a plug-in to load
a users identity or a plug-in to load a users roles is being implemented
you will be implementing one of these interfaces.

*_Note_* _- All classes and interfaces of the SPI to be implemented are
in the 'org.jboss.as.domain.management.plugin' package which is a part
of the 'org.jboss.as.domain-management' module but for simplicity for
the rest of this section only the short names will be shown._

[[authenticationplugin]]
== AuthenticationPlugIn

To implement an `AuthenticationPlugIn` the following interface needs to
be implemened: -

[source, java]
----
public interface AuthenticationPlugIn<T extends Credential> {
    Identity<T> loadIdentity(final String userName, final String realm) throws IOException;
}
----

During the authentication process this method will be called with the
user name supplied by the remote user and the name of the realm they are
authenticating against, this method call represents that an
authentication attempt is occurring but it is the Identity instance that
is returned that will be used for the actual authentication to verify
the remote user.

The Identity interface is also an interface you will implement: -

[source,xml]
----
public interface Identity<T extends Credential> {
    String getUserName();
    T getCredential();
}
----

Additional information can be contained within the Identity
implementation although it will not currently be used, the key piece of
information here is the Credential that will be returned - this needs to
be one of the following: -

=== PasswordCredential

[source, java]
----
public final class PasswordCredential implements Credential {
    public PasswordCredential(final char[] password);
    public char[] getPassword();
    void clear();
}
----

The `PasswordCredential` is already implemented so use this class if you
have the plain text password of the remote user, by using this the
secured interfaces will be able to continue using the Digest mechanism
for authentication.

[[digestcredential]]
=== DigestCredential

[source, java]
----
public final class DigestCredential implements Credential {
    public DigestCredential(final String hash);
    public String getHash();
}
----

This class is also already implemented and should be returned if instead
of the plain text password you already have a pre-prepared hash of the
username, realm and password.


=== ValidatePasswordCredential

[source, java]
----
public interface ValidatePasswordCredential extends Credential {
    boolean validatePassword(final char[] password);
}
----

This is a special Credential type to use when it is not possible to
obtain either a plain text representation of the password or a
pre-prepared hash - this is an interface as you will need to provide an
implementation to verify a supplied password. The down side of using
this type of Credential is that the authentication mechanism used at the
transport level will need to drop down from Digest to either HTTP Basic
or SASL Plain which will now mean that the remote client is sending
their credential across the network in the clear.

If you use this type of credential be sure to force the mechanism choice
to Plain as described in the configuration section below.

[[authorizationplugin]]
== AuthorizationPlugIn

If you are implementing a custom mechanism to load a users roles you
need to implement the `AuthorizationPlugIn`

[source, java]
----
public interface AuthorizationPlugIn {
    String[] loadRoles(final String userName, final String realm) throws IOException;
}
----

As with the `AuthenticationPlugIn` this has a single method that takes a
users userName and realm - the return type is an array of Strings with
each entry representing a role the user is a member of.

[[pluginconfigurationsupport]]
== PlugInConfigurationSupport

In addition to the specific interfaces above there is an additional
interface that a plug-in can implement to receive configuration
information before the plug-in is used and also to receive a Map
instance that can be used to share state between the plug-in instance
used for the authentication step of the call and the plug-in instance
used for the authorization step.

[source, java]
----
public interface PlugInConfigurationSupport {
    void init(final Map<String, String> configuration, final Map<String, Object> sharedState) throws IOException;
}
----

[[installing-and-configuring-a-plug-in]]
== Installing and Configuring a Plug-In

The next step of this article describes the steps to implement a plug-in
provider and how to make it available within WildFly {wildflyVersion} and how to
configure it. Example configuration and an example implementation are
shown to illustrate this.

The following is an example security realm definition which will be used
to illustrate this: -

[source, xml]
----
<security-realm name="PlugInRealm">
   <plug-ins>
      <plug-in module="org.jboss.as.sample.plugin"/>
   </plug-ins>
   <authentication>
      <plug-in name="Sample">
         <properties>
            <property name="darranl.password" value="dpd"/>
            <property name="darranl.roles" value="Admin,Banker,User"/>
         </properties>
      </plug-in>
   </authentication>
   <authorization>
      <plug-in name="Delegate" />
   </authorization>
</security-realm>
----

Before looking closely at the packaging and configuration there is one
more interface to implement and that is the `PlugInProvider` interface,
that interface is responsible for making PlugIn instances available at
runtime to handle the requests.

[[pluginprovider]]
=== PlugInProvider

[source, java]
----
public interface PlugInProvider {
    AuthenticationPlugIn<Credential> loadAuthenticationPlugIn(final String name);
    AuthorizationPlugIn loadAuthorizationPlugIn(final String name);
}
----

These methods are called with the name that is supplied in the plug-in
elements that are contained within the authentication and authorization
elements of the configuration, based on the sample configuration above
the loadAuthenticationPlugIn method will be called with a parameter of
'Sample' and the loadAuthorizationPlugIn method will be called with a
parameter of 'Delegate'.

Multiple plug-in providers may be available to the application server so
if a `PlugInProvider` implementation does not recognise a name then it
should just return null and the server will continue searching the other
providers. If a `PlugInProvider` does recognise a name but fails to
instantiate the PlugIn then a `RuntimeException` can be thrown to
indicate the failure.

As a server could have many providers registered it is recommended that
a naming convention including some form of hierarchy is used e.g. use
package style names to avoid conflicts.

For the example the implementation is as follows: -

[source, java]
----
public class SamplePluginProvider implements PlugInProvider {
 
    public AuthenticationPlugIn<Credential> loadAuthenticationPlugIn(String name) {
        if ("Sample".equals(name)) {
            return new SampleAuthenticationPlugIn();
        }
        return null;
    }
 
    public AuthorizationPlugIn loadAuthorizationPlugIn(String name) {
        if ("Sample".equals(name)) {
            return new SampleAuthenticationPlugIn();
        } else if ("Delegate".equals(name)) {
            return new DelegateAuthorizationPlugIn();
        }
        return null;
    }
}
----

The load methods are called for each authentication attempt but it will
be an implementation detail of the provider if it decides to return a
new instance of the provider each time - in this scenario as we also use
configuration and shared state then new instances of the implementations
make sense.

To load the provider use a ServiceLoader so within the META-INF/services
folder of the jar this project adds a file called '
`org.jboss.as.domain.management.plugin.PlugInProvider`' - this contains
a single entry which is the fully qualified class name of the
PlugInProvider implementation class.

....
org.jboss.as.sample.SamplePluginProvider
....

[[package-as-a-module]]
=== Package as a Module

To make the `PlugInProvider` available to the application it is bundled
as a module and added to the modules already shipped with WildFly {wildflyVersion}.

To add as a module we first need a `module.xml`: -

[source, xml]
----
<?xml version="1.0" encoding="UTF-8"?>
 
<module xmlns="urn:jboss:module:1.1" name="org.jboss.as.sample.plugin">
    <properties>
    </properties>
 
    <resources>
        <resource-root path="SamplePlugIn.jar"/>
    </resources>
 
    <dependencies>
        <module name="org.jboss.as.domain-management" />
    </dependencies>
</module>
----

The interfaces being implemented are in the '
`org.jboss.as.domain-management`' module so a dependency on that module
is defined, this `module.xml` is then placed in the '\{
`jboss.home}/modules/org/jboss/as/sample/plugin/main`'.

The compiled classed and `META-INF/services` as described above are
assembled into a jar called `SamplePlugIn.jar` and also placed into this
folder.

Looking back at the sample configuration at the top of the realm
definition the following element was added: -

[source, xml]
----
   <plug-ins>
      <plug-in module="org.jboss.as.sample.plugin"/>
   </plug-ins>
----

This element is used to list the modules that should be searched for
plug-ins. As plug-ins are loaded during the server start up this search
is a lazy search so don't expect a definition to a non existant module
or to a module that does not contain a plug-in to report an error.

[[the-authenticationplugin]]
=== The AuthenticationPlugIn

The example `AuthenticationPlugIn` is implemented as: -

[source, java]
----
public class SampleAuthenticationPlugIn extends AbstractPlugIn {
 
    private static final String PASSWORD_SUFFIX = ".password";
    private static final String ROLES_SUFFIX = ".roles";
    private Map<String, String> configuration;
 
    public void init(Map<String, String> configuration, Map<String, Object> sharedState) throws IOException {
        this.configuration = configuration;
        // This will allow an AuthorizationPlugIn to delegate back to this instance.
        sharedState.put(AuthorizationPlugIn.class.getName(), this);
    }
 
    public Identity loadIdentity(String userName, String realm) throws IOException {
        String passwordKey = userName + PASSWORD_SUFFIX;
        if (configuration.containsKey(passwordKey)) {
            return new SampleIdentity(userName, configuration.get(passwordKey));
        }
        throw new IOException("Identity not found.");
    }
 
    public String[] loadRoles(String userName, String realm) throws IOException {
        String rolesKey = userName + ROLES_SUFFIX;
        if (configuration.containsKey(rolesKey)) {
            String roles = configuration.get(rolesKey);
            return roles.split(",");
        } else {
            return new String[0];
        }
    }
 
    private static class SampleIdentity implements Identity {
        private final String userName;
        private final Credential credential;
 
        private SampleIdentity(final String userName, final String password) {
            this.userName = userName;
            this.credential = new PasswordCredential(password.toCharArray());
        }
 
        public String getUserName() {
            return userName;
        }
 
        public Credential getCredential() {
            return credential;
        }
    }
}
----

As you can see from this implementation there is also an additional
class being extended `AbstractPlugIn` - that is simply an abstract class
that implements the `AuthenticationPlugIn`, `AuthorizationPlugIn`, and
`PlugInConfigurationSupport` interfaces already. The properties that
were defined in the configuration are passed in as a Map and importantly
for this sample the plug-in adds itself to the shared state map.

[[the-authorizationplugin]]
=== The AuthorizationPlugIn

The example implementation of the authentication plug in is as follows:
-

[source, java]
----
public class DelegateAuthorizationPlugIn extends AbstractPlugIn {
 
    private AuthorizationPlugIn authorizationPlugIn;
 
    public void init(Map<String, String> configuration, Map<String, Object> sharedState) throws IOException {
        authorizationPlugIn = (AuthorizationPlugIn) sharedState.get(AuthorizationPlugIn.class.getName());
    }
 
    public String[] loadRoles(String userName, String realm) throws IOException {
        return authorizationPlugIn.loadRoles(userName, realm);
    }
 
}
----

This plug-in illustrates how two plug-ins can work together, by the
`AuthenticationPlugIn` placing itself in the shared state map it is
possible for the authorization plug-in to make use of it for the
loadRoles implementation.

Another option to consider to achieve similar behaviour could be to
provide an Identity implementation that also contains the roles and
place this in the shared state map - the `AuthorizationPlugIn` can
retrieve this and return the roles.

[[forcing-plain-text-authentication]]
=== Forcing Plain Text Authentication

As mentioned earlier in this article if the `ValidatePasswordCredential`
is going to be used then the authentication used at the transport level
needs to be forced from Digest authentication to plain text
authentication, this can be achieved by adding a mechanism attribute to
the plug-in definition within the authentication element i.e.

[source, xml]
----
  <authentication>
    <plug-in name="Sample" mechanism="PLAIN">
----
