Showing posts with label Authentication. Show all posts
Showing posts with label Authentication. Show all posts

Saturday, 19 January 2019

Using WildFly Elytron with the Netty HttpServerCodec

The WildFly Elytron project was developed to meet the needs if the WildFly application server, however the APIs and SPIs within this project also allow us to use the project in other environments.

A couple of previous blogs from Farah Juma and myself have highlighted a couple of these environments already: -
 Using WildFly Elytron with Undertow Standalone
 Securing an embedded Jetty server using Elytron

Also I have previously published a blog describing how to implement a custom HTTP authentication mechanism using the WildFly Elytron SPIs.
WildFly Elytron - Implementing a Custom HTTP Authentication Mechanism

Being able to take a single security project and use it in multiple environments has numerous benefits, some of which are: -

  • Only needing to learn one framework instead of one framework per server type.
  • Portability of custom implementation such as authentication mechanisms or security realms which can be used in all environments.
  • The ability to combine multiple servers into a single process whilst using common security SPIs.
This blog post is to introduce the integration of WildFly Elytron with the Netty HttpServerCodec for HTTP authentication.

It is worth noting this integration is specifically making use of Netty's HttpServerCodec for integration, if an alternative HTTP server was developed on Netty then an alternative integration with WildFly Elytron would also be required.

The project containing the Netty integration code can be found on GitHub at elytron-web-netty

As an integration project this project only exposes once class as public API 'org.wildfly.elytron.web.netty.server.ElytronHandlers'  - the purpose this class is to take configured WildFly Elytron components and use them to insert a set of handlers into a Netty ChannelPipeline, once inserted they will perform authentication kaing use of Wildfly Elytron.

The example project can be found on GitHub at netty-standalone.

After checking out the example project it can be built using maven: -

    mvn clean instal

And then once build can also be executed using maven: -

    mvn exec:exec

Once running you can navigate to http://localhost:7776/ and access the application using the username 'alice' with the password 'alice123+', if successful you should see the following response: -

Current identity 'alice'

Now that the example project is running we can look into the details as to how WildFly Elytron was activated.

Activation

Within Netty a ChannelInitializer is required to add the handlers to the ChannelPipeline, within the example project this is within the class 'org.wildfly.security.examples.TestInitialiser' and is implemented as: -


protected void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();
    pipeline.addLast(new HttpServerCodec());
    pipeline.addLast(new HttpServerExpectContinueHandler());
    securityHandler.apply(pipeline);
    pipeline.addLast(new TestContentHandler());
}

The 'securityHandler' within the example block of code is actually an instance of the ElytronHandlers class, it is worth noting that it can be cached and re-used potentially performing many initialisations concurrently.

As the example projects starts up the ElytronHandlers is initialised as follows: -

ElytronHandlers securityHandlers = ElytronHandlers.newInstance()
        .setSecurityDomain(securityDomain)
        .setFactory(createHttpAuthenticationFactory())
        .setMechanismConfigurationSelector(MechanismConfigurationSelector.constantSelector(
                MechanismConfiguration.builder()
                        .addMechanismRealm(MechanismRealmConfiguration.builder().setRealmName("Elytron Realm").build())
                        .build()));

This initialisation takes a pre-configured SecurityDomain and HttpAuthenticationFactory and adds a MechanismConfigurationSelector, these have been covered on prior blogs so I am not going to cover the details of these again here although they can all be seen within the org.wildfly.security.examples.HelloWorld class to see how these are initialised.

One further method not used in this example is: -

public ElytronHandlers setAuthenticationRequired(final Predicate<HttpRequest> authenticationRequired)

This can be used to add a Predicate to decide on a request by request basis if authentication is required after inspecting the HttpRequest.

Outcome

After the initialisation described above the channel end up with the following handlers defined on it's pipeline: -

For a request after being handled by the HttpServerCodec handler it will pass so the ElytronInboundHandler, this is where the authentication by WildFly Elytron takes place and a SecurityIdentity is established.

If authentication fails the request can be turned around at this stage and sent back to the client.

Our next inbound handler is the ElytronRunAsHandler, this handler is responsible for taking any established SecurityIdentity and ensuring it is associated with the current thread.

In this set up we have one outbound handler which is the ElytronOutboundHandler, this handler is called for all messages being sent back to the client is responsible for setting any security related HTTP headers that need to be set on the respone message.


Contribution

The Netty integration project is currently tagged as a Beta as a number of areas still need to be developed, if anyone is interested in contributing their contributions will be welcome.

