Skip to content

Commit

Permalink
[WFLY-9336] Extend Elytron security context propagation test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
Ondrej Lukas committed Oct 27, 2017
1 parent 535bf19 commit 217829f
Show file tree
Hide file tree
Showing 45 changed files with 3,361 additions and 425 deletions.
Expand Up @@ -89,7 +89,7 @@
<configuration> <configuration>
<property name="jbossHome">${basedir}/target/seccontext-server1</property> <property name="jbossHome">${basedir}/target/seccontext-server1</property>
<property name="javaVmArguments">${server.jvm.args} -Djboss.inst=${basedir}/target/seccontext-server1 -Djboss.node.name=seccontext-server1</property> <property name="javaVmArguments">${server.jvm.args} -Djboss.inst=${basedir}/target/seccontext-server1 -Djboss.node.name=seccontext-server1</property>
<property name="serverConfig">standalone.xml</property> <property name="serverConfig">${jboss.server.config.file.name:standalone-ha.xml}</property>
<property name="jbossArguments">${jboss.args}</property> <property name="jbossArguments">${jboss.args}</property>
<property name="allowConnectingToRunningServer">true</property> <property name="allowConnectingToRunningServer">true</property>
<property name="managementAddress">${node0:127.0.0.1}</property> <property name="managementAddress">${node0:127.0.0.1}</property>
Expand All @@ -101,6 +101,21 @@
</configuration> </configuration>
</container> </container>


<container qualifier="seccontext-server1-backup" default="false" mode="manual">
<configuration>
<property name="jbossHome">${basedir}/target/seccontext-server1-backup</property>
<property name="javaVmArguments">${server.jvm.args} -Djboss.socket.binding.port-offset=2000 -Djboss.inst=${basedir}/target/seccontext-server1-backup -Djboss.node.name=seccontext-server1-backup</property>
<property name="serverConfig">${jboss.server.config.file.name:standalone-ha.xml}</property>
<property name="jbossArguments">${jboss.args}</property>
<property name="allowConnectingToRunningServer">true</property>
<property name="managementAddress">${node0:127.0.0.1}</property>
<property name="managementPort">11990</property>

<property name="waitForPorts">11990</property>
<property name="waitForPortsTimeoutInSeconds">8</property>
</configuration>
</container>

<container qualifier="seccontext-server2" default="false" mode="manual"> <container qualifier="seccontext-server2" default="false" mode="manual">
<configuration> <configuration>
<property name="jbossHome">${basedir}/target/seccontext-server2</property> <property name="jbossHome">${basedir}/target/seccontext-server2</property>
Expand All @@ -117,6 +132,22 @@
</configuration> </configuration>
</container> </container>


<container qualifier="seccontext-server3" default="false" mode="manual">
<configuration>
<property name="jbossHome">${basedir}/target/seccontext-server3</property>
<property name="javaVmArguments">${server.jvm2.args} -Djboss.socket.binding.port-offset=250 -Djboss.inst=${basedir}/target/seccontext-server3 -Djboss.node.name=seccontext-server3</property>
<property name="serverConfig">standalone.xml</property>
<property name="jbossArguments">${jboss.args}</property>
<property name="allowConnectingToRunningServer">true</property>
<property name="managementAddress">${node1}</property>
<property name="managementPort">10240</property>

<!-- AS7-4070 -->
<property name="waitForPorts">${as.debug.port.node1} 10240</property>
<property name="waitForPortsTimeoutInSeconds">8</property>
</configuration>
</container>

<container qualifier="jbossas-with-remote-outbound-connection-non-clustered" default="false" mode="manual"> <container qualifier="jbossas-with-remote-outbound-connection-non-clustered" default="false" mode="manual">
<configuration> <configuration>
<property name="jbossHome">${basedir}/target/jbossas-with-remote-outbound-connection</property> <property name="jbossHome">${basedir}/target/jbossas-with-remote-outbound-connection</property>
Expand Down

Large diffs are not rendered by default.

@@ -0,0 +1,141 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2017, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.test.manual.elytron.seccontext;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;

import org.junit.Test;

