/*
* 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.integration.elytron.realm;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import org.apache.commons.io.FileUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;
import org.codehaus.plexus.util.StringUtils;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.as.arquillian.api.ServerSetupTask;
import org.jboss.as.arquillian.container.ManagementClient;
import org.jboss.as.test.integration.management.util.CLIWrapper;
import org.jboss.as.test.integration.security.common.Utils;
import static org.jboss.as.test.integration.security.common.Utils.createTemporaryFolder;
import org.jboss.as.test.integration.security.common.servlets.RolePrintingServlet;
import org.jboss.as.test.shared.CliUtils;
import static org.jboss.as.test.shared.CliUtils.asAbsolutePath;
import org.jboss.as.test.shared.ServerReload;
import org.jboss.crypto.CryptoUtil;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Test case for Elytron Aggregate Realm.
*
* It tests two types of scenarios:
* <ul>
* <li>Both, authentication and authorization realm, is the same Elytron Realm type (both are Properties Realm for this test
* case)</li>
* <li>Both is the different Elytron Realm type (Filesystem Realm for authentication and Properties Realm for
* authorization)</li>
* </ul>
*
* Given: Secured application for printing roles secured by Aggregate Realm.<br>
*
* @author olukas
*/
@RunWith(Arquillian.class)
@RunAsClient
@ServerSetup({AggregateRealmTestCase.SetupTask.class})
public class AggregateRealmTestCase {
private static final String CHARSET_UTF_8 = "UTF-8";
private static final String AGGREGATE_REALM_SAME_TYPE_NAME = "elytron-aggregate-realm-same-type";
private static final String AGGREGATE_REALM_DIFFERENT_TYPE_NAME = "elytron-aggregate-realm-different-type";
private static final String USER_WITHOUT_ROLE = "userWithoutRole";
private static final String USER_WITH_ONE_ROLE = "userWithOneRole";
private static final String USER_WITH_TWO_ROLES = "userWithTwoRoles";
private static final String USER_WITH_DIFFERENT_ROLE_IN_DIFFERENT_REALM = "userWithDifferentRoleInDifferentRealm";
private static final String USER_ONLY_IN_AUTHORIZATION = "userOnlyInAuthorization";
private static final String WRONG_USER = "wrongUser";
private static final String CORRECT_PASSWORD = "password";
private static final String AUTHORIZATION_REALM_PASSWORD = "passwordInAuthzRealm";
private static final String WRONG_PASSWORD = "wrongPassword";
private static final String EMPTY_PASSWORD = "";
private static final String ROLE_ADMIN = "Admin";
private static final String ROLE_USER = "User";
private static final String[] ALL_TESTED_ROLES = {ROLE_ADMIN, ROLE_USER};
static final String QUERY_ROLES;
static {
final List<NameValuePair> qparams = new ArrayList<>();
for (final String role : ALL_TESTED_ROLES) {
qparams.add(new BasicNameValuePair(RolePrintingServlet.PARAM_ROLE_NAME, role));
}
QUERY_ROLES = URLEncodedUtils.format(qparams, "UTF-8");
}
@Deployment(name = AGGREGATE_REALM_SAME_TYPE_NAME)
public static WebArchive deploymentSameType() {
return deployment(AGGREGATE_REALM_SAME_TYPE_NAME);
}
@Deployment(name = AGGREGATE_REALM_DIFFERENT_TYPE_NAME)
public static WebArchive deploymentDifferentType() {
return deployment(AGGREGATE_REALM_DIFFERENT_TYPE_NAME);
}
private static WebArchive deployment(String name) {
final WebArchive war = ShrinkWrap.create(WebArchive.class, name + ".war");
war.addClasses(RolePrintingServlet.class);
war.addAsWebInfResource(AggregateRealmTestCase.class.getPackage(), "aggregate-realm-web.xml", "web.xml");
war.addAsWebInfResource(Utils.getJBossWebXmlAsset(name), "jboss-web.xml");
return war;
}
/**
* Given: Authentication is provided by Elytron Properties Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and roles property file maps no roles for the user. <br>
* When the user with correct username and password tries to authenticate, <br>
* then authentication should succeed <br>
* and authorization should fail - no roles should be assigned to the user (HTTP status 403 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_SAME_TYPE_NAME)
public void userWithNoRoles_userInBothRealm_sameTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
userWithNoRoles_userInBothRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Properties Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and roles property file maps role 'User' for the user. <br>
* When user with correct username and password tries to authenticate, <br>
* then authentication should succeed <br>
* and just role 'User' should be assigned to the user.
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_SAME_TYPE_NAME)
public void userWithOneRole_userInBothRealm_sameTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
userWithOneRole_userInBothRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Properties Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and roles property file maps roles 'User' and 'Admin' for the user. <br>
* When user with correct username and password tries to authenticate, <br>
* then authentication should succeed <br>
* and just roles 'User' and 'Admin' should be assigned to the user.
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_SAME_TYPE_NAME)
public void userWithTwoRoles_userInBothRealm_sameTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
userWithTwoRoles_userInBothRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Properties Realm<br>
* and authorization is provided by another Elytron Properties Realm.<br>
* When the user with correct username but wrong password tries to authenticate, <br>
* then authentication should fail (HTTP status 401 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_SAME_TYPE_NAME)
public void wrongPassword_userInBothRealm_sameTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
wrongPassword_userInBothRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Properties Realm<br>
* and authorization is provided by another Elytron Properties Realm.<br>
* When the user with correct username but with empty password tries to authenticate, <br>
* then authentication should fail (HTTP status 401 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_SAME_TYPE_NAME)
public void emptyPassword_userInBothRealm_sameTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
emptyPassword_userInBothRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Properties Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and realm used for authorization define different password for the user then realm for authentication.<br>
* When the user with correct username but with password from realm for authorization tries to authenticate, <br>
* then authentication should fail (HTTP status 401 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_SAME_TYPE_NAME)
public void passwordFromAuthzRealm_userInBothRealm_sameTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
passwordFromAuthzRealm_userInBothRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Properties Realm<br>
* and authorization is provided by another Elytron Properties Realm.<br>
* When non-exist user tries to authenticate, <br>
* then authentication should fail (HTTP status 401 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_SAME_TYPE_NAME)
public void wrongUser_sameTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
wrongUser(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Properties Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and realm for authentication maps role 'User' for the user <br>
* and realm for authorization maps role 'Admin' for the user. <br>
* When user with correct username and password tries to authenticate, <br>
* then authentication should succeed <br>
* and just role 'Admin' should be assigned to the user.
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_SAME_TYPE_NAME)
public void userWithDifferentRoleInDifferentRealm_sameTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
userWithDifferentRoleInDifferentRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Properties Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and roles property file maps role 'User' for the user <br>
* and realm for authorization does not include user's username in authentication store. <br>
* When user with correct username and password tries to authenticate, <br>
* then authentication should succeed <br>
* and just role 'User' should be assigned to the user.
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_SAME_TYPE_NAME)
public void correctPassword_userOnlyInAuthzRealm_sameTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
correctPassword_userOnlyInAuthzRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Properties Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and realm for authorization does not include user's username in authentication store. <br>
* When the user with correct username but wrong password tries to authenticate, <br>
* then authentication should fail (HTTP status 401 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_SAME_TYPE_NAME)
public void wrongPassword_userOnlyInAuthzRealm_sameTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
wrongPassword_userOnlyInAuthzRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Properties Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and realm for authorization does not include user's username in authentication store. <br>
* When the user with correct username but with empty password tries to authenticate, <br>
* then authentication should fail (HTTP status 401 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_SAME_TYPE_NAME)
public void emptyPassword_userOnlyInAuthzRealm_sameTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
emptyPassword_userOnlyInAuthzRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Filesystem Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and roles property file maps no roles for the user. <br>
* When the user with correct username and password tries to authenticate, <br>
* then authentication should succeed <br>
* and authorization should fail - no roles should be assigned to the user (HTTP status 403 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_DIFFERENT_TYPE_NAME)
public void userWithNoRoles_userInBothRealm_differentTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
userWithNoRoles_userInBothRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Filesystem Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and roles property file maps role 'User' for the user. <br>
* When user with correct username and password tries to authenticate, <br>
* then authentication should succeed <br>
* and just role 'User' should be assigned to the user.
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_DIFFERENT_TYPE_NAME)
public void userWithOneRole_userInBothRealm_differentTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
userWithOneRole_userInBothRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Filesystem Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and roles property file maps roles 'User' and 'Admin' for the user. <br>
* When user with correct username and password tries to authenticate, <br>
* then authentication should succeed <br>
* and just roles 'User' and 'Admin' should be assigned to the user.
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_DIFFERENT_TYPE_NAME)
public void userWithTwoRoles_userInBothRealm_differentTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
userWithTwoRoles_userInBothRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Filesystem Realm<br>
* and authorization is provided by another Elytron Properties Realm.<br>
* When the user with correct username but wrong password tries to authenticate, <br>
* then authentication should fail (HTTP status 401 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_DIFFERENT_TYPE_NAME)
public void wrongPassword_userInBothRealm_differentTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
wrongPassword_userInBothRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Filesystem Realm<br>
* and authorization is provided by another Elytron Properties Realm.<br>
* When the user with correct username but with empty password tries to authenticate, <br>
* then authentication should fail (HTTP status 401 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_DIFFERENT_TYPE_NAME)
public void emptyPassword_userInBothRealm_differentTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
emptyPassword_userInBothRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Filesystem Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and realm used for authorization define different password for the user then realm for authentication.<br>
* When the user with correct username but with password from realm for authorization tries to authenticate, <br>
* then authentication should fail (HTTP status 401 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_DIFFERENT_TYPE_NAME)
public void passwordFromAuthzRealm_userInBothRealm_differentTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
passwordFromAuthzRealm_userInBothRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Filesystem Realm<br>
* and authorization is provided by another Elytron Properties Realm.<br>
* When non-exist user tries to authenticate, <br>
* then authentication should fail (HTTP status 401 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_DIFFERENT_TYPE_NAME)
public void wrongUser_differentTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
wrongUser(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Filesystem Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and realm for authentication maps role 'User' for the user <br>
* and realm for authorization maps role 'Admin' for the user. <br>
* When user with correct username and password tries to authenticate, <br>
* then authentication should succeed <br>
* and just role 'Admin' should be assigned to the user.
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_DIFFERENT_TYPE_NAME)
public void userWithDifferentRoleInDifferentRealm_differentTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
userWithDifferentRoleInDifferentRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Filesystem Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and roles property file maps role 'User' for the user <br>
* and realm for authorization does not include user's username in authentication store. <br>
* When user with correct username and password tries to authenticate, <br>
* then authentication should succeed <br>
* and just role 'User' should be assigned to the user.
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_DIFFERENT_TYPE_NAME)
public void correctPassword_userOnlyInAuthzRealm_differentTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
correctPassword_userOnlyInAuthzRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Filesystem Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and realm for authorization does not include user's username in authentication store. <br>
* When the user with correct username but wrong password tries to authenticate, <br>
* then authentication should fail (HTTP status 401 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_DIFFERENT_TYPE_NAME)
public void wrongPassword_userOnlyInAuthzRealm_differentTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
wrongPassword_userOnlyInAuthzRealm(webAppURL);
}
/**
* Given: Authentication is provided by Elytron Filesystem Realm<br>
* and authorization is provided by another Elytron Properties Realm<br>
* and realm for authorization does not include user's username in authentication store. <br>
* When the user with correct username but with empty password tries to authenticate, <br>
* then authentication should fail (HTTP status 401 is returned).
*/
@Test
@OperateOnDeployment(AGGREGATE_REALM_DIFFERENT_TYPE_NAME)
public void emptyPassword_userOnlyInAuthzRealm_differentTypeRealm(@ArquillianResource URL webAppURL) throws Exception {
emptyPassword_userOnlyInAuthzRealm(webAppURL);
}
private void userWithNoRoles_userInBothRealm(URL webAppURL) throws Exception {
assertNoRoleAssigned(webAppURL, USER_WITHOUT_ROLE, CORRECT_PASSWORD);
}
private void userWithOneRole_userInBothRealm(URL webAppURL) throws Exception {
testAssignedRoles(webAppURL, USER_WITH_ONE_ROLE, CORRECT_PASSWORD, ROLE_USER);
}
private void userWithTwoRoles_userInBothRealm(URL webAppURL) throws Exception {
testAssignedRoles(webAppURL, USER_WITH_TWO_ROLES, CORRECT_PASSWORD, ROLE_USER, ROLE_ADMIN);
}
private void wrongPassword_userInBothRealm(URL webAppURL) throws Exception {
assertAuthenticationFailed(webAppURL, USER_WITH_ONE_ROLE, WRONG_PASSWORD);
}
private void emptyPassword_userInBothRealm(URL webAppURL) throws Exception {
assertAuthenticationFailed(webAppURL, USER_WITH_ONE_ROLE, EMPTY_PASSWORD);
}
private void passwordFromAuthzRealm_userInBothRealm(URL webAppURL) throws Exception {
assertAuthenticationFailed(webAppURL, USER_WITH_ONE_ROLE, AUTHORIZATION_REALM_PASSWORD);
}
private void wrongUser(URL webAppURL) throws Exception {
assertAuthenticationFailed(webAppURL, WRONG_USER, CORRECT_PASSWORD);
}
private void userWithDifferentRoleInDifferentRealm(URL webAppURL) throws Exception {
testAssignedRoles(webAppURL, USER_WITH_DIFFERENT_ROLE_IN_DIFFERENT_REALM, CORRECT_PASSWORD, ROLE_ADMIN);
}
private void correctPassword_userOnlyInAuthzRealm(URL webAppURL) throws Exception {
testAssignedRoles(webAppURL, USER_ONLY_IN_AUTHORIZATION, CORRECT_PASSWORD, ROLE_USER);
}
private void wrongPassword_userOnlyInAuthzRealm(URL webAppURL) throws Exception {
assertAuthenticationFailed(webAppURL, USER_ONLY_IN_AUTHORIZATION, WRONG_PASSWORD);
}
private void emptyPassword_userOnlyInAuthzRealm(URL webAppURL) throws Exception {
assertAuthenticationFailed(webAppURL, USER_ONLY_IN_AUTHORIZATION, EMPTY_PASSWORD);
}
private void testAssignedRoles(URL webAppURL, String username, String password, String... assignedRoles) throws Exception {
final URL rolesPrintingURL = prepareRolesPrintingURL(webAppURL);
final String rolesResponse = Utils.makeCallWithBasicAuthn(rolesPrintingURL, username, password, SC_OK);
final List<String> assignedRolesList = Arrays.asList(assignedRoles);
for (String role : ALL_TESTED_ROLES) {
if (assignedRolesList.contains(role)) {
assertInRole(rolesResponse, role);
} else {
assertNotInRole(rolesResponse, role);
}
}
}
private void assertNoRoleAssigned(URL webAppURL, String username, String password) throws Exception {
final URL rolesPrintingURL = prepareRolesPrintingURL(webAppURL);
Utils.makeCallWithBasicAuthn(rolesPrintingURL, username, password, SC_FORBIDDEN);
}
private void assertAuthenticationFailed(URL webAppURL, String username, String password) throws Exception {
final URL rolesPrintingURL = prepareRolesPrintingURL(webAppURL);
Utils.makeCallWithBasicAuthn(rolesPrintingURL, username, password, SC_UNAUTHORIZED);
}
private URL prepareRolesPrintingURL(URL webAppURL) throws MalformedURLException {
return new URL(webAppURL.toExternalForm() + RolePrintingServlet.SERVLET_PATH.substring(1) + "?" + QUERY_ROLES);
}
private void assertInRole(final String rolePrintResponse, String role) {
if (!StringUtils.contains(rolePrintResponse, "," + role + ",")) {
fail("Missing role '" + role + "' assignment");
}
}
private void assertNotInRole(final String rolePrintResponse, String role) {
if (StringUtils.contains(rolePrintResponse, "," + role + ",")) {
fail("Unexpected role '" + role + "' assignment");
}
}
static class SetupTask implements ServerSetupTask {
private static final String PREDEFINED_HTTP_SERVER_MECHANISM_FACTORY = "global";
private static final String PROPERTIES_REALM_AUTHN_NAME = "elytron-authn-properties-realm";
private static final String PROPERTIES_REALM_AUTHZ_NAME = "elytron-authz-properties-realm";
private static final String FILESYSTEM_REALM_AUTHN_NAME = "elytron-authn-filesystem-realm";
private static final String USERS_AUTHN_REALM_FILENAME = "users-authn.properties";
private static final String ROLES_AUTHN_REALM_FILENAME = "roles-authn.properties";
private static final String USERS_AUTHZ_REALM_FILENAME = "users-authz.properties";
private static final String ROLES_AUTHZ_REALM_FILENAME = "roles-authz.properties";
private File usersAuthnRealmFile;
private File rolesAuthnRealmFile;
private File usersAuthzRealmFile;
private File rolesAuthzRealmFile;
private String fsRealmPath;
private File tempFolder;
@Override
public void setup(ManagementClient mc, String string) throws Exception {
tempFolder = createTemporaryFolder("ely-" + AggregateRealmTestCase.class.getSimpleName());
String tempFolderAbsolutePath = tempFolder.getAbsolutePath();
usersAuthnRealmFile = new File(tempFolderAbsolutePath, USERS_AUTHN_REALM_FILENAME);
rolesAuthnRealmFile = new File(tempFolderAbsolutePath, ROLES_AUTHN_REALM_FILENAME);
usersAuthzRealmFile = new File(tempFolderAbsolutePath, USERS_AUTHZ_REALM_FILENAME);
rolesAuthzRealmFile = new File(tempFolderAbsolutePath, ROLES_AUTHZ_REALM_FILENAME);
fsRealmPath = CliUtils.escapePath(tempFolderAbsolutePath + File.separator + "fs-realm-users");
createPropertiesFiles();
try (CLIWrapper cli = new CLIWrapper(true)) {
cli.sendLine(String.format(
"/subsystem=elytron/properties-realm=%s:add(users-properties={path=%s},groups-properties={path=%s})",
PROPERTIES_REALM_AUTHN_NAME, asAbsolutePath(usersAuthnRealmFile),
asAbsolutePath(rolesAuthnRealmFile)));
cli.sendLine(String.format(
"/subsystem=elytron/properties-realm=%s:add(users-properties={path=%s},groups-properties={path=%s})",
PROPERTIES_REALM_AUTHZ_NAME, asAbsolutePath(usersAuthzRealmFile),
asAbsolutePath(rolesAuthzRealmFile)));
cli.sendLine(String.format(
"/subsystem=elytron/filesystem-realm=%s:add(case-sensitive=true,path=%s)",
FILESYSTEM_REALM_AUTHN_NAME, fsRealmPath));
addUserToFilesystemRealm(cli, USER_WITHOUT_ROLE, CORRECT_PASSWORD);
addUserToFilesystemRealm(cli, USER_WITH_ONE_ROLE, CORRECT_PASSWORD);
addUserToFilesystemRealm(cli, USER_WITH_TWO_ROLES, CORRECT_PASSWORD);
addUserToFilesystemRealm(cli, USER_WITH_DIFFERENT_ROLE_IN_DIFFERENT_REALM, CORRECT_PASSWORD, ROLE_USER);
addUserToFilesystemRealm(cli, USER_ONLY_IN_AUTHORIZATION, CORRECT_PASSWORD);
addAggregateRealmAndRelatedResources(cli, AGGREGATE_REALM_SAME_TYPE_NAME, PROPERTIES_REALM_AUTHN_NAME,
PROPERTIES_REALM_AUTHZ_NAME);
addAggregateRealmAndRelatedResources(cli, AGGREGATE_REALM_DIFFERENT_TYPE_NAME, FILESYSTEM_REALM_AUTHN_NAME,
PROPERTIES_REALM_AUTHZ_NAME);
}
ServerReload.reloadIfRequired(mc.getControllerClient());
}
@Override
public void tearDown(ManagementClient mc, String string) throws Exception {
try (CLIWrapper cli = new CLIWrapper(true)) {
removeAggregateRealmAndRelatedResources(mc, cli, AGGREGATE_REALM_DIFFERENT_TYPE_NAME);
removeAggregateRealmAndRelatedResources(mc, cli, AGGREGATE_REALM_SAME_TYPE_NAME);
ServerReload.reloadIfRequired(mc.getControllerClient());
cli.sendLine(String.format("/subsystem=elytron/filesystem-realm=%s:remove()", FILESYSTEM_REALM_AUTHN_NAME));
cli.sendLine(String.format("/subsystem=elytron/properties-realm=%s:remove()", PROPERTIES_REALM_AUTHZ_NAME));
cli.sendLine(String.format("/subsystem=elytron/properties-realm=%s:remove()", PROPERTIES_REALM_AUTHN_NAME));
ServerReload.reloadIfRequired(mc.getControllerClient());
} finally {
removePropertiesFiles();
}
}
private void createPropertiesFiles() throws IOException {
createUsersProperties_authnRealm();
createRolesProperties_authnRealm();
createUsersProperties_authzRealm();
createRolesProperties_authzRealm();
}
private void createUsersProperties_authnRealm() throws IOException {
StringBuilder sb = new StringBuilder();
sb.append("#$REALM_NAME=" + PROPERTIES_REALM_AUTHN_NAME + "$\n");
sb.append(createPropertiesUserWithHashedPassword(USER_WITHOUT_ROLE, CORRECT_PASSWORD, PROPERTIES_REALM_AUTHN_NAME));
sb.append(createPropertiesUserWithHashedPassword(USER_WITH_ONE_ROLE, CORRECT_PASSWORD, PROPERTIES_REALM_AUTHN_NAME));
sb.append(createPropertiesUserWithHashedPassword(USER_WITH_TWO_ROLES, CORRECT_PASSWORD, PROPERTIES_REALM_AUTHN_NAME));
sb.append(createPropertiesUserWithHashedPassword(USER_WITH_DIFFERENT_ROLE_IN_DIFFERENT_REALM, CORRECT_PASSWORD, PROPERTIES_REALM_AUTHN_NAME));
sb.append(createPropertiesUserWithHashedPassword(USER_ONLY_IN_AUTHORIZATION, CORRECT_PASSWORD, PROPERTIES_REALM_AUTHN_NAME));
FileUtils.writeStringToFile(usersAuthnRealmFile, sb.toString(), CHARSET_UTF_8);
}
private void createRolesProperties_authnRealm() throws IOException {
StringBuilder sb = new StringBuilder();
sb.append(USER_WITH_DIFFERENT_ROLE_IN_DIFFERENT_REALM + "=" + ROLE_USER + "\n");
FileUtils.writeStringToFile(rolesAuthnRealmFile, sb.toString(), CHARSET_UTF_8);
}
private void createUsersProperties_authzRealm() throws IOException {
StringBuilder sb = new StringBuilder();
sb.append("#$REALM_NAME=" + PROPERTIES_REALM_AUTHZ_NAME + "$\n");
sb.append(createPropertiesUserWithHashedPassword(USER_WITHOUT_ROLE, AUTHORIZATION_REALM_PASSWORD, PROPERTIES_REALM_AUTHZ_NAME));
sb.append(createPropertiesUserWithHashedPassword(USER_WITH_ONE_ROLE, AUTHORIZATION_REALM_PASSWORD, PROPERTIES_REALM_AUTHZ_NAME));
sb.append(createPropertiesUserWithHashedPassword(USER_WITH_TWO_ROLES, AUTHORIZATION_REALM_PASSWORD, PROPERTIES_REALM_AUTHZ_NAME));
sb.append(createPropertiesUserWithHashedPassword(USER_WITH_DIFFERENT_ROLE_IN_DIFFERENT_REALM, AUTHORIZATION_REALM_PASSWORD, PROPERTIES_REALM_AUTHZ_NAME));
FileUtils.writeStringToFile(usersAuthzRealmFile, sb.toString(), CHARSET_UTF_8);
}
private void createRolesProperties_authzRealm() throws IOException {
StringBuilder sb = new StringBuilder();
sb.append(USER_WITH_ONE_ROLE + "=" + ROLE_USER + "\n");
sb.append(USER_WITH_TWO_ROLES + "=" + ROLE_USER + "," + ROLE_ADMIN + "\n");
sb.append(USER_WITH_DIFFERENT_ROLE_IN_DIFFERENT_REALM + "=" + ROLE_ADMIN + "\n");
sb.append(USER_ONLY_IN_AUTHORIZATION + "=" + ROLE_USER + "\n");
FileUtils.writeStringToFile(rolesAuthzRealmFile, sb.toString(), CHARSET_UTF_8);
}
private String createPropertiesUserWithHashedPassword(String username, String password, String realmName) {
return username + "=" + createHashedPassword(username, password, realmName) + "\n";
}
private String createHashedPassword(String username, String password, String realmName) {
String clearTextPassword = username + ":" + realmName + ":" + password;
String hashedPassword = CryptoUtil.createPasswordHash("MD5", "hex", null, null, clearTextPassword);
return hashedPassword;
}
private void removePropertiesFiles() throws IOException {
FileUtils.deleteQuietly(usersAuthnRealmFile);
FileUtils.deleteQuietly(rolesAuthnRealmFile);
FileUtils.deleteQuietly(usersAuthzRealmFile);
FileUtils.deleteQuietly(rolesAuthzRealmFile);
FileUtils.deleteDirectory(new File(fsRealmPath));
FileUtils.deleteDirectory(tempFolder);
}
private void addUserToFilesystemRealm(CLIWrapper cli, String username, String password) throws Exception {
addUserToFilesystemRealm(cli, username, password, null);
}
private void addUserToFilesystemRealm(CLIWrapper cli, String username, String password, String role)
throws Exception {
cli.sendLine(String.format("/subsystem=elytron/filesystem-realm=%s:add-identity(identity=%s)",
FILESYSTEM_REALM_AUTHN_NAME, username));
cli.sendLine(String.format("/subsystem=elytron/filesystem-realm=%s:set-password(identity=%s, clear={password=\"%s\"})",
FILESYSTEM_REALM_AUTHN_NAME, username, password));
if (role != null) {
cli.sendLine(String.format("/subsystem=elytron/filesystem-realm=%s:add-identity-attribute(identity=%s, name=Roles, value=[\"%s\"])",
FILESYSTEM_REALM_AUTHN_NAME, username, role));
}
}
private void addAggregateRealmAndRelatedResources(CLIWrapper cli, String name, String authnRealm, String authzRealm) {
cli.sendLine(String.format(
"/subsystem=elytron/aggregate-realm=%s:add(authentication-realm=%s,authorization-realm=%s)",
name, authnRealm, authzRealm));
cli.sendLine(String.format(
"/subsystem=elytron/security-domain=%1$s:add(realms=[{realm=%1$s,role-decoder=groups-to-roles}],default-realm=%1$s,permission-mapper=default-permission-mapper)",
name));
cli.sendLine(String.format(
"/subsystem=elytron/http-authentication-factory=%1$s:add(http-server-mechanism-factory=%2$s,security-domain=%1$s,"
+ "mechanism-configurations=[{mechanism-name=BASIC,mechanism-realm-configurations=[{realm-name=\"Some realm\"}]}])",
name, PREDEFINED_HTTP_SERVER_MECHANISM_FACTORY));
cli.sendLine(String.format(
"/subsystem=undertow/application-security-domain=%1$s:add(http-authentication-factory=%1$s)",
name));
}
private void removeAggregateRealmAndRelatedResources(ManagementClient mc, CLIWrapper cli, String name) throws Exception {
cli.sendLine(String.format("/subsystem=undertow/application-security-domain=%s:remove()", name));
cli.sendLine(String.format("/subsystem=elytron/http-authentication-factory=%s:remove()", name));
cli.sendLine(String.format("/subsystem=elytron/security-domain=%s:remove()", name));
cli.sendLine(String.format("/subsystem=elytron/aggregate-realm=%s:remove()", name));
}
}
}