/*
* JBoss, Home of Professional Open Source.
* Copyright 2015, 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.jboss.as.test.integration.domain.mixed;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.AUTHENTICATION;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CHILD_TYPE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PROFILE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_CHILDREN_NAMES_OPERATION;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_RESOURCE_OPERATION;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVER_GROUP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOCKET_BINDING_GROUP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SYSTEM_PROPERTY;
import static org.jboss.as.test.integration.domain.management.util.DomainTestUtils.executeForResult;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.client.helpers.domain.DomainClient;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.security.SecurityExtension;
import org.jboss.as.test.integration.domain.management.util.DomainTestUtils;
import org.jboss.as.test.integration.domain.mixed.eap620.DomainAdjuster620;
import org.jboss.as.test.integration.domain.mixed.eap630.DomainAdjuster630;
import org.jboss.as.test.integration.domain.mixed.eap640.DomainAdjuster640;
import org.jboss.as.test.integration.domain.mixed.eap700.DomainAdjuster700;
import org.jboss.dmr.ModelNode;
import org.junit.Assert;
/**
* Adjusts the domain configuration for the legacy server version.
* The default implementation trims down the domain model to only include the following
* profiles, socket-binding-groups and server-groups
* <uL>
* <li>{@code /profile=full-ha}</li>
* <li>{@code /socket-binding-group=full-ha-sockets}</li>
* <li>{@code /server-group=other-server-group}</li>
* <li>{@code /server-group=main-server-group}</li>
* </uL>
* Subclasses can then further execute operations to put the model in a state which can be transformed
* to a legacy version.
*
* @author <a href="mailto:kabir.khan@jboss.com">Kabir Khan</a>
*/
public class DomainAdjuster {
//We only want to test the full ha profile in these tests
private final String FULL_HA = "full-ha";
private final String MAIN_SERVER_GROUP = "main-server-group";
private final String OTHER_SERVER_GROUP = "other-server-group";
protected DomainAdjuster() {
}
static void adjustForVersion(final DomainClient client, final Version.AsVersion asVersion) throws Exception {
final DomainAdjuster adjuster;
switch (asVersion) {
case EAP_6_2_0:
adjuster = new DomainAdjuster620();
break;
case EAP_6_3_0:
adjuster = new DomainAdjuster630();
break;
case EAP_6_4_0:
adjuster = new DomainAdjuster640();
break;
case EAP_7_0_0:
adjuster = new DomainAdjuster700();
break;
default:
adjuster = new DomainAdjuster();
}
adjuster.adjust(client);
}
final void adjust(final DomainClient client) throws Exception {
//Trim it down so we have only
//profile=full-ha,
//the main-server-group and other-server-group
//socket-binding-group = full-ha-sockets
final List<String> allProfiles = getAllChildrenOfType(client, PathAddress.EMPTY_ADDRESS, PROFILE);
final ModelNode serverGroup = removeServerGroups(client);
for (String profileName : allProfiles) {
if (profileName.equals(FULL_HA)) {
continue;
}
removeProfile(client, profileName);
}
final String socketBindingGroup = serverGroup.get(SOCKET_BINDING_GROUP).asString();
removeUnusedSocketBindingGroups(client, socketBindingGroup);
removeIpv4SystemProperty(client);
// We don't want any standard host-excludes as the tests are meant to see what happens
// with the current configs on legacy slaves
removeHostExcludes(client);
//Add a jaspi test security domain used later by the tests
addJaspiTestSecurityDomain(client);
//Version specific changes
final List<ModelNode> adjustments = adjustForVersion(client, PathAddress.pathAddress(PROFILE, FULL_HA));
applyVersionAdjustments(client, adjustments);
}
private void removeIpv4SystemProperty(final DomainClient client) throws Exception {
//The standard domain configuration contains -Djava.net.preferIPv4Stack=true, remove that
DomainTestUtils.executeForResult(
Util.createRemoveOperation(PathAddress.pathAddress(SYSTEM_PROPERTY, "java.net.preferIPv4Stack")), client);
}
private void removeHostExcludes(DomainClient client) throws Exception {
final List<String> allHostExcludes = getAllChildrenOfType(client, PathAddress.EMPTY_ADDRESS, "host-exclude");
for (String exclude : allHostExcludes) {
DomainTestUtils.executeForResult(
Util.createRemoveOperation(PathAddress.pathAddress("host-exclude", exclude)), client);
}
}
protected List<ModelNode> adjustForVersion(final DomainClient client, final PathAddress profileAddress) throws Exception {
return Collections.emptyList();
}
private void removeProfile(final DomainClient client, final String name) throws Exception {
executeForResult(Util.createRemoveOperation(PathAddress.pathAddress(PROFILE, name)), client);
}
private List<String> getAllChildrenOfType(final DomainClient client,
final PathAddress parent, final String type) throws Exception {
final ModelNode op = Util.createEmptyOperation(READ_CHILDREN_NAMES_OPERATION, parent);
op.get(CHILD_TYPE).set(type);
final ModelNode result = executeForResult(op, client);
final List<String> childNames = new ArrayList<>();
for (ModelNode nameNode : result.asList()) {
childNames.add(nameNode.asString());
}
return childNames;
}
private ModelNode removeServerGroups(final DomainClient client) throws Exception {
final ModelNode op = Util.createEmptyOperation(READ_RESOURCE_OPERATION, PathAddress.pathAddress(PathElement.pathElement(SERVER_GROUP)));
final ModelNode results = executeForResult(op, client);
ModelNode group = null;
for (ModelNode result : results.asList()) {
String groupName = PathAddress.pathAddress(result.get(ADDRESS)).getLastElement().getValue();
if (groupName.equals(OTHER_SERVER_GROUP)) {
group = result.get(RESULT);
} else {
ModelNode remove = Util.createRemoveOperation(PathAddress.pathAddress(result.get(ADDRESS)));
executeForResult(remove, client);
}
}
Assert.assertNotNull(group);
//Add main-server-group as a copy of other-server-group (cuts down on the amount of profiles needed)
final ModelNode addMain = group.clone();
final PathAddress mainServerGroupAddress = PathAddress.pathAddress(SERVER_GROUP, MAIN_SERVER_GROUP);
addMain.get(OP).set(ADD);
addMain.get(OP_ADDR).set(mainServerGroupAddress.toModelNode());
executeForResult(addMain, client);
return group;
}
private void removeUnusedSocketBindingGroups(final DomainClient client, final String keepGroup) throws Exception {
final List<String> allGroups = getAllChildrenOfType(client, PathAddress.EMPTY_ADDRESS, SOCKET_BINDING_GROUP);
for (String groupName : allGroups) {
if (!keepGroup.equals(groupName)) {
ModelNode remove = Util.createRemoveOperation(PathAddress.pathAddress(PathAddress.pathAddress(SOCKET_BINDING_GROUP, groupName)));
executeForResult(remove, client);
}
}
}
private void addJaspiTestSecurityDomain(final DomainClient client) throws Exception {
//Before when this test was configured via xml, there was an extra security domain for testing jaspi.
final PathAddress domain = PathAddress.pathAddress(PROFILE, FULL_HA)
.append(SUBSYSTEM, SecurityExtension.SUBSYSTEM_NAME).append("security-domain", "jaspi-test");
DomainTestUtils.executeForResult(Util.createAddOperation(domain), client);
final PathAddress auth = domain.append(AUTHENTICATION, "jaspi");
DomainTestUtils.executeForResult(Util.createAddOperation(auth), client);
final PathAddress stack = auth.append("login-module-stack", "lm-stack");
DomainTestUtils.executeForResult(Util.createAddOperation(stack), client);
final ModelNode addLoginModule = Util.createAddOperation(stack.append("login-module", "lm"));
addLoginModule.get("code").set("UsersRoles");
addLoginModule.get("flag").set("required");
addLoginModule.get("module").set("test-jaspi");
final ModelNode options = addLoginModule.get("module-options");
options.setEmptyList();
options.add(new ModelNode().set("usersProperties", "${jboss.server.config.dir:}/application-users.properties"));
options.add(new ModelNode().set("rolesProperties", "${jboss.server.config.dir:}/application-roles.properties"));
DomainTestUtils.executeForResult(addLoginModule, client);
final ModelNode addAuthModule = Util.createAddOperation(auth.append("auth-module", getJaspiTestAuthModuleName()));
addAuthModule.get("code").set(getJaspiTestAuthModuleName());
addAuthModule.get("login-module-stack-ref").set("lm-stack");
addAuthModule.get("flag").set("${test.prop:optional}");
DomainTestUtils.executeForResult(addAuthModule, client);
}
/**
* Returns the class name of the http auth module. This uses the wildfly version. Adjusters for AS 7/EAP 6
* should override this method and return
* {@code org.wildfly.extension.undertow.security.jaspi.modules.HTTPSchemeServerAuthModule}
*
* @return the auth module
*/
protected String getJaspiTestAuthModuleName() {
return "org.wildfly.extension.undertow.security.jaspi.modules.HTTPSchemeServerAuthModule";
}
private void applyVersionAdjustments(DomainClient client, List<ModelNode> operations) throws Exception {
if (operations.size() == 0) {
return;
}
for (ModelNode op : operations) {
DomainTestUtils.executeForResult(op, client);
}
}
}