org.wildfly.elytron.web.undertow.server.FormAuthenticationWithClusteredSSOTest.java Source code

Java tutorial

Introduction

Here is the source code for org.wildfly.elytron.web.undertow.server.FormAuthenticationWithClusteredSSOTest.java

Source

/*
 * JBoss, Home of Professional Open Source
 *
 * Copyright 2016 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.wildfly.elytron.web.undertow.server;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.wildfly.security.password.interfaces.ClearPassword.ALGORITHM_CLEAR;

import java.security.KeyPair;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Supplier;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.remoting.transport.jgroups.JGroupsTransport;
import org.junit.Rule;
import org.junit.Test;
import org.wildfly.elytron.web.undertow.server.util.KeyPairSupplier;
import org.wildfly.elytron.web.undertow.server.util.UndertowServer;
import org.wildfly.security.auth.permission.LoginPermission;
import org.wildfly.security.auth.realm.SimpleMapBackedSecurityRealm;
import org.wildfly.security.auth.realm.SimpleRealmEntry;
import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.credential.PasswordCredential;
import org.wildfly.security.http.HttpServerAuthenticationMechanismFactory;
import org.wildfly.security.http.util.sso.DefaultSingleSignOnManager;
import org.wildfly.security.http.util.sso.DefaultSingleSignOnSessionFactory;
import org.wildfly.security.http.util.sso.DefaultSingleSignOnSessionIdentifierFactory;
import org.wildfly.security.http.util.sso.SingleSignOnEntry;
import org.wildfly.security.http.util.sso.SingleSignOnManager;
import org.wildfly.security.http.util.sso.SingleSignOnServerMechanismFactory;
import org.wildfly.security.http.util.sso.SingleSignOnSessionFactory;
import org.wildfly.security.password.PasswordFactory;
import org.wildfly.security.password.spec.ClearPasswordSpec;
import org.wildfly.security.permission.PermissionVerifier;

import io.undertow.server.session.InMemorySessionManager;
import io.undertow.server.session.SessionManager;

/**
 * Test case to test HTTP FORM authentication where authentication is backed by Elytron and session replication is enabled.
 *
 * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
 * @author Paul Ferraro
 */
public class FormAuthenticationWithClusteredSSOTest extends AbstractHttpServerMechanismTest {

    private final Map<Integer, SessionManager> sessionManagers = new HashMap<>();

    private final Supplier<KeyPair> keyPairSupplier = new KeyPairSupplier();

    @Rule
    public final UndertowServer serverA = createUndertowServer(7776);

    @Rule
    public final UndertowServer serverB = createUndertowServer(7777);

    @Rule
    public final UndertowServer serverC = createUndertowServer(7778);

    @Rule
    public final UndertowServer serverD = createUndertowServer(7779);

    @Rule
    public final UndertowServer serverE = createUndertowServer(7780);

    private UndertowServer createUndertowServer(int port) {
        InMemorySessionManager sessionManager = new InMemorySessionManager(String.valueOf(port));

        sessionManagers.put(port, sessionManager);

        return new UndertowServer(createRootHttpHandler(sessionManager), port, sessionManager.getDeploymentName());
    }

    @Test
    public void testSingleSignOn() throws Exception {
        BasicCookieStore cookieStore = new BasicCookieStore();
        HttpClient httpClient = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).build();

        assertLoginPage(httpClient.execute(new HttpGet(serverA.createUri())));

        assertFalse(cookieStore.getCookies().stream().filter(cookie -> cookie.getName().equals("JSESSIONSSOID"))
                .findAny().isPresent());

        // authenticate on NODE_A
        HttpPost httpAuthenticate = new HttpPost(serverA.createUri("/j_security_check"));
        List<NameValuePair> parameters = new ArrayList<>(2);

        parameters.add(new BasicNameValuePair("j_username", "ladybird"));
        parameters.add(new BasicNameValuePair("j_password", "Coleoptera"));

        httpAuthenticate.setEntity(new UrlEncodedFormEntity(parameters));

        HttpResponse execute = httpClient.execute(httpAuthenticate);

