modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java | 119 ++++++---- modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/i18n/AgentI18NResourceKeys.java | 9 modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ViewAgentUIBean.java | 8 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java | 41 +-- modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java | 108 ++++++++- 5 files changed, 217 insertions(+), 68 deletions(-)
New commits: commit 7a155eadc7989be7de1a26fd135ad461660b0959 Author: John Mazzitelli mazz@redhat.com Date: Wed Jan 18 17:19:58 2012 -0500
[BZ 782612][BZ 772318] the agent registration now requires a token. null tokens are rejected unless its a new agent.
diff --git a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java index 5359c3c..c7e0cfc 100644 --- a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java +++ b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java @@ -751,8 +751,8 @@ public class AgentMain { try { shutdownPluginContainer(); } catch (Throwable ignore) { - LOG.warn(AgentI18NResourceKeys.FAILED_TO_SHUTDOWN_COMPONENT, "Plugin Container", ThrowableUtil - .getAllMessages(ignore)); + LOG.warn(AgentI18NResourceKeys.FAILED_TO_SHUTDOWN_COMPONENT, "Plugin Container", + ThrowableUtil.getAllMessages(ignore)); }
/////// @@ -984,8 +984,8 @@ public class AgentMain { LOG.debug(AgentI18NResourceKeys.FAILOVER_LIST_LOADED, failoverListFile, list.size()); } catch (Exception e) { list = new FailoverListComposite(new ArrayList<ServerEntry>()); - LOG.warn(e, AgentI18NResourceKeys.FAILOVER_LIST_CANNOT_BE_LOADED, failoverListFile, ThrowableUtil - .getAllMessages(e)); + LOG.warn(e, AgentI18NResourceKeys.FAILOVER_LIST_CANNOT_BE_LOADED, failoverListFile, + ThrowableUtil.getAllMessages(e)); } }
@@ -1191,8 +1191,10 @@ public class AgentMain { // store is the default value. // But first we need to backup these original preferences in case the config file fails to load - // we'll restore the original values in that case. - + // Note that we squirrel away any security token we already have - we need to preserve this when we can + // because otherwise the agent will not be able to re-register with any previous name is was registered with. Preferences preferencesNode = getPreferencesNode(); + String securityToken = preferencesNode.get(AgentConfigurationConstants.AGENT_SECURITY_TOKEN, null); ByteArrayOutputStream backup = new ByteArrayOutputStream(); preferencesNode.exportSubtree(backup); preferencesNode.clear(); @@ -1213,10 +1215,26 @@ public class AgentMain { ByteArrayInputStream new_config_input_stream = new ByteArrayInputStream(new_config.getBytes()); Preferences.importPreferences(new_config_input_stream);
- if (new AgentConfiguration(preferencesNode).getAgentConfigurationVersion() == 0) { + AgentConfiguration newAgentConfig = new AgentConfiguration(preferencesNode); + if (newAgentConfig.getAgentConfigurationVersion() == 0) { throw new IllegalArgumentException(MSG.getMsg(AgentI18NResourceKeys.BAD_NODE_NAME_IN_CONFIG_FILE, file_name, m_agentPreferencesNodeName)); } + + // If we had a security token, restore it so we can maintain our known registration with the server. + // Note that if the configuration file already had a security token defined, it will be used and the old + // token we had will be thrown away. + if (securityToken != null) { + if (newAgentConfig.getAgentSecurityToken() == null) { + LOG.debug(AgentI18NResourceKeys.RESTORING_SECURITY_TOKEN); + newAgentConfig.setAgentSecurityToken(securityToken); + } else { + LOG.info(AgentI18NResourceKeys.NOT_RESTORING_SECURITY_TOKEN); + } + } + + preferencesNode.flush(); + } catch (Exception e) { // a problem occurred importing the config file; let's restore our original values try { @@ -2297,8 +2315,8 @@ public class AgentMain { */ private void prepareAutoDiscoveryListener() throws Exception { if (m_configuration.isServerAutoDetectionEnabled()) { - ServiceContainerConfiguration comm_config = new ServiceContainerConfiguration(m_configuration - .getPreferences()); + ServiceContainerConfiguration comm_config = new ServiceContainerConfiguration( + m_configuration.getPreferences()); if (comm_config.isMulticastDetectorEnabled()) { m_autoDiscoveryListener = new AgentAutoDiscoveryListener(this, createServerRemoteCommunicator(null, false, false)); @@ -2469,8 +2487,8 @@ public class AgentMain { if (wait > 0) { long now = System.currentTimeMillis(); if ((started + wait) < now) { - throw new RuntimeException(MSG - .getMsg(AgentI18NResourceKeys.CANNOT_WAIT_TO_BE_REGISTERED_ANY_LONGER)); + throw new RuntimeException( + MSG.getMsg(AgentI18NResourceKeys.CANNOT_WAIT_TO_BE_REGISTERED_ANY_LONGER)); } }
@@ -2570,27 +2588,27 @@ public class AgentMain { Map<String, String> config = new HashMap<String, String>();
if (SecurityUtil.isTransportSecure(uri)) { - config.put(SSLSocketBuilder.REMOTING_KEY_STORE_FILE_PATH, m_configuration - .getClientSenderSecurityKeystoreFile()); - config.put(SSLSocketBuilder.REMOTING_KEY_STORE_ALGORITHM, m_configuration - .getClientSenderSecurityKeystoreAlgorithm()); + config.put(SSLSocketBuilder.REMOTING_KEY_STORE_FILE_PATH, + m_configuration.getClientSenderSecurityKeystoreFile()); + config.put(SSLSocketBuilder.REMOTING_KEY_STORE_ALGORITHM, + m_configuration.getClientSenderSecurityKeystoreAlgorithm()); config.put(SSLSocketBuilder.REMOTING_KEY_STORE_TYPE, m_configuration.getClientSenderSecurityKeystoreType()); - config.put(SSLSocketBuilder.REMOTING_KEY_STORE_PASSWORD, m_configuration - .getClientSenderSecurityKeystorePassword()); - config.put(SSLSocketBuilder.REMOTING_KEY_PASSWORD, m_configuration - .getClientSenderSecurityKeystoreKeyPassword()); - config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_FILE_PATH, m_configuration - .getClientSenderSecurityTruststoreFile()); - config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_ALGORITHM, m_configuration - .getClientSenderSecurityTruststoreAlgorithm()); - config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_TYPE, m_configuration - .getClientSenderSecurityTruststoreType()); - config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_PASSWORD, m_configuration - .getClientSenderSecurityTruststorePassword()); + config.put(SSLSocketBuilder.REMOTING_KEY_STORE_PASSWORD, + m_configuration.getClientSenderSecurityKeystorePassword()); + config.put(SSLSocketBuilder.REMOTING_KEY_PASSWORD, + m_configuration.getClientSenderSecurityKeystoreKeyPassword()); + config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_FILE_PATH, + m_configuration.getClientSenderSecurityTruststoreFile()); + config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_ALGORITHM, + m_configuration.getClientSenderSecurityTruststoreAlgorithm()); + config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_TYPE, + m_configuration.getClientSenderSecurityTruststoreType()); + config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_PASSWORD, + m_configuration.getClientSenderSecurityTruststorePassword()); config.put(SSLSocketBuilder.REMOTING_SSL_PROTOCOL, m_configuration.getClientSenderSecuritySocketProtocol()); config.put(SSLSocketBuilder.REMOTING_KEY_ALIAS, m_configuration.getClientSenderSecurityKeystoreAlias()); - config.put(SSLSocketBuilder.REMOTING_SERVER_AUTH_MODE, Boolean.toString(m_configuration - .isClientSenderSecurityServerAuthMode())); + config.put(SSLSocketBuilder.REMOTING_SERVER_AUTH_MODE, + Boolean.toString(m_configuration.isClientSenderSecurityServerAuthMode())); config.put(SSLSocketBuilder.REMOTING_SOCKET_USE_CLIENT_MODE, "true");
// since we do not know the server's client-auth mode, assume we need a keystore and let's make sure we have one @@ -2600,10 +2618,10 @@ public class AgentMain { dummy_sslbuilder.setKeyStoreURL(m_configuration.getClientSenderSecurityKeystoreFile()); } catch (Exception e) { // this probably is due to the fact that the keystore doesn't exist yet - let's prepare one now - SecurityUtil.createKeyStore(m_configuration.getClientSenderSecurityKeystoreFile(), m_configuration - .getClientSenderSecurityKeystoreAlias(), "CN=RHQ, OU=RedHat, O=redhat.com, C=US", m_configuration - .getClientSenderSecurityKeystorePassword(), m_configuration - .getClientSenderSecurityKeystoreKeyPassword(), "DSA", 36500); + SecurityUtil.createKeyStore(m_configuration.getClientSenderSecurityKeystoreFile(), + m_configuration.getClientSenderSecurityKeystoreAlias(), "CN=RHQ, OU=RedHat, O=redhat.com, C=US", + m_configuration.getClientSenderSecurityKeystorePassword(), + m_configuration.getClientSenderSecurityKeystoreKeyPassword(), "DSA", 36500);
// now try to set it again, if an exception is still thrown, it's an unrecoverable error dummy_sslbuilder.setKeyStoreURL(m_configuration.getClientSenderSecurityKeystoreFile()); @@ -2702,8 +2720,8 @@ public class AgentMain { StreamUtil.copy(byteStream, fileStream, true); LOG.debug(AgentI18NResourceKeys.FAILOVER_LIST_PERSISTED, failoverListFile); } catch (Exception e) { - LOG.warn(e, AgentI18NResourceKeys.FAILOVER_LIST_CANNOT_BE_PERSISTED, failoverListFile, ThrowableUtil - .getAllMessages(e)); + LOG.warn(e, AgentI18NResourceKeys.FAILOVER_LIST_CANNOT_BE_PERSISTED, failoverListFile, + ThrowableUtil.getAllMessages(e)); }
// let's be kind to the user - if any server address is "localhost" or "127.0.0.#" @@ -2773,8 +2791,8 @@ public class AgentMain { break; } } catch (Throwable t) { - m_output.println(MSG.getMsg(AgentI18NResourceKeys.COMMAND_FAILURE, cmd, ThrowableUtil - .getAllMessages(t))); + m_output.println(MSG.getMsg(AgentI18NResourceKeys.COMMAND_FAILURE, cmd, + ThrowableUtil.getAllMessages(t))); LOG.debug(t, AgentI18NResourceKeys.COMMAND_FAILURE_STACK_TRACE); } } @@ -2890,7 +2908,7 @@ public class AgentMain { * @throws HelpException if help was requested and the agent should not be created */ private void processArguments(String[] args) throws Exception { - String sopts = "-:hdlasntguD:i:o:c:p:e:"; + String sopts = "-:hdlLasntguD:i:o:c:p:e:"; LongOpt[] lopts = { new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h'), new LongOpt("input", LongOpt.REQUIRED_ARGUMENT, null, 'i'), new LongOpt("output", LongOpt.REQUIRED_ARGUMENT, null, 'o'), @@ -2899,6 +2917,7 @@ public class AgentMain { new LongOpt("console", LongOpt.REQUIRED_ARGUMENT, null, 'e'), new LongOpt("daemon", LongOpt.NO_ARGUMENT, null, 'd'), new LongOpt("cleanconfig", LongOpt.NO_ARGUMENT, null, 'l'), + new LongOpt("cleanallconfig", LongOpt.NO_ARGUMENT, null, 'L'), new LongOpt("advanced", LongOpt.NO_ARGUMENT, null, 'a'), new LongOpt("setup", LongOpt.NO_ARGUMENT, null, 's'), new LongOpt("nostart", LongOpt.NO_ARGUMENT, null, 'n'), @@ -2908,6 +2927,7 @@ public class AgentMain {
String config_file_name = null; boolean clean_config = false; + boolean clean_token = false; // only used if clean_config = true boolean purge_data = false; boolean purge_plugins = false; AgentInputReaderFactory.ConsoleType console_type = null; @@ -2967,6 +2987,13 @@ public class AgentMain { break; }
+ case 'L': { + clean_config = true; + purge_data = true; + clean_token = true; + break; + } + case 'u': { purge_data = true; break; @@ -3051,7 +3078,21 @@ public class AgentMain {
// now that all the arguments were processed, let's load in our config (this allows the -p to come after -c) if (clean_config) { - getPreferencesNode().removeNode(); + Preferences prefsNode = getPreferencesNode(); + if (clean_token) { + prefsNode.removeNode(); + } else { + // remove everything EXCEPT the security token + String[] prefKeys = prefsNode.keys(); + if (prefKeys != null && prefKeys.length > 0) { + for (String prefKey : prefKeys) { + if (!prefKey.equals(AgentConfigurationConstants.AGENT_SECURITY_TOKEN)) { + prefsNode.remove(prefKey); + } + } + } + } + prefsNode.flush(); }
if (config_file_name != null) { @@ -3260,6 +3301,8 @@ public class AgentMain { preferencesNode.put(ServiceContainerConfigurationConstants.DATA_DIRECTORY, data_dir); }
+ prefs.flush(); + LOG.debug(AgentI18NResourceKeys.CONFIGURATION, agent_configuration);
return; diff --git a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/i18n/AgentI18NResourceKeys.java b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/i18n/AgentI18NResourceKeys.java index 59702fc..0b41bb7 100644 --- a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/i18n/AgentI18NResourceKeys.java +++ b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/i18n/AgentI18NResourceKeys.java @@ -613,7 +613,8 @@ public interface AgentI18NResourceKeys { + "\ -g, --purgeplugins Deletes all plugins, forcing the agent to re-download all of them\n\\n" + "\ -h, --help Shows this help message (default)\n\\n" + "\ -i, --input=<filename> Specifies a script file to be used for input\n\\n" - + "\ -l, --cleanconfig Clears out any existing configuration and data files so the agent starts with a totally clean slate\n\\n" + + "\ -l, --cleanconfig Clears out existing configuration and data files, except for the security token.\n\\n" + + "\ -L, --cleanallconfig Clears out all existing configuration and data files so the agent starts with a totally clean slate\n\\n" + "\ -n, --nostart If specified, the agent will not be automatically started\n\\n" + "\ -o, --output=<filename> Specifies a file to write all output (excluding log messages)\n\\n" + "\ -p, --pref=<preferences name> Specifies the agent preferences name used to identify what configuration to use\n\\n" @@ -2104,4 +2105,10 @@ public interface AgentI18NResourceKeys {
@I18NMessage("Restarting the plugin container due to previous failure to merge the upgrade results with the server.") String RESTARTING_PLUGIN_CONTAINER_AFTER_UPGRADE_MERGE_FAILURE = "AgentMain.pc-conditional-restart"; + + @I18NMessage("Restoring the original security token.") + String RESTORING_SECURITY_TOKEN = "AgentMain.restoring-security-token"; + + @I18NMessage("The config file already has a security token defined. The original security token will be thrown away.") + String NOT_RESTORING_SECURITY_TOKEN = "AgentMain.not-restoring-security-token"; } \ No newline at end of file diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ViewAgentUIBean.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ViewAgentUIBean.java index fd2286c..90d7042 100644 --- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ViewAgentUIBean.java +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ViewAgentUIBean.java @@ -56,6 +56,9 @@ public class ViewAgentUIBean extends PagedDataTableUIBean { hasPermission(); int agentId = FacesContextUtility.getRequiredRequestParameter("agentId", Integer.class); agent = agentManager.getAgentByID(agentId); + if (!hasPermissionToViewSecurityToken()) { + agent.setAgentToken("******"); + } } return agent; } @@ -94,4 +97,9 @@ public class ViewAgentUIBean extends PagedDataTableUIBean { + "] does not have the proper permissions to view or manage agents"); } } + + private boolean hasPermissionToViewSecurityToken() { + Subject subject = EnterpriseFacesContextUtility.getSubject(); + return LookupUtil.getAuthorizationManager().hasGlobalPermission(subject, Permission.MANAGE_SECURITY); + } } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java index e380b6e..75c4d65 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java @@ -104,14 +104,10 @@ public class CoreServerServiceImpl implements CoreServerService { * something else". * * If there is no original token with the request, this is either a brand new agent never before registered, or it - * is an agent that has been registered before but for some reason lost its token. In this case, we will look at - * this registration's host/port of this new agent. If it matches the host/port of another agent but the - * existing name and the new agent's name don't match, the server will abort and tell the agent, "You don't know - * who you are, but I know there is already an agent with the host and port you are trying to register with - * under a different name - so I'm going to trust this original agent and not allow you to register that name - * under a different host/port. If you are that original agent, then you need to register with that original - * name". When the agent registers again, this time with the correct name, the agent will be given its token. - * This usually will occur if you reinstall the agent and try to register it under a different name. + * is an agent that has been registered before but for some reason lost its token. + * In this case, if there is no agent with the name being requested, we register this as a new agent. + * If, however, the agent name is already in use, we abort the request. An agent cannot register with an + * existing agent without sending that agent's security token. */
if (request.getOriginalToken() != null) { @@ -140,19 +136,24 @@ public class CoreServerServiceImpl implements CoreServerService { // the agent request provided a name that already is in use by an agent. However, the request // provided a security token that was not assigned to any agent! How can this be? Something is fishy. String msg = "The agent asking for registration under the name [" + request.getName() - + "] provided an invalid security token. This request will fail."; + + "] provided an invalid security token. This request will fail. " + + "Please consult an administrator to reconfigure this agent with its proper security token."; throw new AgentRegistrationException(msg); } Agent agentByAddressPort = getAgentManager().getAgentByAddressAndPort(request.getAddress(), request.getPort()); if (agentByAddressPort != null) { - // the agent request provided a security token but it is an unknown/unused/bogus token. + // The agent is requesting to register an unused agent name - so this is considered a new agent. + // It provided a security token but it is an unknown/obsolete/bogus token (usually due to the + // fact that someone purged the platform/agent from the server database but the old agent is + // still around with its old token). // However, the IP/port it wants to use is already in-use. This sounds fishy. If we let this // go through, this agent with an unknown/bogus token will essentially hijack this IP/port // belonging to an existing agent. If the agent wants to reuse an IP/port already in existence, it should // already know its security token associated with that IP/port. Thus, we will abort this request. String msg = "The agent asking for registration under the name [" + request.getName() - + "] is attempting to authenticate using an unknown security token. This request will fail."; + + "] is attempting to take another agent's address/port [" + request.getAddress() + ":" + + request.getPort() + "] with an unknown security token. This request will fail."; throw new AgentRegistrationException(msg); } } @@ -167,23 +168,25 @@ public class CoreServerServiceImpl implements CoreServerService { + request.getPort() + "] that is already registered under a different name [" + agentByAddressPort.getName() - + "]; if this new agent is actually the same as the original, then re-register with the same name"; + + "]; if this new agent is actually the same as the original, then re-register with the same name" + + " and same security token."; throw new AgentRegistrationException(msg); + } else { + String msg = "The agent [" + request.getName() + + "] is attempting to re-register without a security token. " + + "Please consult an administrator to reconfigure this agent with its proper security token."; + throw new AgentRegistrationException(msg); + } } else { if (agentByName != null) { - // the name being registered already exists, however, the agent request is trying to set it - // to some unknown IP/port combination and there is no security token to authenticate this request! + // the name being registered already exists - but there is no security token to authenticate this request! // Therefore, because this agent name is already registered and because this current request // cannot authenticate itself with the proper security token, we fail. String msg = "An agent is trying to register with an existing agent name [" + request.getName() - + "]. The registration request is attempting to assign the agent an unknown address/port [" - + request.getAddress() - + ":" - + request.getPort() + "] without providing a valid security token. If you are attempting to re-register this agent, " - + "make sure you register with its prior address/port."; + + "please consult an administrator to reconfigure this agent with its proper security token."; throw new AgentRegistrationException(msg); } } diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java index a3dda5e..5a702ff 100644 --- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java @@ -41,12 +41,57 @@ import org.rhq.core.domain.cloud.Server; import org.rhq.core.domain.cloud.Server.OperationMode; import org.rhq.core.domain.common.ProductInfo; import org.rhq.core.domain.resource.Agent; +import org.rhq.core.util.exception.ThrowableUtil; import org.rhq.enterprise.server.test.AbstractEJB3Test; import org.rhq.enterprise.server.util.LookupUtil;
/** + * This tests the core server service. This includes agent registration. + * * @author John Mazzitelli */ + +// These are the agent registration unit test cases. +// (allowed) means the registration should succeed. +// (REJECT) means the server should reject that agent registration request. +// --- +// A. testNewAgentRegistrationWithOldToken +// 1) register a new agent with a non-null, unknown security token (allowed) +// B. testChangeAddressPort +// 1) register a new agent Z with null security token (allowed) +// 2) re-register agent Z with its token but change its host (allowed) +// 3) re-register agent Z with its token but change its port (allowed) +// 4) re-register agent Z with its token but change its host and port (allowed) +// 5) re-register agent Z with its token but change nothing (allowed) +// 6) re-register agent Z with NO token but change its host (REJECT) +// 7) re-register agent Z with NO token but change its port (REJECT) +// 8) re-register agent Z with NO token but change its host and port (REJECT) +// 9) re-register agent Z with NO token but change nothing (REJECT) +// C. testNormalAgentRegistration +// 1) register a new agent A with a null security token (allowed, same as B.1) +// D. testHijackExistingAgentAddressPort +// 1) register a new agent B with null security token but using A's host/port (REJECT) +// E. testHijackExistingAgentName +// 1) register an agent using an already-existing agent name A, and using A's host but a different port with a null token (REJECT - missing the token) +// 2) register an agent using an already-existing agent name A, and using A's port but a different host with a null token (REJECT - missing the token) +// 3) register an agent using an already-existing agent name A, and using a different port and host with a null token (REJECT - missing the token) +// F. testHijackExistingAgentAddressPortWithBogusToken +// 1) register a new agent B with A's host and port but with a bogus token (REJECT) +// G. testHijackExistingAgentNameWithBogusToken +// 1) re-register agent A with its original host and port but with a bogus token (REJECT) +// 2) re-register agent A with its original host, different port but with bogus token (REJECT) +// 3) re-register agent A with different host, original port but with bogus token (REJECT) +// 4) re-register agent A with different host and port but with bogus token (REJECT) +// H. testHijackExistingAgentNameWithAnotherAgentToken +// 1) re-register agent A with its original host and port but with Z's security token (REJECT - you cannot authenticate using another agent's token) +// 2) re-register agent A with different host and original port but with Z's security token (REJECT - you cannot authenticate using another agent's token) +// 3) re-register agent A with original host and different port but with Z's security token (REJECT - you cannot authenticate using another agent's token) +// 4) re-register agent A with different host and port but with Z's security token (REJECT - you cannot authenticate using another agent's token) +// I. testAgentHijackingAnotherAgentAddressPort +// 1) re-register agent A using A's correct security token but with Z's host and Z's port (REJECT - one agent cannot steal another agent's host/port endpoint) NOTE: this is not D.1 because in D.1, the request doesn't have a token. This I.1 test has a token and it really authenticates the agent A making the request. This also isn't F.1 because F.1, while it has a token, it is not a valid token, thus its agent is not authentic. +// J. testAttemptToChangeAgentName +// 1) register agent "newName" but with Z's host/port/token. In effect, this is trying to change the agent's name. (REJECT - you are not allowed to rename agents) + @Test public class CoreServerServiceImplTest extends AbstractEJB3Test { private static final String TEST_AGENT_NAME_PREFIX = "CoreServerServiceImplTest.Agent"; @@ -67,7 +112,7 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test { public void testNewAgentRegistrationWithOldToken() throws Exception { // this tests the case where someone purged an agent from the DB, but then // changed their mind and want to re-run that agent and re-register it again. - // In this case, the agent (if not using --cleanconfig) would still have the old token. + // In this case, the agent (if not using --cleanallconfig) would still have the old token. // The agent should still be allowed to register again. CoreServerServiceImpl service = new CoreServerServiceImpl(); AgentRegistrationRequest request = createRequest(prefixName("old"), "hostOld", 12345, "oldtoken"); @@ -128,18 +173,40 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test { assert agent.getAddress().equals("hostZdoubleprime"); assert agent.getPort() == 55552;
- // now don't change Z's host/port but re-register everything the same, but with no token - request = createRequest(zName, "hostZdoubleprime", 55552, null); - results = service.registerAgent(request); - assert results != null; - agent = LookupUtil.getAgentManager().getAgentByAgentToken(results.getAgentToken()); - assert agent.getName().equals(zName); - assert agent.getAddress().equals("hostZdoubleprime"); - assert agent.getPort() == 55552; - // remember this agent so our later tests can use it zReq = request; zResults = results; + + // Try to re-register changes to host and/or port but do not send any token. + // Because there is no token, these should fail. + request = createRequest(zName, B_HOST, zReq.getPort(), null); + try { + service.registerAgent(request); + assert false : "(1) Should not have been able to register without a token"; + } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); + } + request = createRequest(zName, zReq.getAddress(), B_PORT, null); + try { + service.registerAgent(request); + assert false : "(2) Should not have been able to register without a token"; + } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); + } + request = createRequest(zName, B_HOST, B_PORT, null); + try { + service.registerAgent(request); + assert false : "(3) Should not have been able to register without a token"; + } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); + } + request = createRequest(zName, zReq.getAddress(), zReq.getPort(), null); + try { + service.registerAgent(request); + assert false : "(4) Should not have been able to register without a token"; + } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); + } }
@Test(dependsOnMethods = "testChangeAddressPort") @@ -159,6 +226,7 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test { service.registerAgent(request); assert false : "Should not have been able to hijack a used host/port with new agent name"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } }
@@ -171,18 +239,21 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test { service.registerAgent(request); assert false : "Should not have been able to hijack a used agent name without a token"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } request = createRequest(aReq.getName(), B_HOST, aReq.getPort(), null); try { service.registerAgent(request); assert false : "Should not have been able to hijack a used agent name without a token"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } request = createRequest(aReq.getName(), B_HOST, B_PORT, null); try { service.registerAgent(request); assert false : "Should not have been able to hijack a used agent name without a token"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } }
@@ -195,6 +266,7 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test { service.registerAgent(request); assert false : "Should not have been able to hijack a used host/port with new agent name and invalid token"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } }
@@ -207,24 +279,28 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test { service.registerAgent(request); assert false : "Should not have been able to hijack a used agent name with an invalid token"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } request = createRequest(aReq.getName(), aReq.getAddress(), B_PORT, "badtoken"); try { service.registerAgent(request); assert false : "Should not have been able to hijack a used agent name with an invalid token"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } request = createRequest(aReq.getName(), B_HOST, aReq.getPort(), "badtoken"); try { service.registerAgent(request); assert false : "Should not have been able to hijack a used agent name with an invalid token"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } request = createRequest(aReq.getName(), B_HOST, B_PORT, "badtoken"); try { service.registerAgent(request); assert false : "Should not have been able to hijack a used agent name with an invalid token"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } }
@@ -237,24 +313,28 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test { service.registerAgent(request); assert false : "Should not have been able to hijack agent A using Z's token"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } request = createRequest(aReq.getName(), B_HOST, aReq.getPort(), zResults.getAgentToken()); try { service.registerAgent(request); assert false : "Should not have been able to hijack agent A using Z's token"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } request = createRequest(aReq.getName(), aReq.getAddress(), B_PORT, zResults.getAgentToken()); try { service.registerAgent(request); assert false : "Should not have been able to hijack agent A using Z's token"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } request = createRequest(aReq.getName(), B_HOST, B_PORT, zResults.getAgentToken()); try { service.registerAgent(request); assert false : "Should not have been able to hijack agent A using Z's token"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } }
@@ -267,6 +347,7 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test { service.registerAgent(request); assert false : "An agent should not have been able to hijack another agent's host/port"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } }
@@ -279,6 +360,7 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test { service.registerAgent(request); assert false : "An agent should not be able to change its name"; } catch (AgentRegistrationException ok) { + debugPrintThrowable(ok); } }
@@ -291,6 +373,12 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test { return TEST_AGENT_NAME_PREFIX + name; }
+ private void debugPrintThrowable(Throwable t) { + if (true) { + System.out.println(ThrowableUtil.getAllMessages(t)); + } + } + @BeforeClass public void prepare() throws Exception { // mock the name of our server via the sysprop (in production, this is normally set in rhq-server.properties)
rhq-commits@lists.fedorahosted.org