Completing the implementation of the ElytronHttpExchange class: -
  • Support for all Scope types.
  • Parsing of request parameters.
  • Cookie support.
Request InputStream handling.

Improved response OutputStream handling.

Adding support for authorization, either role based checks or Java permission checks.

Further enhancement of the test cases including adding more mechanisms to be tested.

Outside of the Netty integration there are other projects out there still possible options for integration, some of these are: -
  • Tomcat
  • Pure servlet integration.
  • EE Security integration.

For all integrations some form of common testsuite to verify the full permutation of authentication mechanisms available within WildFly Elytron.


Thursday, 18 October 2018

Using WildFly Elytron JASPI with Standalone Undertow

As part of the development efforts for WildFly 15 an implementation of the servlet profile from the JASPI (JSR-196) specification has been added to WildFly Elytron and is in the final stages of being integrated within the application server.

As with many of the features included in WildFly Elytron it is possible to make use of this outside of the application server, this blog post combined with an example project illustrates how the WildFly Elytron JASPI implementation can be used with a standalone Undertow server.

The example project can be found at the following location: -

https://github.com/wildfly-security-incubator/elytron-examples/tree/master/undertow-standalone-jaspi

The project can be built using Apache Maven using the following command: -

mvn clean install

And executed with: -

mvn exec:exec

The remainder of this blog post will describe the remainder of the project and then demonstrate how to make an invocation to the servlet using 'curl'.

Server Auth Module

This project contains a very simple ServerAuthModule 'org.wildfly.security.examples.jaspi.SimpleServerAuthModule', this module expects to receive a username using the 'X-USERNAME' header and expects to receive a password using the 'X-PASSWORD' header.

This module does not perform it's own username and password validation, instead it makes use of a 'PasswordValidationCallback' which is handled by the 'CallbackHandler' passed to the module on initialisation, this means the verification is in turn handled by WildFly Elytron.

Finally this module makes use of a 'GroupPrincipalCallback' which is used to override the groups / role assigned to the resulting identity and in this case assign the identity the 'Users' role.

Although this example demonstrates delegating the verification of the username and password to WildFly Elytron it is also possible to implement a ServerAuthModule which performs it's own validation and instead just describe the resulting identity using the callbacks.

Servlet

To make this demonstration possible the example project contains a servlet 'org.wildfly.security.examples.servlet.SecuredServlet', the purpose of this servlet is to return a HTML page containing the name of the current authenticated identity.

Configuration and Execution

Undertow and WildFly Elytron are programatically configured and started within 'org.wildfly.security.examples.HelloWorld', this class contains some initialisation that has been seen previously and some new configuration to enable JASPI and integrate with Undertow.

createSecurityDomain()

The first step is to create the SecurityDomain backed by a SecurityRealm: -

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

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

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

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

    builder.addRealm("TestRealm", simpleRealm).build();
    builder.setRoleMapper(RoleMapper.constant(Roles.of("Test")));

    builder.setPermissionMapper((principal, roles) -> PermissionVerifier.from(new LoginPermission()));

    return builder.build();
}

Here we have a single identity 'elytron' with the password 'Coleoptera', however any of the other security realms could have been used here allowing for alternative integration options.

configureJaspi()

The next step is the JASPI configuration, at this stage this is still independent of the Undertow initialisation: -

private static String configureJaspi() {
    AuthConfigFactory authConfigFactory = new ElytronAuthConfigFactory();
    AuthConfigFactory.setFactory(authConfigFactory);

    return JaspiConfigurationBuilder.builder(null, null)
            .setDescription("Default Catch All Configuration")
            .addAuthModuleFactory(SimpleServerAuthModule::new)
            .register(authConfigFactory);
}


The first step is to initialise the Elytron implementation of 'AuthConfigFactory' and to register it as the global default implementation.

The JASPI APIs provide a lot of flexibility to allow for programatic registration of configurations, however the APIs do not provide a way to instantiate the implementations of these implementations when in the majority of the cases where dynamic registration is used it is just to register a custom ServerAuthModule.  With the changes added to Wildfly Elytron we have added a new API of our own in a class called 'org.wildfly.security.auth.jaspi.JaspiConfigurationBuilder' - this can be used to register a configuration with the 'AuthConfigFactory'.

Configuring and Starting Undertow

Now that the prior two steps have been completed it is possible to use the Undertow and WildFly Elytron APIs to complete the configuration of a deployment and start the Undertow server with JASPI authentication enabled.

The first step is using the Undertow APIs to define a deployment: -