        assertTrue(cookieStore.getCookies().stream().filter(cookie -> cookie.getName().equals("JSESSIONSSOID"))
                .findAny().isPresent());
        assertSuccessfulResponse(execute, "ladybird");
        assertSuccessfulResponse(httpClient.execute(new HttpGet(serverB.createUri())), "ladybird");
        assertSuccessfulResponse(httpClient.execute(new HttpGet(serverC.createUri())), "ladybird");
        assertSuccessfulResponse(httpClient.execute(new HttpGet(serverD.createUri())), "ladybird");
        assertSuccessfulResponse(httpClient.execute(new HttpGet(serverE.createUri())), "ladybird");
    }

    @Test
    public void testSingleLogout() throws Exception {
        BasicCookieStore cookieStore = new BasicCookieStore();
        HttpClient httpClient = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).build();

        assertLoginPage(httpClient.execute(new HttpGet(serverA.createUri())));

        // authenticate on NODE_A
        HttpPost httpAuthenticate = new HttpPost(serverA.createUri("/j_security_check"));
        List<NameValuePair> parameters = new ArrayList<>();

        parameters.add(new BasicNameValuePair("j_username", "ladybird"));
        parameters.add(new BasicNameValuePair("j_password", "Coleoptera"));

        httpAuthenticate.setEntity(new UrlEncodedFormEntity(parameters));

        HttpResponse execute = httpClient.execute(httpAuthenticate);

        assertSuccessfulResponse(execute, "ladybird");
        assertSuccessfulResponse(httpClient.execute(new HttpGet(serverB.createUri())), "ladybird");
        assertSuccessfulResponse(httpClient.execute(new HttpGet(serverC.createUri())), "ladybird");
        assertSuccessfulResponse(httpClient.execute(new HttpGet(serverD.createUri())), "ladybird");
        assertSuccessfulResponse(httpClient.execute(new HttpGet(serverE.createUri())), "ladybird");

        httpClient.execute(new HttpGet(serverB.createUri("/logout")));

        assertLoginPage(httpClient.execute(new HttpGet(serverC.createUri())));
        assertLoginPage(httpClient.execute(new HttpGet(serverA.createUri())));
        assertLoginPage(httpClient.execute(new HttpGet(serverB.createUri())));
        assertLoginPage(httpClient.execute(new HttpGet(serverD.createUri())));
        assertLoginPage(httpClient.execute(new HttpGet(serverE.createUri())));
    }

    @Test
    public void testSingleLogoutWhenNodeIsFailing() throws Exception {
        BasicCookieStore cookieStore = new BasicCookieStore();
        HttpClient httpClient = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).build();

        assertLoginPage(httpClient.execute(new HttpGet(serverA.createUri())));

        // authenticate on NODE_A
        HttpPost httpAuthenticate = new HttpPost(serverA.createUri("/j_security_check"));
        List<NameValuePair> parameters = new ArrayList<>(2);

        parameters.add(new BasicNameValuePair("j_username", "ladybird"));
        parameters.add(new BasicNameValuePair("j_password", "Coleoptera"));

        httpAuthenticate.setEntity(new UrlEncodedFormEntity(parameters));

        HttpResponse execute = httpClient.execute(httpAuthenticate);

        assertSuccessfulResponse(execute, "ladybird");
        assertSuccessfulResponse(httpClient.execute(new HttpGet(serverB.createUri())), "ladybird");
        assertSuccessfulResponse(httpClient.execute(new HttpGet(serverC.createUri())), "ladybird");
        assertSuccessfulResponse(httpClient.execute(new HttpGet(serverD.createUri())), "ladybird");
        assertSuccessfulResponse(httpClient.execute(new HttpGet(serverE.createUri())), "ladybird");

        serverC.forceShutdown();
        serverE.forceShutdown();

        httpClient.execute(new HttpGet(serverB.createUri("/logout")));

        assertLoginPage(httpClient.execute(new HttpGet(serverA.createUri())));
        assertLoginPage(httpClient.execute(new HttpGet(serverB.createUri())));
        assertLoginPage(httpClient.execute(new HttpGet(serverD.createUri())));
    }

    @Test
    public void testSessionInvalidation() throws Exception {
        BasicCookieStore cookieStore = new BasicCookieStore();
        HttpClient httpClient = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).build();

        assertLoginPage(httpClient.execute(new HttpGet(serverA.createUri())));

        for (int i = 0; i < 10; i++) {
            HttpPost httpAuthenticate = new HttpPost(serverA.createUri("/j_security_check"));
            List<NameValuePair> parameters = new ArrayList<>(2);

            parameters.add(new BasicNameValuePair("j_username", "ladybird"));
            parameters.add(new BasicNameValuePair("j_password", "Coleoptera"));

            httpAuthenticate.setEntity(new UrlEncodedFormEntity(parameters));

            HttpResponse execute = httpClient.execute(httpAuthenticate);

            assertSuccessfulResponse(execute, "ladybird");
            assertSuccessfulResponse(httpClient.execute(new HttpGet(serverA.createUri())), "ladybird");
            assertSuccessfulResponse(httpClient.execute(new HttpGet(serverB.createUri())), "ladybird");
            assertSuccessfulResponse(httpClient.execute(new HttpGet(serverC.createUri())), "ladybird");
            assertSuccessfulResponse(httpClient.execute(new HttpGet(serverD.createUri())), "ladybird");
            assertSuccessfulResponse(httpClient.execute(new HttpGet(serverE.createUri())), "ladybird");

            httpClient.execute(new HttpGet(serverA.createUri("/logout")));

            assertLoginPage(httpClient.execute(new HttpGet(serverC.createUri())));
            assertLoginPage(httpClient.execute(new HttpGet(serverA.createUri())));
            assertLoginPage(httpClient.execute(new HttpGet(serverB.createUri())));
            assertLoginPage(httpClient.execute(new HttpGet(serverD.createUri())));
            assertLoginPage(httpClient.execute(new HttpGet(serverE.createUri())));
        }

        this.sessionManagers.values().forEach(
                manager -> assertEquals(manager.getDeploymentName(), 1, manager.getActiveSessions().size()));
    }

    @Override
    protected String getMechanismName() {
        return "FORM";
    }

    @Override
    protected SecurityDomain doCreateSecurityDomain() throws Exception {
        PasswordFactory passwordFactory = PasswordFactory.getInstance(ALGORITHM_CLEAR);
        Map<String, SimpleRealmEntry> passwordMap = new HashMap<>();

        passwordMap.put("ladybird", new SimpleRealmEntry(Collections.singletonList(new PasswordCredential(
                passwordFactory.generatePassword(new ClearPasswordSpec("Coleoptera".toCharArray()))))));

        SimpleMapBackedSecurityRealm securityRealm = new SimpleMapBackedSecurityRealm();

        securityRealm.setPasswordMap(passwordMap);

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

        builder.addRealm("TestRealm", securityRealm).build();
        builder.setPermissionMapper((principal, roles) -> PermissionVerifier.from(new LoginPermission()));

        return builder.build();
    }

    @Override
    protected HttpServerAuthenticationMechanismFactory doCreateHttpServerMechanismFactory(
            Map<String, ?> properties) {
        HttpServerAuthenticationMechanismFactory delegate = super.doCreateHttpServerMechanismFactory(properties);

        String cacheManagerName = UUID.randomUUID().toString();
        EmbeddedCacheManager cacheManager = new DefaultCacheManager(
                GlobalConfigurationBuilder.defaultClusteredBuilder().globalJmxStatistics()
                        .cacheManagerName(cacheManagerName).transport().nodeName(cacheManagerName)
                        .addProperty(JGroupsTransport.CONFIGURATION_FILE, "fast.xml").build(),
                new ConfigurationBuilder().clustering().cacheMode(CacheMode.REPL_SYNC).build());

        Cache<String, SingleSignOnEntry> cache = cacheManager.getCache();
        SingleSignOnManager manager = new DefaultSingleSignOnManager(cache,
                new DefaultSingleSignOnSessionIdentifierFactory(), (id, entry) -> cache.put(id, entry));
        SingleSignOnServerMechanismFactory.SingleSignOnConfiguration signOnConfiguration = new SingleSignOnServerMechanismFactory.SingleSignOnConfiguration(
                "JSESSIONSSOID", null, "/", false, false);

        SingleSignOnSessionFactory singleSignOnSessionFactory = new DefaultSingleSignOnSessionFactory(manager,
                this.keyPairSupplier.get());

        return new SingleSignOnServerMechanismFactory(delegate, singleSignOnSessionFactory, signOnConfiguration);
    }
}