Securing Netty applications with Elytron

This article introduces you to securing Netty applications using Elytron security framework, which is a core component of WildFly application server.


Setting up the Netty Project

The example project we will discuss here is available in the elytron examples repository. To set up a secured Netty server we will add the following components:

  • An InboundHandler which allows to handle a specific type of messages. In this example, we will be handling incoming HttpObject.
  • A Channel Initializer: This is a special handler whose purpose is to initialize the connection applying the Security layer in the Channel pipeline.
  • A Main class which bootstraps the Netty Server, adding as Child Handler the Channel Initializer, which in turns contains a reference to Elytron Security domain

Let’s start checking each single component, starting from the Main class.

Coding the BootStrap Class

To bootstrap a Netty server, you need to use a ServerBootstrap Class. The difference from a plain text Netty server is that, in this example, we are adding a Security Handler as Child Handler.

To create the Security Handler we use the ElytronHandlers which is backed by a SimpleMapBackedSecurityRealm:

public class HelloWorld {

    private static final WildFlyElytronProvider elytronProvider = new WildFlyElytronProvider();

    private static final int PORT = 7776;

     * @param args
    public static void main(String[] args) throws Exception {
        System.out.println("Here we go");

        SecurityDomain securityDomain = createSecurityDomain();

        EventLoopGroup parentGroup = new NioEventLoopGroup(1);
        EventLoopGroup childGroup = new NioEventLoopGroup(1);

        ElytronHandlers securityHandlers = ElytronHandlers.newInstance()
                                .addMechanismRealm(MechanismRealmConfiguration.builder().setRealmName("Elytron Realm").build())

        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.option(ChannelOption.SO_BACKLOG, 1024);, childGroup)
            .handler(new LoggingHandler(LogLevel.INFO))
            .childHandler(new TestInitialiser(securityHandlers));


    private static HttpServerAuthenticationMechanismFactory createHttpAuthenticationFactory() {
        HttpServerAuthenticationMechanismFactory factory = new SecurityProviderServerMechanismFactory(() -> new Provider[] {elytronProvider});

        return  new FilterServerMechanismFactory(factory, true, "BASIC");

    private static SecurityDomain createSecurityDomain() throws Exception {
        // Create an Elytron map-backed security realm
        SimpleMapBackedSecurityRealm simpleRealm = new SimpleMapBackedSecurityRealm(() -> new Provider[] { elytronProvider });
        Map<String, SimpleRealmEntry> identityMap = new HashMap<>();

        // Add user alice
        identityMap.put("alice", new SimpleRealmEntry(getCredentialsForClearPassword("alice123+"), getAttributesForRoles("employee", "admin")));

        // Add user bob
        identityMap.put("bob", new SimpleRealmEntry(getCredentialsForClearPassword("bob123+"), getAttributesForRoles("employee")));


        // Add the map-backed security realm to a new security domain's list of realms
        SecurityDomain.Builder builder = SecurityDomain.builder()
                .addRealm("ExampleRealm", simpleRealm).build()
                .setPermissionMapper((principal, roles) -> PermissionVerifier.from(new LoginPermission()))


    private static List<Credential> getCredentialsForClearPassword(String clearPassword) throws Exception {
        PasswordFactory passwordFactory = PasswordFactory.getInstance(ALGORITHM_CLEAR, elytronProvider);
        return Collections.singletonList(new PasswordCredential(passwordFactory.generatePassword(new ClearPasswordSpec(clearPassword.toCharArray()))));

    private static MapAttributes getAttributesForRoles(String... roles) {
        MapAttributes attributes = new MapAttributes();
        HashSet<String> rolesSet = new HashSet<>();
        if (roles != null) {
            for (String role : roles) {
        attributes.addAll(RoleDecoder.KEY_ROLES, rolesSet);
        return attributes;


If you want to switch to another kind of Realm, update the method createSecurityDomain accordingly. For example, here is how to create a FileSystemSecurityRealm:

FileSystemSecurityRealm fsRealm = new FileSystemSecurityRealm(fsRealmPath, NameRewriter.IDENTITY_REWRITER, 2, true);

Coding the Content Handler

Next, we will be adding the InBoundHandler which reads the incoming HTTP Connections and produces a Response. The response is an FullHttpResponse which also includes the Security’s Principal Name:

class TestContentHandler extends SimpleChannelInboundHandler<HttpObject> {

    private static final AsciiString CONTENT_TYPE = AsciiString.cached("Content-Type");
    private static final AsciiString CONTENT_LENGTH = AsciiString.cached("Content-Length");
    private static final AsciiString CONNECTION = AsciiString.cached("Connection");
    private static final AsciiString KEEP_ALIVE = AsciiString.cached("keep-alive");

    TestContentHandler() {

    public void channelReadComplete(ChannelHandlerContext ctx) {


    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {

        if (msg instanceof HttpRequest) {
            HttpRequest req = (HttpRequest) msg;

            boolean keepAlive = HttpUtil.isKeepAlive(req);
            final String identity = getElytronIdentity();
            FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(getContent(identity)));
            response.headers().set(CONTENT_TYPE, "text/plain");
            response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());

            if (!keepAlive) {
            } else {
                response.headers().set(CONNECTION, KEEP_ALIVE);
        } else {
            System.out.println("TestContentHandler - Not a HttpRequest");


    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {

    private byte[] getContent(final String identity) {
        return String.format("Current identity '%s'", identity).getBytes(StandardCharsets.UTF_8);

    private String getElytronIdentity() {
        SecurityDomain securityDomain = SecurityDomain.getCurrent();
        if (securityDomain != null) {
            SecurityIdentity securityIdentity = securityDomain.getCurrentSecurityIdentity();
            if (securityIdentity != null) {
                return securityIdentity.getPrincipal().getName();

        return null;


Coding the ChannelInitializer

Finally, to bootstrap our Netty Server we need a ChannelInitializer. The ChannelInitializer contains a Pipeline of Handlers. In this example, we are adding at the end of the Pipeline the Handler from our previous section:

class TestInitialiser extends ChannelInitializer<SocketChannel> {

    private final Function<ChannelPipeline, ChannelPipeline> securityHandler;

    TestInitialiser(final Function<ChannelPipeline, ChannelPipeline> securityHandler) {
        this.securityHandler = securityHandler;

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


Testing the example

The example project includes a Maven Java exec plugin, therefore you can build and run it as follows:

mvn clean install exec:exec

As you can see from the following snapshot, the servers starts and binds Netty to all available network addresses on port 7776:

Then, from the browser or the command line, use one of the available identities to reach the Netty Server. For example:

$ curl -u alice:alice123+ http://localhost:7776
Current identity 'alice'


That’s all. This article was a quick walk through an example of a Netty Server which uses an Elytron Security Domain in the Pipiline of its Socket Handlers