modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/JBossASClient.java | 1 modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/SecurityDomainJBossASClient.java | 121 +++++++--- modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml | 2 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CustomJaasDeploymentService.java | 55 ++-- 4 files changed, 131 insertions(+), 48 deletions(-)
New commits: commit 00ec08dead23cdf5fb8238d106f8561f93c33247 Author: Jay Shaughnessy jshaughn@redhat.com Date: Fri Dec 21 15:03:05 2012 -0500
In dev mode we try and run the installer automatically for the dev, if it hasn't been run already. We do this in the "background" so we use the same window (the /B option). Change it to suppress output (> nul) so it doesn't interfere with the actual server startup. And change it to suppress input (< nul) so it doesn't hang waiting for "Terminate Batch Job (Y/N)" when it completes.
diff --git a/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml b/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml index 0be2e6f..0c30da9 100644 --- a/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml +++ b/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml @@ -611,7 +611,7 @@ rhq.sync.endpoint-address=false <replace file="${project.build.outputDirectory}/bin/rhq-server.bat"> <replacefilter> <replacetoken>rem START SERVER</replacetoken> - <replacevalue><![CDATA[start /B %RHQ_SERVER_HOME%\bin\rhq-autoinstall.bat]]></replacevalue> + <replacevalue><![CDATA[start /B %RHQ_SERVER_HOME%\bin\rhq-autoinstall.bat < nul > nul]]></replacevalue> </replacefilter> </replace> </target>
commit 839b84fde562548edca1e4ac36324e5f0e0c0860 Author: Jay Shaughnessy jshaughn@redhat.com Date: Fri Dec 21 14:48:15 2012 -0500
LDAP support in RHQ-on-AS7 - fix up the client API to support: - removal/replacement of the existing security domain for RHQ logins - allow for multiple login-modules for a single security domain - fix up the CustomJaasDeploymentService to play with the new API to be able to add or remove the ldap support based on whether it is enabled.
diff --git a/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/JBossASClient.java b/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/JBossASClient.java index a4f47a0..343cc25 100644 --- a/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/JBossASClient.java +++ b/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/JBossASClient.java @@ -55,6 +55,7 @@ public class JBossASClient { public static final String READ_RESOURCE = "read-resource"; public static final String WRITE_ATTRIBUTE = "write-attribute"; public static final String ADD = "add"; + public static final String REMOVE = "remove"; public static final String SYSTEM_PROPERTY = "system-property"; public static final String PERSISTENT = "persistent"; // used by some operations to persist their effects public static final String REMOVE = "remove"; diff --git a/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/SecurityDomainJBossASClient.java b/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/SecurityDomainJBossASClient.java index 043e8f8..48aede8 100644 --- a/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/SecurityDomainJBossASClient.java +++ b/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/SecurityDomainJBossASClient.java @@ -20,6 +20,8 @@ package org.rhq.common.jbossas.client.controller;
import java.util.Map;
+import javax.security.auth.login.AppConfigurationEntry; + import org.jboss.as.controller.client.ModelControllerClient; import org.jboss.dmr.ModelNode;
@@ -148,45 +150,77 @@ public class SecurityDomainJBossASClient extends JBossASClient { }
/** - * Convenience method that builds a request which can create a new security domain - * using the database server authentication method. This is used when you want to directly - * authenticate against a db entry. + * Convenience method that removes a security domain by name. Useful when changing the characteristics of the + * login modules. * * @param securityDomainName the name of the new security domain - * @param loginModuleFQCN fully qualified class name to be set as the login-module "code". - * @param moduleOptionProperties map of propName->propValue mappings to to bet as module options + * @throws Exception if failed to remove the security domain + */ + public void removeSecurityDomainRequest(String securityDomainName) throws Exception { + + // If not there just return + if (!isSecurityDomain(securityDomainName)) { + return; + } + + final Address addr = Address.root().add(SUBSYSTEM, SUBSYSTEM_SECURITY, SECURITY_DOMAIN, securityDomainName); + ModelNode removeSecurityDomainNode = createRequest(REMOVE, addr); + + final ModelNode results = execute(removeSecurityDomainNode); + if (!isSuccess(results)) { + throw new FailureException(results, "Failed to remove security domain [" + securityDomainName + "]"); + } + + return; + } + + /** + * Convenience method that builds a request to create a new security domain including one or + * more login modules. The security domain will be replaced if it exists. + * + * @param securityDomainName the name of the new security domain + * @param loginModules an array of login modules to place in the security domain. They are ordered top-down in the + * same index order of the array. * @throws Exception if failed to create security domain */ - public void createNewCustomSecurityDomainRequest(String securityDomainName, String loginModuleFQCN, - Map<String, String> moduleOptionProperties) throws Exception { + public void createNewSecurityDomainRequest(String securityDomainName, LoginModuleRequest... loginModules) + throws Exception { + + if (isSecurityDomain(securityDomainName)) { + removeSecurityDomainRequest(securityDomainName); + }
Address addr = Address.root().add(SUBSYSTEM, SUBSYSTEM_SECURITY, SECURITY_DOMAIN, securityDomainName); - ModelNode addTopNode = null;
- // If necessary create the security domain, otherwise just add the loginModule - if (!isSecurityDomain(securityDomainName)) { - addTopNode = createRequest(ADD, addr); - addTopNode.get(CACHE_TYPE).set("default"); - } + ModelNode addTopNode = createRequest(ADD, addr); + addTopNode.get(CACHE_TYPE).set("default");
ModelNode addAuthNode = createRequest(ADD, addr.clone().add(AUTHENTICATION, CLASSIC)); ModelNode loginModulesNode = addAuthNode.get(LOGIN_MODULES); - ModelNode loginModule = new ModelNode(); - loginModule.get(CODE).set(loginModuleFQCN); - loginModule.get(FLAG).set("required"); - ModelNode moduleOptions = loginModule.get(MODULE_OPTIONS); - moduleOptions.setEmptyList();
- if (null != moduleOptionProperties) { - for (String key : moduleOptionProperties.keySet()) { - moduleOptions.add(key, moduleOptionProperties.get(key)); + ModelNode[] loginModuleNodes = new ModelNode[loginModules.length]; + + for (int i = 0, len = loginModules.length; i < len; ++i) { + ModelNode loginModule = new ModelNode(); + loginModule.get(CODE).set(loginModules[i].getLoginModuleFQCN()); + loginModule.get(FLAG).set(loginModules[i].getFlagString()); + ModelNode moduleOptions = loginModule.get(MODULE_OPTIONS); + moduleOptions.setEmptyList(); + + Map<String, String> moduleOptionProperties = loginModules[i].getModuleOptionProperties(); + if (null != moduleOptionProperties) { + for (String key : moduleOptionProperties.keySet()) { + String value = moduleOptionProperties.get(key); + if (null != value) { + moduleOptions.add(key, value); + } + } } - }
- loginModulesNode.add(loginModule); + loginModulesNode.add(loginModule); + }
- ModelNode batch = (null != addTopNode) ? createBatchRequest(addTopNode, addAuthNode) - : createBatchRequest(addAuthNode); + ModelNode batch = createBatchRequest(addTopNode, addAuthNode); ModelNode results = execute(batch); if (!isSuccess(results)) { throw new FailureException(results, "Failed to create security domain [" + securityDomainName + "]"); @@ -195,4 +229,41 @@ public class SecurityDomainJBossASClient extends JBossASClient { return; }
+ /** Immutable helper */ + public static class LoginModuleRequest { + private AppConfigurationEntry entry; + + /** + * @param loginModuleFQCN fully qualified class name to be set as the login-module "code". + * @param flag constant, one of required|requisite|sufficient|optional + * @param moduleOptionProperties map of propName->propValue mappings to to bet as module options + */ + public LoginModuleRequest(String loginModuleFQCN, AppConfigurationEntry.LoginModuleControlFlag flag, + Map<String, String> moduleOptionProperties) { + + this.entry = new AppConfigurationEntry(loginModuleFQCN, flag, moduleOptionProperties); + } + + public String getLoginModuleFQCN() { + return entry.getLoginModuleName(); + } + + public AppConfigurationEntry.LoginModuleControlFlag getFlag() { + return entry.getControlFlag(); + } + + public String getFlagString() { + return entry.getControlFlag().toString().split(" ")[1]; + } + + public Map<String, String> getModuleOptionProperties() { + return (Map<String, String>) entry.getOptions(); + } + + @Override + public String toString() { + return "LoginModuleRequest [loginModuleFQCN=" + getLoginModuleFQCN() + ", flag=" + getFlag() + + ", moduleOptionProperties=" + getModuleOptionProperties() + "]"; + } + } } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CustomJaasDeploymentService.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CustomJaasDeploymentService.java index ddd0815..582de5e 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CustomJaasDeploymentService.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CustomJaasDeploymentService.java @@ -18,7 +18,9 @@ */ package org.rhq.enterprise.server.core;
+import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Properties;
@@ -29,6 +31,7 @@ import javax.naming.AuthenticationException; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.ldap.InitialLdapContext; +import javax.security.auth.login.AppConfigurationEntry;
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -36,6 +39,7 @@ import org.apache.commons.logging.LogFactory; import org.jboss.as.controller.client.ModelControllerClient;
import org.rhq.common.jbossas.client.controller.SecurityDomainJBossASClient; +import org.rhq.common.jbossas.client.controller.SecurityDomainJBossASClient.LoginModuleRequest; import org.rhq.core.domain.common.composite.SystemSetting; import org.rhq.enterprise.server.RHQConstants; import org.rhq.enterprise.server.core.jaas.JDBCLoginModule; @@ -101,26 +105,30 @@ public class CustomJaasDeploymentService implements CustomJaasDeploymentServiceM public void postDeregister() { }
+ /** + * Will register the necessary JAAS login Modules. The RHQ_USER_SECURITY_DOMAIN will be created, or recreated + * if it already exists. This allows us to add/remove ldap support as it is enabled or disabled. + * + * @param systemConfig + * @throws Exception + */ private void registerJaasModules(Properties systemConfig) throws Exception {
ModelControllerClient mcc = null; try { mcc = ManagementService.getClient(); final SecurityDomainJBossASClient client = new SecurityDomainJBossASClient(mcc); - final String securityDomain = RHQ_USER_SECURITY_DOMAIN;
- if (client.isSecurityDomain(securityDomain)) { - log.info("Security domain [" + securityDomain + "] already exists, skipping the creation request"); - return; + if (client.isSecurityDomain(RHQ_USER_SECURITY_DOMAIN)) { + log.info("Security domain [" + RHQ_USER_SECURITY_DOMAIN + "] already exists, it will be replaced."); }
- // Always register the RHQ user JDBC login module, this checks the pricipal against the RHQ DB - Map<String, String> moduleOptionProperties = getJdbcOptions(systemConfig); - String code = JDBCLoginModule.class.getName(); + List<LoginModuleRequest> loginModules = new ArrayList<LoginModuleRequest>(3);
- client.createNewCustomSecurityDomainRequest(securityDomain, code, moduleOptionProperties); - log.info("Security domain [" + securityDomain + "] created"); - log.info("Security domain login module [" + securityDomain + ":" + code + "] created"); + // Always register the RHQ user JDBC login module, this checks the principal against the RHQ DB + LoginModuleRequest jdbcLoginModule = new LoginModuleRequest(JDBCLoginModule.class.getName(), + AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT, getJdbcOptions(systemConfig)); + loginModules.add(jdbcLoginModule);
// Optionally register two more login modules for LDAP support. The first ensures // we don't have a DB principal (if we do then the JDBC login module is sufficient. @@ -130,16 +138,15 @@ public class CustomJaasDeploymentService implements CustomJaasDeploymentServiceM
if (isLdapAuthenticationEnabled) { // this is a "gatekeeper" that only allows us to go to LDAP if there is no principal in the DB - moduleOptionProperties = getJdbcOptions(systemConfig); - code = JDBCPrincipalCheckLoginModule.class.getName(); - - client.createNewCustomSecurityDomainRequest(securityDomain, code, moduleOptionProperties); - log.info("Security domain login module [" + securityDomain + ":" + code + "] created"); + LoginModuleRequest jdbcPrincipalCheckLoginModule = new LoginModuleRequest( + JDBCPrincipalCheckLoginModule.class.getName(), + AppConfigurationEntry.LoginModuleControlFlag.REQUISITE, getJdbcOptions(systemConfig)); + loginModules.add(jdbcPrincipalCheckLoginModule);
- // this is the LDAP module that checks the LDAP for auth - moduleOptionProperties = getLdapOptions(systemConfig); + // this is the LDAP module that checks the LDAP for auth + Map<String, String> ldapModuleOptionProperties = getLdapOptions(systemConfig); try { - validateLdapOptions(moduleOptionProperties); + validateLdapOptions(ldapModuleOptionProperties);
} catch (NamingException e) { String descriptiveMessage = null; @@ -155,11 +162,15 @@ public class CustomJaasDeploymentService implements CustomJaasDeploymentServiceM }
// Enable the login module even if the LDAP properties have issues - code = LdapLoginModule.class.getName(); - - client.createNewCustomSecurityDomainRequest(securityDomain, code, moduleOptionProperties); - log.info("Security domain login module [" + securityDomain + ":" + code + "] created"); + LoginModuleRequest ldapLoginModule = new LoginModuleRequest(LdapLoginModule.class.getName(), + AppConfigurationEntry.LoginModuleControlFlag.REQUISITE, ldapModuleOptionProperties); + loginModules.add(ldapLoginModule); } + + client.createNewSecurityDomainRequest(RHQ_USER_SECURITY_DOMAIN, + loginModules.toArray(new LoginModuleRequest[loginModules.size()])); + log.info("Security domain [" + RHQ_USER_SECURITY_DOMAIN + "] created with login modules " + loginModules); + } catch (Exception e) { throw new Exception("Error registering RHQ JAAS modules", e); } finally {
rhq-commits@lists.fedorahosted.org