DeploymentInfo deploymentInfo = Servlets.deployment()
        .setClassLoader(SecuredServlet.class.getClassLoader())
        .setContextPath(PATH)
        .setDeploymentName("helloworld.war")
        .addSecurityConstraint(new SecurityConstraint()
                .addWebResourceCollection(new WebResourceCollection()
                        .addUrlPattern("/secured/*"))
                .addRoleAllowed("Users")
                .setEmptyRoleSemantic(SecurityInfo.EmptyRoleSemantic.DENY))
        .addServlets(Servlets.servlet(SecuredServlet.class)
                .addMapping(SERVLET));

Next we can use the WildFly Elytron APIs to apply Wildfly Elytron backed security to this deployment: -

AuthenticationManager authManager = AuthenticationManager.builder()
        .setSecurityDomain(securityDomain)
        .build();
authManager.configure(deploymentInfo);

It is worth noting this is where the WildFly Elytron SecurityDomain is associated with the deployment, the JASPI configuration performed earlier was independent of the domain.

The final stages are now to complete the deployment before creating and starting the Undertow server: -

DeploymentManager deployManager = Servlets.defaultContainer().addDeployment(deploymentInfo);
deployManager.deploy();

PathHandler path = Handlers.path(Handlers.redirect(PATH))
        .addPrefixPath(PATH, deployManager.start());

Undertow server = Undertow.builder()
        .addHttpListener(PORT, HOST)
        .setHandler(path)
        .build();
server.start();

Invoking the Servlet

Once the server is running it is now time to invoke the servlet using 'curl', other clients could also be used however they would need to support custom headers to work with this mechanism.

Firstly if we call the servlet without any headers we should see the request rejected with a message asking for the headers: -

]$ curl -v http://localhost:28080/helloworld/secured
...
< HTTP/1.1 401 Unauthorized
< Expires: 0
< Connection: keep-alive
< Cache-Control: no-cache, no-store, must-revalidate
< Pragma: no-cache
< X-MESSAGE: Please resubmit the request with a username specified using the X-USERNAME and a password specified using the X-PASSWORD header.
< Content-Type: text/html;charset=UTF-8
< Content-Length: 71

We can now repeat the command and provide a username and password using the appropriate headers: -

]$ curl -v http://localhost:28080/helloworld/secured -H "X-Username:elytron" -H "X-Password:Coleoptera"
...
< HTTP/1.1 200 OK
< Expires: 0
< Connection: keep-alive
< Cache-Control: no-cache, no-store, must-revalidate
< Pragma: no-cache
< Content-Length: 154
<html>
  <head><title>Secured Servlet</title></head>
  <body>
    <h1>Secured Servlet</h1>
    <p>
 Current Principal 'elytron'    </p>
  </body>
</html>

In this case we now see the expected HTML specifying the name of the current identity.

















Thursday, 8 February 2018

WildFly Elytron - Implementing a Custom HTTP Authentication Mechanism

When WildFly Elytron is used to secure a web application is is possible to implement custom HTTP authentication mechanisms that can be registered using the Elytron subsystem, it is then possible to override the configuration within the deployment to make use of this mechanism without requiring modifications to the deployment.

This blog post explores a custom authentication mechanism that can make use of custom HTTP headers to receive a clear text username and password and use these for authentication.  Generally passing clear text passwords is something that should be voided, they are only used here to avoid over complicating the example.

This blog will be making use of two projects within the elytron-examples respository that can be found at: -

https://github.com/wildfly-security-incubator/elytron-examples


  • simple-webapp - A very simple secured web application that can be deployed to test the mechanism.
  • simple-http-mechanism - A small project containing the minimal pieces to develop a custom mechanism.

Mechanism Implementation

The major piece of any custom HTTP mechanism is going to be the actual implementation of the mechanism, all custom mechanisms are required to implement the interface HttpServerAuthenticationMechanism.html.

In general for a mechanism the evaluateRequest method is called to handle the request passing in a HttpServerRequest object, the mechanism processes the requests and uses one of the following callback methods on the request to indicate the outcome: -
For each of these callback methods it is possible to pass in an instance of a HttpServerMechanismResponder which can be used to send challenge information to the calling client, which responders are called will depend very much on the outcome of the other mechanisms in use concurrently.


The custom mechanism implemented for this blog can be found at CustomHeaderHttpAuthenticationMechanism.java