/**
* Authorization forwarding (credential less forwarding) for security context propagation test.
*
* @author Josef Cacek
*/
public abstract class AbstractAuthorizationForwardingTestCase extends AbstractSecurityContextPropagationTestBase {

/**
* Test the authorization forwarding (credential less propagation) works for EJB calls when {@link RunAsPrincipalPermission}
* is assigned to caller server identity.
*
* <pre>
* When: EJB client calls EntryBean as admin user and Elytron AuthenticationContext API is used to
* authorization forwarding to WhoAmIBean call with "server" user used as caller server identity
* Then: WhoAmIBean call is possible and returns "admin" username
* </pre>
*/
@Test
public void testForwardedAuthorizationPasses() throws Exception {
String[] doubleWhoAmI = SeccontextUtil.switchIdentity("admin", "admin",
getDoubleWhoAmICallable(ReAuthnType.FORWARDED_AUTHORIZATION, "server", "server"),
ReAuthnType.AC_AUTHENTICATION);
assertNotNull("The entryBean.doubleWhoAmI() should return not-null instance", doubleWhoAmI);
assertArrayEquals("Unexpected principal names returned from doubleWhoAmI", new String[]{"admin", "admin"},
doubleWhoAmI);
}

/**
* Test the authorization forwarding works for EJB calls when {@link RunAsPrincipalPermission} is not assigned to the caller
* identity, but the authentication identity == authorization identity (which has sufficient roles to call the EJB).
*
* <pre>
* When: EJB client calls EntryBean as admin user and Elytron AuthenticationContext API is used to
* authorization forwarding to WhoAmIBean call with "admin" user used as caller server identity.
* Then: WhoAmIBean call is possible and returns "admin" username
* </pre>
*/
@Test
public void testSameAuthorizationIdentityPasses() throws Exception {
String[] doubleWhoAmI = SeccontextUtil.switchIdentity("admin", "admin",
getDoubleWhoAmICallable(ReAuthnType.FORWARDED_AUTHORIZATION, "admin", "admin"), ReAuthnType.AC_AUTHENTICATION);
assertNotNull("The entryBean.doubleWhoAmI() should return not-null instance", doubleWhoAmI);
assertArrayEquals("Unexpected principal names returned from doubleWhoAmI", new String[]{"admin", "admin"},
doubleWhoAmI);
}

/**
* Test the authorization forwarding fails for EJB calls when {@link RunAsPrincipalPermission} is not assigned to the caller
* identity.
*
* <pre>
* When: EJB client calls EntryBean as admin user and Elytron AuthenticationContext API is used to
* authorization forwarding to WhoAmIBean call with either "server-norunas" or "whoami" users
* used as caller server identity.
* Then: WhoAmIBean call fails in both cases as the server identity don't have RunAsPrincipalPermission
* </pre>
*/
@Test
public void testForwardedAuthorizationIdentityWithoutRunAsFails() throws Exception {
String[] doubleWhoAmI = SeccontextUtil.switchIdentity("admin", "admin",
getDoubleWhoAmICallable(ReAuthnType.FORWARDED_AUTHORIZATION, "server-norunas", "server-norunas"),
ReAuthnType.AC_AUTHENTICATION);
assertNotNull("The entryBean.doubleWhoAmI() should return not-null instance", doubleWhoAmI);
assertThat(doubleWhoAmI[1], isEjbAuthenticationError());

doubleWhoAmI = SeccontextUtil.switchIdentity("admin", "admin",
getDoubleWhoAmICallable(ReAuthnType.FORWARDED_AUTHORIZATION, "whoami", "whoami"),
ReAuthnType.AC_AUTHENTICATION);
assertNotNull("The entryBean.doubleWhoAmI() should return not-null instance", doubleWhoAmI);
assertThat(doubleWhoAmI[1], isEjbAuthenticationError());
}

/**
* Test propagation of RuntimeException back to server1 during a call using the authorization forwarding.
*
* <pre>
* When: EJB client calls EntryBean as admin user and Elytron AuthenticationContext API is used to
* authorization forwarding to WhoAmIBean call with "server" user used as caller server identity
* Then: WhoAmIBean.throwIllegalStateException call should result in expected IllegalStateException.
* </pre>
*/
@Test
public void testIllegalStateExceptionFromForwardedAuthz() throws Exception {
String[] doubleWhoAmI = SeccontextUtil.switchIdentity("admin", "admin",
getWhoAmIAndIllegalStateExceptionCallable(ReAuthnType.FORWARDED_AUTHORIZATION, "server", "server"),
ReAuthnType.AC_AUTHENTICATION);
assertNotNull("The entryBean.whoAmIAndIllegalStateException() should return not-null instance", doubleWhoAmI);
assertEquals("admin", doubleWhoAmI[0]);
assertThat(doubleWhoAmI[1], isExpectedIllegalStateException());
}

/**
* Test propagation of Server2Exception (unknown on server1) back to server1 during a call using the authorization
* forwarding.
*
* <pre>
* When: EJB client calls EntryBean as admin user and Elytron AuthenticationContext API is used to
* authorization forwarding to WhoAmIBean call with "server" user used as caller server identity
* Then: WhoAmIBean.throwServer2Exception call should result in expected ClassNotFoundException.
* </pre>
*/
@Test
public void testServer2ExceptionFromForwardedAuthz() throws Exception {
String[] doubleWhoAmI = SeccontextUtil.switchIdentity("admin", "admin",
getWhoAmIAndServer2ExceptionCallable(ReAuthnType.FORWARDED_AUTHORIZATION, "server", "server"),
ReAuthnType.AC_AUTHENTICATION);
assertNotNull("The entryBean.whoAmIAndServer2Exception() should return not-null instance", doubleWhoAmI);
assertEquals("admin", doubleWhoAmI[0]);
assertThat(doubleWhoAmI[1], isClassNotFoundException_Server2Exception());
}
}
@@ -0,0 +1,138 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2017, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.test.manual.elytron.seccontext;

