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(a)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(a)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 {