Showing posts with label BASIC. Show all posts
Showing posts with label BASIC. 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.


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.