import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.jboss.as.test.integration.security.common.Utils.REDIRECT_STRATEGY;
import static org.junit.Assert.assertEquals;
import static org.wildfly.test.manual.elytron.seccontext.AbstractSecurityContextPropagationTestBase.server1;
import static org.wildfly.test.manual.elytron.seccontext.SeccontextUtil.SERVER1_BACKUP;
import static org.wildfly.test.manual.elytron.seccontext.SeccontextUtil.WAR_ENTRY_SERVLET_FORM;

import java.io.IOException;
import java.net.URL;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.as.cli.CommandLineException;
import org.jboss.as.test.integration.management.util.MgmtOperationException;
import org.jboss.as.test.shared.TestSuiteEnvironment;
import org.jboss.shrinkwrap.api.Archive;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;

/**
* Tests authorization forwarding within a cluster.
*
* <h3>Given</h3>
* See the superclass for common implementation details.
* <pre>
* Additional started and configured servers:
* - seccontext-server1-backup (standalone-ha.xml - creates cluster with seccontext-server1) -
* * entry-servlet-form.war
* </pre>
* @author Josef Cacek
*/
public abstract class AbstractHAAuthorizationForwardingTestCase extends AbstractSecurityContextPropagationTestBase {

private static final ServerHolder server1backup = new ServerHolder(SERVER1_BACKUP, TestSuiteEnvironment.getServerAddress(),
2000);

/**
* Creates deployment with Entry servlet and FORM authentication.
*/
@Deployment(name = WAR_ENTRY_SERVLET_FORM + "backup", managed = false, testable = false)
@TargetsContainer(SERVER1_BACKUP)
public static Archive<?> createDeploymentForBackup() {
return createEntryServletFormAuthnDeployment();
}

/**
* Start server1backup.
*/
@Before
public void startServer1backup() throws CommandLineException, IOException, MgmtOperationException {
server1backup.resetContainerConfiguration(new ServerConfigurationBuilder()
.withDeployments(WAR_ENTRY_SERVLET_FORM + "backup")
.build());
}

/**
* Shut down server1backup.
*/
@AfterClass
public static void shutdownServer1backup() throws IOException {
server1backup.shutDown();
}

/**
* Verifies, the distributable web-app with FORM authentication supports session replication out of the box.
*
* <pre>
* When: HTTP client calls WhoAmIServlet as "admin" (using FORM authn) on first cluster node and then
* it calls WhoAmIServlet (without authentication needed) on the second cluster node
* Then: the call to WhoAmIServlet on second node (without authentication) passes and returns "admin"
* (i.e. SSO works with FORM authentication)
* </pre>
*/
@Test
public void testServletSso() throws Exception {
final URL whoamiUrl = new URL(
server1.getApplicationHttpUrl() + "/" + WAR_ENTRY_SERVLET_FORM + WhoAmIServlet.SERVLET_PATH);
final URL whoamiBackupUrl = new URL(
server1backup.getApplicationHttpUrl() + "/" + WAR_ENTRY_SERVLET_FORM + WhoAmIServlet.SERVLET_PATH);

try (final CloseableHttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(REDIRECT_STRATEGY).build()) {
assertEquals("Unexpected result from WhoAmIServlet", "admin",
doHttpRequestFormAuthn(httpClient, whoamiUrl, true, "admin", "admin", SC_OK));
assertEquals("Unexpected result from WhoAmIServlet (backup-server)", "admin",
doHttpRequest(httpClient, whoamiBackupUrl, SC_OK));
}
}

/**
* Verifies, the authorization forwarding works within cluster (FORM authn). This simulates failover on
* distributed web application (e.g. when load balancer is used).
*
* <pre>
* When: HTTP client calls WhoAmIServlet as "admin" (using FORM authn) on second cluster node and then
* it calls EntryServlet (without authentication needed) on the first cluster node;
* the EntryServlet uses Elytron API to forward authz name to call remote WhoAmIBean
* Then: the calls pass and WhoAmIBean returns "admin" username
* </pre>
*/
@Test
public void testServletSsoPropagation() throws Exception {
final URL entryServletUrl = getEntryServletUrl(WAR_ENTRY_SERVLET_FORM, "server", "server",
ReAuthnType.FORWARDED_AUTHORIZATION);
final URL whoamiUrl = new URL(
server1backup.getApplicationHttpUrl() + "/" + WAR_ENTRY_SERVLET_FORM + WhoAmIServlet.SERVLET_PATH);

try (final CloseableHttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(REDIRECT_STRATEGY).build()) {
assertEquals("Unexpected result from WhoAmIServlet (backup-server)", "admin",
doHttpRequestFormAuthn(httpClient, whoamiUrl, true, "admin", "admin", SC_OK));
assertEquals("Unexpected result from EntryServlet", "admin", doHttpRequest(httpClient, entryServletUrl, SC_OK));
}
}
}

0 comments on commit 217829f

Please sign in to comment.