Where this custom mechanism sends a challenge the challenge is always the same so we can use a static instance of the responder to avoid creating a new one each time we need to challenge: -

    private static final HttpServerMechanismsResponder RESPONDER = new      
            HttpServerMechanismsResponder() {       
        public void sendResponse(HttpServerResponse response) throws 
                HttpAuthenticationException {
            response.addResponseHeader(MESSAGE_HEADER, "Please resubit the request with a username specified using the X-USERNAME and a password specified using the X-PASSWORD header.");
            response.setStatusCode(401);
        }
    };


The evaluateRequest method then follows a path that will be common to many mechanisms.


final String username = request.getFirstRequestHeaderValue(USERNAME_HEADER);
final String password = request.getFirstRequestHeaderValue(PASSWORD_HEADER);

if (username == null || username.length() == 0 || password == null || 
      password.length() == 0) {    
    request.noAuthenticationInProgress(RESPONDER);
    return;
}


In this first block the mechanism tests if it has authentication headers appropriate for this mechanism, if not 'noAuthenticationInProgress' is called to notify the framework this mechanism is not doing anything yet and passes the responder in case a response is needed to challenge the client.


NameCallback nameCallback = new NameCallback("Remote Authentication Name", 
                                              username);
nameCallback.setName(username);
final PasswordGuessEvidence evidence = new 
                PasswordGuessEvidence(password.toCharArray());
EvidenceVerifyCallback evidenceVerifyCallback = new 
                EvidenceVerifyCallback(evidence);
try {
    callbackHandler.handle(new Callback[] { nameCallback, 
                                            evidenceVerifyCallback });
} catch (IOException | UnsupportedCallbackException e) {
    throw new HttpAuthenticationException(e);
}

if (evidenceVerifyCallback.isVerified() == false) {
    request.authenticationFailed("Username / Password Validation Failed", 
                                 RESPONDER);
}


In this second block the mechanism takes the headers received from the client and uses them to perform authentication by passing Callbacks to the provided CallbackHandler.

After a successful authentication it is possible to associate any credentials received from the client with the resulting identity, this step is optional but can be useful.


try {
    callbackHandler.handle(new Callback[] {new IdentityCredentialCallback(
        new PasswordCredential(ClearPassword.createRaw(
                ClearPassword.ALGORITHM_CLEAR, 
                password.toCharArray())), true)});
} catch (IOException | UnsupportedCallbackException e) {
    throw new HttpAuthenticationException(e);
}

At this point the identity has been authenticated and the credential associated but no check has been performed to ensure the identity is allowed to login so the next step is an authorization.

try {
    callbackHandler.handle(new Callback[] {authorizeCallback});

    if (authorizeCallback.isAuthorized()) {
        callbackHandler.handle(new Callback[] { 
            AuthenticationCompleteCallback.SUCCEEDED });
        request.authenticationComplete();
    } else {
        callbackHandler.handle(new Callback[] { 
            AuthenticationCompleteCallback.FAILED });
        request.authenticationFailed("Authorization check failed.", RESPONDER);
    }
    return;
} catch (IOException | UnsupportedCallbackException e) {
    throw new HttpAuthenticationException(e);
}

In this last block finally an AuthenticationCompleteCallback is needed to indicate the overall outcome of the authentication as decided by the mechanism, the reason the mechanism makes this decision is because a mechanism could take into account additional information in addition beyond the outcomes from the callbacks - an an example the HTTP Digest information will asses the validity of the nonce late in the authentication process.

Mechanism Factory Implementation

After the mechanism implementation the next class required is a factory to return instances of the mechanism, factories implement the HttpAuthenticationFactory interface, in this example the factory only returns a single mechanism however a single factory could support multiple mechanisms.

Within the test project this is implemented in CustomMechanismFactory.java

The most important step within the factory is to double check the name of the mechanism requested, it is important for the factory to return null if it can not create the required mechanism.  The mechanism factory can also take into account properties in the Map passed in to decide if it can create the requested mechanism.

Advertising Availability

There are two different approaches that can be used to advertise the availability of a mechanism factory, the first is to implement a java.security.Provider with the HttpAuthenticationFactory registered as an available service once for each mechanism it supports.

This example however is very simple so instead of implementing a provider we use a java.util.ServiceLoader to discover the factory instead, to achieve this we add the descriptor org.wildfly.security.http.HttpServerAuthenticationMechanismFactory under META-INF/services the only contents required in this file are the fully qualified class name of the factory.

Mechanism Installation

At this stage the mechanism project can be built and installed in the application server as a module ready to be used, the project is a simple maven project so can be built with: -

    mvn clean install

For the next stage the application server does not need to be running, the following command can be executed within the jboss-cli to add the module to the application server: -

module add --name=org.wildfly.security.examples.custom-http \
 --resources=/path/elytron-examples/simple-http-mechanism/target/simple-http-mechanism-1.0.0.Alpha1-SNAPSHOT.jar \
 --dependencies=org.wildfly.security.elytron,javax.api

The required dependencies are very simple, the installed module just requires a dependency on the public Elytron API and the javax API for access to some of the common callbacks and related exceptions.

Testing - BASIC authentication

When testing changes within the application server it is often better to start with small changes and verify those are working before moving onto the next set of changes, often users that make a large number of changes at once find it difficult to track down at which stage an error was introduced.

The next step within this blog is to deploy the simple-webapp also in the elytron-examples repository and verify it works with HTTP BASIC authentication, once verified we will switch the configuration to use the new authentication mechanism.

Before starting the application server a new test account can be added using the add-user utility.

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

Now the application server can be started and the CLI connected to the application server.

When the sample application is deployed it will by default use the 'other' security domain so a mapping needs to be added to map this to an Elytron HTTP authentication factory: -

./subsystem=undertow/application-security-domain=other:add(
http-authentication-factory=application-http-authentication)

The simple-webapp can now be deployed directly using maven.

mvn wildfly:deploy

This application could be tested using a web browser as it is using a standard mechanism the browser would understand, however once we switch to using a custom mechanism the browser will not understand so it is better to test the call using a client that will allow us to manipulate the headers ourselves.

curl -v http://localhost:8080/simple-webapp/secured -u testuser:password

If everything is working output similar to the following should be seen (Some headers have been removed to make the output easier to read)

< HTTP/1.1 200 OK
...<
<html>
 <head><title>Secured Servlet</title></head>
 <body>
   <h1>Secured Servlet</h1>
   <p>
Current Principal 'testuser'    </p>
 </body>
</html>

At this stage authentication is being successfully applied to the web application backed by WildFly Elytron using the Elytron implementation of the HTTP BASIC authentication mechanism, the next step is to switch to using the custom mechanism.

Testing - Custom Mechanism

The first resource to add in the CLI is to discover the factory implementation.

./subsystem=elytron/service-loader-http-server-mechanism-factory=
custom-factory:add(module=org.wildfly.security.examples.custom-http)

After this is added a CLI command can be executed to immediately check which mechanisms the factory can create.

./subsystem=elytron/service-loader-http-server-mechanism-factory=
custom-factory:read-resource(include-runtime=true)
{
   "outcome" => "success",
   "result" => {
       "available-mechanisms" => ["CUSTOM_MECHANISM"],
       "module" => "org.wildfly.security.examples.custom-http"
   }
}
The next resource to add is a http-authentication-factory to tie the mechanism factory to a security-domain that will be used for the actual authentication.

./subsystem=elytron/http-authentication-factory=custom-mechanism:
add(http-server-mechanism-factory=custom-factory,
security-domain=ApplicationDomain,
mechanism-configurations=[{mechanism-name=CUSTOM_MECHANISM}])

The application-security-domain resource we added previously can now be updated to use this new http-authentication-factory.

./subsystem=undertow/application-security-domain=other:
write-attribute(name=http-authentication-factory, value=custom-mechanism)
./subsystem=undertow/application-security-domain=other:
write-attribute(name=override-deployment-config, value=true)

The second of those commands is important, the application is defined to use the BASIC authentication mechanism only, by overriding the deployment config the mechanisms from the http-authentication-factory will be used instead.

The server can now be reloaded.

:reload

The same curl command can be executed again but this time it is expected it will fail with output similar to the following.

curl -v http://localhost:8080/simple-webapp/secured -u testuser:password
< HTTP/1.1 401 Unauthorized
...
< X-MESSAGE: Please resubit the request with a username specified using the X-USERNAME and a password specified using the X-PASSWORD header.
...

Here the authentication mechanism has rejected the call and subsequently added a header describing how to authentication.

The curl command can now be modified to: -

curl -v http://localhost:8080/simple-webapp/secured -H "X-USERNAME:testuser" -H "X-PASSWORD:password"
< HTTP/1.1 200 OK
...
<
<html>
 <head><title>Secured Servlet</title></head>
 <body>
   <h1>Secured Servlet</h1>
   <p>
Current Principal 'testuser'    </p>
 </body>
</html>

The resulting output now shows authentication was successful again and the authenticated principal is 'testuser'.







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.