From 5b105b2b10e5ef0055e152992d4ec827728ebe8e Mon Sep 17 00:00:00 2001 From: Jake Cohen Date: Fri, 24 May 2024 14:06:53 -0700 Subject: [PATCH 01/14] testing property mapping --- .../edu/ohio/ais/rundeck/HttpDescription.java | 2 + .../rundeck/HttpWorkflowNodeStepPlugin.java | 45 ++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java b/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java index db1034f..e3fd382 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java @@ -165,6 +165,8 @@ public Description getDescription() { .defaultValue("false") .renderingOption(StringRenderingConstants.GROUP_NAME,"Print") .build()) + .mapping("proxyIP","project.plugin.WorkflowNodeStep.HttpWorkflowNodeStepPlugin.proxyIP") + .build(); } } diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java index ff4cd30..e1c2ec8 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java @@ -5,16 +5,20 @@ import com.dtolabs.rundeck.core.execution.ExecutionContext; import com.dtolabs.rundeck.core.execution.proxy.ProxySecretBundleCreator; import com.dtolabs.rundeck.core.execution.proxy.SecretBundle; +import com.dtolabs.rundeck.core.execution.utils.ResolverUtil; import com.dtolabs.rundeck.core.execution.workflow.steps.StepException; import com.dtolabs.rundeck.core.execution.workflow.steps.StepFailureReason; import com.dtolabs.rundeck.core.execution.workflow.steps.node.NodeStepException; import com.dtolabs.rundeck.core.plugins.Plugin; import com.dtolabs.rundeck.core.plugins.configuration.Describable; import com.dtolabs.rundeck.core.plugins.configuration.Description; +import com.dtolabs.rundeck.core.utils.IPropertyLookup; import com.dtolabs.rundeck.plugins.PluginLogger; import com.dtolabs.rundeck.plugins.ServiceNameConstants; +import com.dtolabs.rundeck.plugins.descriptions.PluginProperty; import com.dtolabs.rundeck.plugins.step.NodeStepPlugin; import com.dtolabs.rundeck.plugins.step.PluginStepContext; +import com.dtolabs.rundeck.plugins.util.DescriptionBuilder; import edu.ohio.ais.rundeck.util.OAuthClient; import edu.ohio.ais.rundeck.util.SecretBundleUtil; import org.apache.http.HttpEntity; @@ -26,7 +30,7 @@ import java.util.*; @Plugin(name = HttpWorkflowNodeStepPlugin.SERVICE_PROVIDER_NAME, service = ServiceNameConstants.WorkflowNodeStep) -public class HttpWorkflowNodeStepPlugin implements NodeStepPlugin, Describable, ProxySecretBundleCreator { +public class HttpWorkflowNodeStepPlugin implements NodeStepPlugin, Describable, ProxySecretBundleCreator, DescriptionBuilder.Collaborator { public static final String SERVICE_PROVIDER_NAME = "edu.ohio.ais.rundeck.HttpWorkflowNodeStepPlugin"; /** @@ -40,6 +44,12 @@ public class HttpWorkflowNodeStepPlugin implements NodeStepPlugin, Describable, */ public static final Integer DEFAULT_TIMEOUT = 30*1000; +// @PluginProperty( +// title = "Proxy URL", +// description = "HTTP URL to which to make the request.", +// required = true +// ) +// String proxyURL; /** * Synchronized map of all existing OAuth clients. This is indexed by @@ -58,6 +68,14 @@ public Description getDescription() { public void executeNodeStep(PluginStepContext context, Map configuration, INodeEntry entry) throws NodeStepException { PluginLogger log = context.getLogger(); + System.out.println("pre-resolver proxyIp: " + configuration.get("proxyIP")); +// propertyResolver("proxySettings", configuration, context); + propertyResolver("proxyIP", configuration, context); +// propertyResolver("proxyPort", configuration, context); + + System.out.println("post-resolver proxyIp: " + configuration.get("proxyIP")); +// System.out.println("proxySettings: " + configuration.get("proxySettings")); + // Parse out the options String remoteUrl = configuration.containsKey("remoteUrl") ? configuration.get("remoteUrl").toString() : null; String method = configuration.containsKey("method") ? configuration.get("method").toString() : null; @@ -146,4 +164,29 @@ public SecretBundle prepareSecretBundleWorkflowNodeStep(ExecutionContext context public List listSecretsPathWorkflowNodeStep(ExecutionContext context, INodeEntry node, Map configuration) { return SecretBundleUtil.getListSecrets(configuration); } + + void propertyResolver(String property, Map Configuration, PluginStepContext context) { + + String projectPrefix = "project.plugin.WorkflowNodeStep." + "HttpWorkflowNodeStepPlugin" + "."; + String frameworkPrefix = "framework.plugin.WorkflowNodeStep" + SERVICE_PROVIDER_NAME + "."; + + Map projectProperties = context.getFramework().getFrameworkProjectMgr().getFrameworkProject(context.getFrameworkProject()).getProperties(); + IPropertyLookup frameworkProperties = context.getFramework().getPropertyLookup(); + + if(!Configuration.containsKey(property) && projectProperties.containsKey(projectPrefix + property)) { + + Configuration.put(property, projectProperties.get(projectPrefix + property)); + + } else if (!Configuration.containsKey(property) && frameworkProperties.hasProperty(frameworkPrefix + property)) { + + Configuration.put(property, frameworkProperties.getProperty(frameworkPrefix + property)); + + } + System.out.println("resolver: " + Configuration.get(property)); + } + + @Override + public void buildWith(DescriptionBuilder descriptionBuilder) { + descriptionBuilder.mapping("proxyIP", "project.plugin.WorkflowNodeStep.HTTPRequest.proxyIP"); + } } From 966510e16ea4842e200a355e8310a6121af9516c Mon Sep 17 00:00:00 2001 From: Jake Cohen Date: Fri, 24 May 2024 14:26:44 -0700 Subject: [PATCH 02/14] refining solution --- .../edu/ohio/ais/rundeck/HttpDescription.java | 2 -- .../rundeck/HttpWorkflowNodeStepPlugin.java | 18 ++++++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java b/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java index e3fd382..db1034f 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java @@ -165,8 +165,6 @@ public Description getDescription() { .defaultValue("false") .renderingOption(StringRenderingConstants.GROUP_NAME,"Print") .build()) - .mapping("proxyIP","project.plugin.WorkflowNodeStep.HttpWorkflowNodeStepPlugin.proxyIP") - .build(); } } diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java index e1c2ec8..6d44137 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java @@ -30,7 +30,7 @@ import java.util.*; @Plugin(name = HttpWorkflowNodeStepPlugin.SERVICE_PROVIDER_NAME, service = ServiceNameConstants.WorkflowNodeStep) -public class HttpWorkflowNodeStepPlugin implements NodeStepPlugin, Describable, ProxySecretBundleCreator, DescriptionBuilder.Collaborator { +public class HttpWorkflowNodeStepPlugin implements NodeStepPlugin, Describable, ProxySecretBundleCreator { public static final String SERVICE_PROVIDER_NAME = "edu.ohio.ais.rundeck.HttpWorkflowNodeStepPlugin"; /** @@ -68,9 +68,11 @@ public Description getDescription() { public void executeNodeStep(PluginStepContext context, Map configuration, INodeEntry entry) throws NodeStepException { PluginLogger log = context.getLogger(); - System.out.println("pre-resolver proxyIp: " + configuration.get("proxyIP")); -// propertyResolver("proxySettings", configuration, context); - propertyResolver("proxyIP", configuration, context); + Description description = new HttpDescription(SERVICE_PROVIDER_NAME, "HTTP Request Node Step", "Performs an HTTP request with or without authentication (per node)").getDescription(); + description.getProperties().forEach(prop-> + propertyResolver(prop.getName(), configuration, context) + ); +// propertyResolver("proxyIP", configuration, context); // propertyResolver("proxyPort", configuration, context); System.out.println("post-resolver proxyIp: " + configuration.get("proxyIP")); @@ -167,7 +169,7 @@ public List listSecretsPathWorkflowNodeStep(ExecutionContext context, IN void propertyResolver(String property, Map Configuration, PluginStepContext context) { - String projectPrefix = "project.plugin.WorkflowNodeStep." + "HttpWorkflowNodeStepPlugin" + "."; + String projectPrefix = "project.plugin.WorkflowNodeStep." + SERVICE_PROVIDER_NAME + "."; String frameworkPrefix = "framework.plugin.WorkflowNodeStep" + SERVICE_PROVIDER_NAME + "."; Map projectProperties = context.getFramework().getFrameworkProjectMgr().getFrameworkProject(context.getFrameworkProject()).getProperties(); @@ -182,11 +184,7 @@ void propertyResolver(String property, Map Configuration, PluginS Configuration.put(property, frameworkProperties.getProperty(frameworkPrefix + property)); } - System.out.println("resolver: " + Configuration.get(property)); + System.out.println("resolver: " + property + Configuration.get(property)); } - @Override - public void buildWith(DescriptionBuilder descriptionBuilder) { - descriptionBuilder.mapping("proxyIP", "project.plugin.WorkflowNodeStep.HTTPRequest.proxyIP"); - } } From b47ec158e60346217d7f2c76323f87bdd59160f9 Mon Sep 17 00:00:00 2001 From: Jake Cohen Date: Fri, 24 May 2024 15:00:13 -0700 Subject: [PATCH 03/14] adding property resolver to both plugins --- .../edu/ohio/ais/rundeck/HttpBuilder.java | 22 ++++++++++++ .../rundeck/HttpWorkflowNodeStepPlugin.java | 36 ++----------------- .../ais/rundeck/HttpWorkflowStepPlugin.java | 7 ++++ .../HttpWorkflowNodeStepPluginTest.java | 19 ++++++++++ 4 files changed, 51 insertions(+), 33 deletions(-) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java index 9da715e..28763d2 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java @@ -4,6 +4,7 @@ import com.dtolabs.rundeck.core.execution.workflow.steps.StepException; import com.dtolabs.rundeck.core.execution.workflow.steps.StepFailureReason; import com.dtolabs.rundeck.core.storage.ResourceMeta; +import com.dtolabs.rundeck.core.utils.IPropertyLookup; import com.dtolabs.rundeck.plugins.PluginLogger; import com.dtolabs.rundeck.plugins.step.PluginStepContext; import com.google.gson.Gson; @@ -108,6 +109,9 @@ public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws Ce httpClientBuilder.setSSLContext(sslContextBuilder.build()); } if(options.containsKey("proxySettings") && Boolean.parseBoolean(options.get("proxySettings").toString())){ + log.log(5, "using proxy IP: " + options.get("proxyIP").toString()); + log.log(5, "using proxy Port: " + options.get("proxyPort").toString()); + HttpHost proxy = new HttpHost(options.get("proxyIP").toString(), Integer.valueOf((String)options.get("proxyPort")), "http"); httpClientBuilder.setProxy(proxy); } @@ -460,5 +464,23 @@ public void setHeaders(String headers, RequestBuilder request){ } } + static void propertyResolver(String property, Map Configuration, PluginStepContext context, String SERVICE_PROVIDER_NAME) { + + String projectPrefix = "project.plugin.WorkflowNodeStep." + SERVICE_PROVIDER_NAME + "."; + String frameworkPrefix = "framework.plugin.WorkflowNodeStep" + SERVICE_PROVIDER_NAME + "."; + + Map projectProperties = context.getFramework().getFrameworkProjectMgr().getFrameworkProject(context.getFrameworkProject()).getProperties(); + IPropertyLookup frameworkProperties = context.getFramework().getPropertyLookup(); + + if(!Configuration.containsKey(property) && projectProperties.containsKey(projectPrefix + property)) { + + Configuration.put(property, projectProperties.get(projectPrefix + property)); + + } else if (!Configuration.containsKey(property) && frameworkProperties.hasProperty(frameworkPrefix + property)) { + + Configuration.put(property, frameworkProperties.getProperty(frameworkPrefix + property)); + + } + } } diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java index 6d44137..60789e5 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java @@ -29,6 +29,8 @@ import java.io.UnsupportedEncodingException; import java.util.*; +import static edu.ohio.ais.rundeck.HttpBuilder.propertyResolver; + @Plugin(name = HttpWorkflowNodeStepPlugin.SERVICE_PROVIDER_NAME, service = ServiceNameConstants.WorkflowNodeStep) public class HttpWorkflowNodeStepPlugin implements NodeStepPlugin, Describable, ProxySecretBundleCreator { public static final String SERVICE_PROVIDER_NAME = "edu.ohio.ais.rundeck.HttpWorkflowNodeStepPlugin"; @@ -44,13 +46,6 @@ public class HttpWorkflowNodeStepPlugin implements NodeStepPlugin, Describable, */ public static final Integer DEFAULT_TIMEOUT = 30*1000; -// @PluginProperty( -// title = "Proxy URL", -// description = "HTTP URL to which to make the request.", -// required = true -// ) -// String proxyURL; - /** * Synchronized map of all existing OAuth clients. This is indexed by * the Client ID and the token URL so that we can store and re-use access tokens. @@ -70,13 +65,8 @@ public void executeNodeStep(PluginStepContext context, Map confi Description description = new HttpDescription(SERVICE_PROVIDER_NAME, "HTTP Request Node Step", "Performs an HTTP request with or without authentication (per node)").getDescription(); description.getProperties().forEach(prop-> - propertyResolver(prop.getName(), configuration, context) + propertyResolver(prop.getName(), configuration, context, SERVICE_PROVIDER_NAME) ); -// propertyResolver("proxyIP", configuration, context); -// propertyResolver("proxyPort", configuration, context); - - System.out.println("post-resolver proxyIp: " + configuration.get("proxyIP")); -// System.out.println("proxySettings: " + configuration.get("proxySettings")); // Parse out the options String remoteUrl = configuration.containsKey("remoteUrl") ? configuration.get("remoteUrl").toString() : null; @@ -167,24 +157,4 @@ public List listSecretsPathWorkflowNodeStep(ExecutionContext context, IN return SecretBundleUtil.getListSecrets(configuration); } - void propertyResolver(String property, Map Configuration, PluginStepContext context) { - - String projectPrefix = "project.plugin.WorkflowNodeStep." + SERVICE_PROVIDER_NAME + "."; - String frameworkPrefix = "framework.plugin.WorkflowNodeStep" + SERVICE_PROVIDER_NAME + "."; - - Map projectProperties = context.getFramework().getFrameworkProjectMgr().getFrameworkProject(context.getFrameworkProject()).getProperties(); - IPropertyLookup frameworkProperties = context.getFramework().getPropertyLookup(); - - if(!Configuration.containsKey(property) && projectProperties.containsKey(projectPrefix + property)) { - - Configuration.put(property, projectProperties.get(projectPrefix + property)); - - } else if (!Configuration.containsKey(property) && frameworkProperties.hasProperty(frameworkPrefix + property)) { - - Configuration.put(property, frameworkProperties.getProperty(frameworkPrefix + property)); - - } - System.out.println("resolver: " + property + Configuration.get(property)); - } - } diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java index fbe4dbb..c5c2083 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java @@ -23,6 +23,8 @@ import java.io.*; import java.util.*; +import static edu.ohio.ais.rundeck.HttpBuilder.propertyResolver; + /** * Main implementation of the plugin. This will handle fetching @@ -69,6 +71,11 @@ public Description getDescription() { public void executeStep(PluginStepContext pluginStepContext, Map options) throws StepException { PluginLogger log = pluginStepContext.getLogger(); + Description description = new HttpDescription(SERVICE_PROVIDER_NAME, "HTTP Request Node Step", "Performs an HTTP request with or without authentication (per node)").getDescription(); + description.getProperties().forEach(prop-> + propertyResolver(prop.getName(), options, pluginStepContext, SERVICE_PROVIDER_NAME) + ); + // Parse out the options String remoteUrl = options.containsKey("remoteUrl") ? options.get("remoteUrl").toString() : null; String method = options.containsKey("method") ? options.get("method").toString() : null; diff --git a/src/test/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPluginTest.java b/src/test/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPluginTest.java index 85aea58..5b0dfea 100644 --- a/src/test/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPluginTest.java +++ b/src/test/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPluginTest.java @@ -1,11 +1,15 @@ package edu.ohio.ais.rundeck; +import com.dtolabs.rundeck.core.common.Framework; +import com.dtolabs.rundeck.core.common.FrameworkProject; +import com.dtolabs.rundeck.core.common.FrameworkProjectMgr; import com.dtolabs.rundeck.core.common.INodeEntry; import com.dtolabs.rundeck.core.execution.ExecutionContext; import com.dtolabs.rundeck.core.execution.ExecutionLogger; import com.dtolabs.rundeck.core.execution.workflow.steps.StepFailureReason; import com.dtolabs.rundeck.core.execution.workflow.steps.node.NodeStepException; import com.dtolabs.rundeck.core.plugins.configuration.Description; +import com.dtolabs.rundeck.core.utils.IPropertyLookup; import com.dtolabs.rundeck.plugins.PluginLogger; import com.dtolabs.rundeck.plugins.step.PluginStepContext; import com.github.tomakehurst.wiremock.client.WireMock; @@ -27,6 +31,7 @@ import java.util.Map; import static org.junit.Assert.*; +import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.when; public class HttpWorkflowNodeStepPluginTest { @@ -176,6 +181,20 @@ public void setUp() { when(pluginContext.getLogger()).thenReturn(pluginLogger); when(pluginContext.getExecutionContext()).thenReturn(executionContext); + // Mock the necessary objects + Framework framework = Mockito.mock(Framework.class); + FrameworkProjectMgr frameworkProjectMgr = Mockito.mock(FrameworkProjectMgr.class); + FrameworkProject frameworkProject = Mockito.mock(FrameworkProject.class); + IPropertyLookup frameworkProperties = Mockito.mock(IPropertyLookup.class); + + // Mock the interactions + when(pluginContext.getFramework()).thenReturn(framework); + when(framework.getFrameworkProjectMgr()).thenReturn(frameworkProjectMgr); + when(frameworkProjectMgr.getFrameworkProject(anyString())).thenReturn(frameworkProject); + when(frameworkProject.getProperties()).thenReturn(new HashMap()); + when(framework.getPropertyLookup()).thenReturn(frameworkProperties); + when(frameworkProperties.hasProperty(anyString())).thenReturn(true); + dataContext =new HashMap<>(); when(pluginContext.getDataContext()).thenReturn(dataContext); From e745a5d4a15373fa6f64fb7855782233895366d2 Mon Sep 17 00:00:00 2001 From: Jake Cohen Date: Tue, 28 May 2024 14:06:21 -0700 Subject: [PATCH 04/14] add logic for workflowstep --- src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java | 6 +++--- .../edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java | 2 +- .../java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java index 28763d2..756cf87 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java @@ -464,10 +464,10 @@ public void setHeaders(String headers, RequestBuilder request){ } } - static void propertyResolver(String property, Map Configuration, PluginStepContext context, String SERVICE_PROVIDER_NAME) { + static void propertyResolver(String pluginType, String property, Map Configuration, PluginStepContext context, String SERVICE_PROVIDER_NAME) { - String projectPrefix = "project.plugin.WorkflowNodeStep." + SERVICE_PROVIDER_NAME + "."; - String frameworkPrefix = "framework.plugin.WorkflowNodeStep" + SERVICE_PROVIDER_NAME + "."; + String projectPrefix = "project.plugin." + pluginType + "." + SERVICE_PROVIDER_NAME + "."; + String frameworkPrefix = "framework.plugin." + pluginType + "." + SERVICE_PROVIDER_NAME + "."; Map projectProperties = context.getFramework().getFrameworkProjectMgr().getFrameworkProject(context.getFrameworkProject()).getProperties(); IPropertyLookup frameworkProperties = context.getFramework().getPropertyLookup(); diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java index 60789e5..155759a 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java @@ -65,7 +65,7 @@ public void executeNodeStep(PluginStepContext context, Map confi Description description = new HttpDescription(SERVICE_PROVIDER_NAME, "HTTP Request Node Step", "Performs an HTTP request with or without authentication (per node)").getDescription(); description.getProperties().forEach(prop-> - propertyResolver(prop.getName(), configuration, context, SERVICE_PROVIDER_NAME) + propertyResolver("WorlflowNodeStep", prop.getName(), configuration, context, SERVICE_PROVIDER_NAME) ); // Parse out the options diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java index c5c2083..f7a9d7c 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java @@ -73,7 +73,7 @@ public void executeStep(PluginStepContext pluginStepContext, Map Description description = new HttpDescription(SERVICE_PROVIDER_NAME, "HTTP Request Node Step", "Performs an HTTP request with or without authentication (per node)").getDescription(); description.getProperties().forEach(prop-> - propertyResolver(prop.getName(), options, pluginStepContext, SERVICE_PROVIDER_NAME) + propertyResolver("WorflowStep",prop.getName(), options, pluginStepContext, SERVICE_PROVIDER_NAME) ); // Parse out the options From 75ed501cfc82657ca3da49804a59c3e886673b5d Mon Sep 17 00:00:00 2001 From: Jake Cohen Date: Thu, 30 May 2024 08:46:09 -0700 Subject: [PATCH 05/14] fixing typos --- .../java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java | 2 +- src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java index 155759a..fada760 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java @@ -65,7 +65,7 @@ public void executeNodeStep(PluginStepContext context, Map confi Description description = new HttpDescription(SERVICE_PROVIDER_NAME, "HTTP Request Node Step", "Performs an HTTP request with or without authentication (per node)").getDescription(); description.getProperties().forEach(prop-> - propertyResolver("WorlflowNodeStep", prop.getName(), configuration, context, SERVICE_PROVIDER_NAME) + propertyResolver("WorkflowNodeStep", prop.getName(), configuration, context, SERVICE_PROVIDER_NAME) ); // Parse out the options diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java index f7a9d7c..bff7b7a 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java @@ -73,7 +73,7 @@ public void executeStep(PluginStepContext pluginStepContext, Map Description description = new HttpDescription(SERVICE_PROVIDER_NAME, "HTTP Request Node Step", "Performs an HTTP request with or without authentication (per node)").getDescription(); description.getProperties().forEach(prop-> - propertyResolver("WorflowStep",prop.getName(), options, pluginStepContext, SERVICE_PROVIDER_NAME) + propertyResolver("WorkflowStep",prop.getName(), options, pluginStepContext, SERVICE_PROVIDER_NAME) ); // Parse out the options From 2a604a57f28acb1cc30c4e23cee32c6cf3f98b7b Mon Sep 17 00:00:00 2001 From: Jake Cohen Date: Fri, 31 May 2024 14:49:23 -0700 Subject: [PATCH 06/14] adding option to use jvm proxy settings --- src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java | 11 +++++++++-- .../java/edu/ohio/ais/rundeck/HttpDescription.java | 7 +++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java index 756cf87..50cf752 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java @@ -23,6 +23,7 @@ import org.apache.http.entity.ContentType; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.SystemDefaultRoutePlanner; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.util.EntityUtils; import org.dom4j.DocumentHelper; @@ -34,6 +35,7 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; import java.io.*; +import java.net.ProxySelector; import java.security.GeneralSecurityException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -109,13 +111,18 @@ public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws Ce httpClientBuilder.setSSLContext(sslContextBuilder.build()); } if(options.containsKey("proxySettings") && Boolean.parseBoolean(options.get("proxySettings").toString())){ - log.log(5, "using proxy IP: " + options.get("proxyIP").toString()); - log.log(5, "using proxy Port: " + options.get("proxyPort").toString()); + log.log(5, "proxy IP set in job: " + options.get("proxyIP").toString()); HttpHost proxy = new HttpHost(options.get("proxyIP").toString(), Integer.valueOf((String)options.get("proxyPort")), "http"); httpClientBuilder.setProxy(proxy); } + if(options.get("useSystemProxySettings").equals("true")) { + + httpClientBuilder.setRoutePlanner(new SystemDefaultRoutePlanner(ProxySelector.getDefault())); + + } + return httpClientBuilder.build(); } diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java b/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java index db1034f..5cead91 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java @@ -2,6 +2,7 @@ import com.dtolabs.rundeck.core.plugins.configuration.Describable; import com.dtolabs.rundeck.core.plugins.configuration.Description; +import com.dtolabs.rundeck.core.plugins.configuration.PropertyScope; import com.dtolabs.rundeck.core.plugins.configuration.StringRenderingConstants; import com.dtolabs.rundeck.plugins.util.DescriptionBuilder; import com.dtolabs.rundeck.plugins.util.PropertyBuilder; @@ -165,6 +166,12 @@ public Description getDescription() { .defaultValue("false") .renderingOption(StringRenderingConstants.GROUP_NAME,"Print") .build()) + .property(PropertyBuilder.builder() + .booleanType("useSystemProxySettings") + .description("Choose whether to use proxy settings set on the JVM.") + .defaultValue("false") + .scope(PropertyScope.Project) + .build()) .build(); } } From 9721f4c5cd1b9329b60c20c5215a3e54eb4656f2 Mon Sep 17 00:00:00 2001 From: Jake Cohen Date: Fri, 31 May 2024 15:34:29 -0700 Subject: [PATCH 07/14] cleaning up --- src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java index 50cf752..a3e218a 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java @@ -119,6 +119,8 @@ public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws Ce if(options.get("useSystemProxySettings").equals("true")) { + log.log(5, "Using proxy settings set on system"); + httpClientBuilder.setRoutePlanner(new SystemDefaultRoutePlanner(ProxySelector.getDefault())); } From 2c3cc840deb74a4b4c4ccc170af45a9b89b2a143 Mon Sep 17 00:00:00 2001 From: Jake Cohen Date: Mon, 10 Jun 2024 15:44:29 -0700 Subject: [PATCH 08/14] allow job-level override --- src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java index a3e218a..261484c 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java @@ -110,13 +110,6 @@ public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws Ce httpClientBuilder.setSSLHostnameVerifier(new NoopHostnameVerifier()); httpClientBuilder.setSSLContext(sslContextBuilder.build()); } - if(options.containsKey("proxySettings") && Boolean.parseBoolean(options.get("proxySettings").toString())){ - log.log(5, "proxy IP set in job: " + options.get("proxyIP").toString()); - - HttpHost proxy = new HttpHost(options.get("proxyIP").toString(), Integer.valueOf((String)options.get("proxyPort")), "http"); - httpClientBuilder.setProxy(proxy); - } - if(options.get("useSystemProxySettings").equals("true")) { log.log(5, "Using proxy settings set on system"); @@ -124,6 +117,12 @@ public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws Ce httpClientBuilder.setRoutePlanner(new SystemDefaultRoutePlanner(ProxySelector.getDefault())); } + if(options.containsKey("proxySettings") && Boolean.parseBoolean(options.get("proxySettings").toString())){ + log.log(5, "proxy IP set in job: " + options.get("proxyIP").toString()); + + HttpHost proxy = new HttpHost(options.get("proxyIP").toString(), Integer.valueOf((String)options.get("proxyPort")), "http"); + httpClientBuilder.setProxy(proxy); + } return httpClientBuilder.build(); } From adc37c991357947eaa464a6023cb033ee59651eb Mon Sep 17 00:00:00 2001 From: Jake Cohen Date: Mon, 15 Jul 2024 23:07:47 -0700 Subject: [PATCH 09/14] fixing logic of overriding proxy settings from job level --- src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java index 261484c..8b5a895 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java @@ -110,7 +110,7 @@ public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws Ce httpClientBuilder.setSSLHostnameVerifier(new NoopHostnameVerifier()); httpClientBuilder.setSSLContext(sslContextBuilder.build()); } - if(options.get("useSystemProxySettings").equals("true")) { + if(options.get("useSystemProxySettings").equals("true") && !Boolean.parseBoolean(options.get("proxySettings").toString())) { log.log(5, "Using proxy settings set on system"); From c03beb32a4b01137cb85acb4f484d6c64e15ad8f Mon Sep 17 00:00:00 2001 From: jmanuelosunamoreno Date: Tue, 13 Aug 2024 17:44:14 -0400 Subject: [PATCH 10/14] fix tests --- .../edu/ohio/ais/rundeck/HttpBuilder.java | 55 +++++++++++++------ .../edu/ohio/ais/rundeck/HttpDescription.java | 1 + .../rundeck/HttpWorkflowNodeStepPlugin.java | 13 +++-- .../ais/rundeck/HttpWorkflowStepPlugin.java | 12 ++-- .../HttpWorkflowNodeStepPluginTest.java | 1 + .../rundeck/HttpWorkflowStepPluginTest.java | 19 +++++++ 6 files changed, 72 insertions(+), 29 deletions(-) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java index 8b5a895..16223e6 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java @@ -97,7 +97,8 @@ public CloseableHttpClient getHttpClient(Map options) throws Gen httpClientBuilder.disableAuthCaching(); httpClientBuilder.disableAutomaticRetries(); - if(options.containsKey("sslVerify") && !Boolean.parseBoolean(options.get("sslVerify").toString())) { + + if(!getBooleanOption(options, "sslVerify", true)) { log.log(5,"Disabling all SSL certificate verification."); SSLContextBuilder sslContextBuilder = new SSLContextBuilder(); sslContextBuilder.loadTrustMaterial(null, new TrustStrategy() { @@ -110,17 +111,15 @@ public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws Ce httpClientBuilder.setSSLHostnameVerifier(new NoopHostnameVerifier()); httpClientBuilder.setSSLContext(sslContextBuilder.build()); } - if(options.get("useSystemProxySettings").equals("true") && !Boolean.parseBoolean(options.get("proxySettings").toString())) { - + if(getBooleanOption(options, "useSystemProxySettings", false) && !getBooleanOption(options, "proxySettings", false)) { log.log(5, "Using proxy settings set on system"); - - httpClientBuilder.setRoutePlanner(new SystemDefaultRoutePlanner(ProxySelector.getDefault())); - + HttpHost proxy = new HttpHost(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort")), "http"); + httpClientBuilder.setProxy(proxy); } - if(options.containsKey("proxySettings") && Boolean.parseBoolean(options.get("proxySettings").toString())){ + if(getBooleanOption(options, "proxySettings", false)){ log.log(5, "proxy IP set in job: " + options.get("proxyIP").toString()); - HttpHost proxy = new HttpHost(options.get("proxyIP").toString(), Integer.valueOf((String)options.get("proxyPort")), "http"); + HttpHost proxy = new HttpHost(options.get("proxyIP").toString(), Integer.parseInt((String)options.get("proxyPort")), "http"); httpClientBuilder.setProxy(proxy); } @@ -144,19 +143,19 @@ public void doRequest(Map options, HttpUriRequest request, Integ try { response = this.getHttpClient(options).execute(request); - if(options.containsKey("printResponseCode") && Boolean.parseBoolean(options.get("printResponseCode").toString())) { + if(getBooleanOption(options,"printResponseCode",false)) { String responseCode = response.getStatusLine().toString(); log.log(2, "Response Code: " + responseCode); } //print the response content - if(options.containsKey("printResponse") && Boolean.parseBoolean(options.get("printResponse").toString())) { + if(getBooleanOption(options,"printResponse",false)) { output = getOutputForResponse(this.prettyPrint(response)); //print response log.log(2, output); } - if(options.containsKey("printResponseToFile") && Boolean.parseBoolean(options.get("printResponseToFile").toString())){ + if(getBooleanOption(options,"printResponseToFile",false)){ File file = new File(options.get("file").toString()); BufferedWriter writer = new BufferedWriter(new FileWriter(file)); if( output.isEmpty() ){ @@ -170,7 +169,7 @@ public void doRequest(Map options, HttpUriRequest request, Integ } //check response status - if(options.containsKey("checkResponseCode") && Boolean.parseBoolean(options.get("checkResponseCode").toString())) { + if(getBooleanOption(options,"checkResponseCode",false)) { if(options.containsKey("responseCode")){ int responseCode = Integer.valueOf( (String) options.get("responseCode")); @@ -347,14 +346,14 @@ public String prettyPrint(HttpResponse response){ String getAuthHeader(PluginStepContext pluginStepContext, Map options) throws StepException { - String authentication = options.containsKey("authentication") ? options.get("authentication").toString() : AUTH_NONE; + String authentication = getStringOption(options, "authentication",AUTH_NONE); //moving the password to the key storage String password=null; String authHeader = null; if(options.containsKey("password") ){ - String passwordRaw = options.containsKey("password") ? options.get("password").toString() : null; + String passwordRaw = getStringOption(options, "password"); //to avid the test error add a try-catch //if it didn't find the key path, it will use the password directly byte[] content = SecretBundleUtil.getStoragePassword(pluginStepContext.getExecutionContext(),passwordRaw ); @@ -368,7 +367,7 @@ String getAuthHeader(PluginStepContext pluginStepContext, Map o if(authentication.equals(AUTH_BASIC)) { // Setup the authentication header for BASIC - String username = options.containsKey("username") ? options.get("username").toString() : null; + String username = getStringOption(options, "username"); if(username == null || password == null) { throw new StepException("Username and password not provided for BASIC Authentication", @@ -381,9 +380,12 @@ String getAuthHeader(PluginStepContext pluginStepContext, Map o authHeader = "Basic " + com.dtolabs.rundeck.core.utils.Base64.encode(authHeader); } else if (authentication.equals(AUTH_OAUTH2)) { // Get an OAuth token and setup the auth header for OAuth - String tokenEndpoint = options.containsKey("oauthTokenEndpoint") ? options.get("oauthTokenEndpoint").toString() : null; - String validateEndpoint = options.containsKey("oauthValidateEndpoint") ? options.get("oauthValidateEndpoint").toString() : null; - String clientId = options.containsKey("username") ? options.get("username").toString() : null; + String tokenEndpoint = getStringOption(options, "oauthTokenEndpoint"); + String validateEndpoint = getStringOption(options, "oauthValidateEndpoint"); + String clientId = getStringOption(options, "username"); + + + String clientSecret = password; @@ -491,4 +493,21 @@ static void propertyResolver(String pluginType, String property, Map options, String key) { + return getStringOption(options, key, null); + } + + static String getStringOption(Map options, String key, String defValue) { + return options.containsKey(key) && options.get(key) != null ? options.get(key).toString() : defValue; + } + + public static Integer getIntOption(Map options, String key, Integer defValue) { + return options.containsKey(key) && options.get(key) != null ? Integer.parseInt(options.get(key).toString()) : defValue; + } + + public static Boolean getBooleanOption(Map options, String key, Boolean defValue) { + return options.containsKey(key) && options.get(key) != null ? Boolean.parseBoolean(options.get(key).toString()) : defValue; + } + + } diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java b/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java index 5cead91..de7ac43 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpDescription.java @@ -167,6 +167,7 @@ public Description getDescription() { .renderingOption(StringRenderingConstants.GROUP_NAME,"Print") .build()) .property(PropertyBuilder.builder() + .title("System Proxy Settings") .booleanType("useSystemProxySettings") .description("Choose whether to use proxy settings set on the JVM.") .defaultValue("false") diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java index fada760..d11ab1b 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPlugin.java @@ -30,6 +30,8 @@ import java.util.*; import static edu.ohio.ais.rundeck.HttpBuilder.propertyResolver; +import static edu.ohio.ais.rundeck.HttpBuilder.getIntOption; +import static edu.ohio.ais.rundeck.HttpBuilder.getStringOption; @Plugin(name = HttpWorkflowNodeStepPlugin.SERVICE_PROVIDER_NAME, service = ServiceNameConstants.WorkflowNodeStep) public class HttpWorkflowNodeStepPlugin implements NodeStepPlugin, Describable, ProxySecretBundleCreator { @@ -69,12 +71,11 @@ public void executeNodeStep(PluginStepContext context, Map confi ); // Parse out the options - String remoteUrl = configuration.containsKey("remoteUrl") ? configuration.get("remoteUrl").toString() : null; - String method = configuration.containsKey("method") ? configuration.get("method").toString() : null; - - Integer timeout = configuration.containsKey("timeout") ? Integer.parseInt(configuration.get("timeout").toString()) : DEFAULT_TIMEOUT; - String headers = configuration.containsKey("headers") ? configuration.get("headers").toString() : null; - String body = configuration.containsKey("body") ? configuration.get("body").toString() : null; + String remoteUrl = getStringOption(configuration, "remoteUrl"); + String method = getStringOption(configuration, "method"); + Integer timeout =getIntOption(configuration,"timeout", DEFAULT_TIMEOUT); + String headers = getStringOption(configuration, "headers"); + String body = getStringOption(configuration, "body"); log.log(5, "remoteUrl: " + remoteUrl); log.log(5, "method: " + method); diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java index bff7b7a..88fec4f 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpWorkflowStepPlugin.java @@ -24,6 +24,8 @@ import java.util.*; import static edu.ohio.ais.rundeck.HttpBuilder.propertyResolver; +import static edu.ohio.ais.rundeck.HttpBuilder.getIntOption; +import static edu.ohio.ais.rundeck.HttpBuilder.getStringOption; /** @@ -77,11 +79,11 @@ public void executeStep(PluginStepContext pluginStepContext, Map ); // Parse out the options - String remoteUrl = options.containsKey("remoteUrl") ? options.get("remoteUrl").toString() : null; - String method = options.containsKey("method") ? options.get("method").toString() : null; - Integer timeout = options.containsKey("timeout") ? Integer.parseInt(options.get("timeout").toString()) : DEFAULT_TIMEOUT; - String headers = options.containsKey("headers") ? options.get("headers").toString() : null; - String body = options.containsKey("body") ? options.get("body").toString() : null; + String remoteUrl = getStringOption(options, "remoteUrl"); + String method = getStringOption(options, "method"); + Integer timeout =getIntOption(options,"timeout", DEFAULT_TIMEOUT); + String headers = getStringOption(options, "headers"); + String body = getStringOption(options, "body"); if(remoteUrl == null || method == null) { throw new StepException("Remote URL and Method are required.", StepFailureReason.ConfigurationFailure); diff --git a/src/test/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPluginTest.java b/src/test/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPluginTest.java index 5b0dfea..60453b7 100644 --- a/src/test/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPluginTest.java +++ b/src/test/java/edu/ohio/ais/rundeck/HttpWorkflowNodeStepPluginTest.java @@ -335,6 +335,7 @@ public void canHandleAuthenticationRequired() throws NodeStepException { options.put("remoteUrl", OAuthClientTest.BASE_URI + ERROR_URL_401); options.put("method", "GET"); + options.put("authentication", HttpBuilder.AUTH_BASIC); this.plugin.executeNodeStep(pluginContext, options, node ); } diff --git a/src/test/java/edu/ohio/ais/rundeck/HttpWorkflowStepPluginTest.java b/src/test/java/edu/ohio/ais/rundeck/HttpWorkflowStepPluginTest.java index ba7ccf1..88773a8 100644 --- a/src/test/java/edu/ohio/ais/rundeck/HttpWorkflowStepPluginTest.java +++ b/src/test/java/edu/ohio/ais/rundeck/HttpWorkflowStepPluginTest.java @@ -1,10 +1,14 @@ package edu.ohio.ais.rundeck; +import com.dtolabs.rundeck.core.common.Framework; +import com.dtolabs.rundeck.core.common.FrameworkProject; +import com.dtolabs.rundeck.core.common.FrameworkProjectMgr; import com.dtolabs.rundeck.core.execution.ExecutionContext; import com.dtolabs.rundeck.core.execution.workflow.steps.PluginStepContextImpl; import com.dtolabs.rundeck.core.execution.workflow.steps.StepException; import com.dtolabs.rundeck.core.execution.workflow.steps.StepFailureReason; import com.dtolabs.rundeck.core.plugins.configuration.Description; +import com.dtolabs.rundeck.core.utils.IPropertyLookup; import com.dtolabs.rundeck.plugins.PluginLogger; import com.dtolabs.rundeck.plugins.step.PluginStepContext; import com.github.tomakehurst.wiremock.client.WireMock; @@ -20,6 +24,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.when; public class HttpWorkflowStepPluginTest { @@ -163,6 +168,19 @@ public void setUp() { dataContext =new HashMap<>(); Mockito.when(pluginContext.getDataContext()).thenReturn(dataContext); + // Mock the necessary objects + Framework framework = Mockito.mock(Framework.class); + FrameworkProjectMgr frameworkProjectMgr = Mockito.mock(FrameworkProjectMgr.class); + FrameworkProject frameworkProject = Mockito.mock(FrameworkProject.class); + IPropertyLookup frameworkProperties = Mockito.mock(IPropertyLookup.class); + + when(pluginContext.getFramework()).thenReturn(framework); + when(framework.getFrameworkProjectMgr()).thenReturn(frameworkProjectMgr); + when(frameworkProjectMgr.getFrameworkProject(anyString())).thenReturn(frameworkProject); + when(frameworkProject.getProperties()).thenReturn(new HashMap()); + when(framework.getPropertyLookup()).thenReturn(frameworkProperties); + when(frameworkProperties.hasProperty(anyString())).thenReturn(true); + } @Test() @@ -293,6 +311,7 @@ public void canHandleAuthenticationRequired() throws StepException { options.put("remoteUrl", OAuthClientTest.BASE_URI + ERROR_URL_401); options.put("method", "GET"); + options.put("authentication", HttpBuilder.AUTH_BASIC); this.plugin.executeStep(pluginContext, options); } From 5df878186ae96e0271ef967b036d7be25019eaf4 Mon Sep 17 00:00:00 2001 From: jmanuelosunamoreno Date: Tue, 13 Aug 2024 17:51:24 -0400 Subject: [PATCH 11/14] remove unnused import --- src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java index 16223e6..77fdf5d 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java @@ -23,7 +23,6 @@ import org.apache.http.entity.ContentType; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.conn.SystemDefaultRoutePlanner; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.util.EntityUtils; import org.dom4j.DocumentHelper; @@ -35,7 +34,6 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; import java.io.*; -import java.net.ProxySelector; import java.security.GeneralSecurityException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; From ca1117f5a55dd06a0f2aa1797d85652afff35546 Mon Sep 17 00:00:00 2001 From: jmanuelosunamoreno Date: Tue, 13 Aug 2024 18:20:14 -0400 Subject: [PATCH 12/14] add java doc --- .../edu/ohio/ais/rundeck/HttpBuilder.java | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java index 77fdf5d..fbc7ee1 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java @@ -491,18 +491,54 @@ static void propertyResolver(String pluginType, String property, Map options, String key) { + /** + * Retrieves a string value from the options map. + * If the key does not exist or the value is null, it returns null. + * + * @param options the map containing option keys and values + * @param key the key whose associated value is to be returned + * @return the string value associated with the specified key, or null if the key does not exist or the value is null + */ + static String getStringOption(Map options, String key) { return getStringOption(options, key, null); } + /** + * Retrieves a string value from the options map. + * If the key does not exist or the value is null, it returns the specified default value. + * + * @param options the map containing option keys and values + * @param key the key whose associated value is to be returned + * @param defValue the default value to return if the key does not exist or the value is null + * @return the string value associated with the specified key, or the default value if the key does not exist or the value is null + */ static String getStringOption(Map options, String key, String defValue) { return options.containsKey(key) && options.get(key) != null ? options.get(key).toString() : defValue; } + /** + * Retrieves an integer value from the options map. + * If the key does not exist or the value is null, it returns the specified default value. + * + * @param options the map containing option keys and values + * @param key the key whose associated value is to be returned + * @param defValue the default value to return if the key does not exist or the value is null + * @return the integer value associated with the specified key, or the default value if the key does not exist or the value is null + * @throws NumberFormatException if the value cannot be parsed as an integer + */ public static Integer getIntOption(Map options, String key, Integer defValue) { return options.containsKey(key) && options.get(key) != null ? Integer.parseInt(options.get(key).toString()) : defValue; } + /** + * Retrieves a boolean value from the options map. + * If the key does not exist or the value is null, it returns the specified default value. + * + * @param options the map containing option keys and values + * @param key the key whose associated value is to be returned + * @param defValue the default value to return if the key does not exist or the value is null + * @return the boolean value associated with the specified key, or the default value if the key does not exist or the value is null + */ public static Boolean getBooleanOption(Map options, String key, Boolean defValue) { return options.containsKey(key) && options.get(key) != null ? Boolean.parseBoolean(options.get(key).toString()) : defValue; } From 6c55dbd4c3152a111763fae28de77edc597063ee Mon Sep 17 00:00:00 2001 From: jmanuelosunamoreno Date: Wed, 14 Aug 2024 14:37:30 -0400 Subject: [PATCH 13/14] improve validation and log --- .../edu/ohio/ais/rundeck/HttpBuilder.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java index fbc7ee1..ec3d7f4 100644 --- a/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java +++ b/src/main/java/edu/ohio/ais/rundeck/HttpBuilder.java @@ -89,7 +89,7 @@ public enum Reason implements FailureReason { } - public CloseableHttpClient getHttpClient(Map options) throws GeneralSecurityException { + public CloseableHttpClient getHttpClient(Map options) throws GeneralSecurityException, StepException { HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); httpClientBuilder.disableAuthCaching(); @@ -111,13 +111,25 @@ public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws Ce } if(getBooleanOption(options, "useSystemProxySettings", false) && !getBooleanOption(options, "proxySettings", false)) { log.log(5, "Using proxy settings set on system"); - HttpHost proxy = new HttpHost(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort")), "http"); + String proxyHost = System.getProperty("http.proxyHost"); + String proxyPort = System.getProperty("http.proxyPort"); + if (proxyPort.isEmpty() || proxyHost.isEmpty()) { + throw new StepException("proxyHost and proxyPort are required to use System Proxy Settings", StepFailureReason.ConfigurationFailure); + } + HttpHost proxy = new HttpHost(proxyHost, Integer.parseInt(proxyPort), "http"); httpClientBuilder.setProxy(proxy); } - if(getBooleanOption(options, "proxySettings", false)){ - log.log(5, "proxy IP set in job: " + options.get("proxyIP").toString()); + if (getBooleanOption(options, "proxySettings", false)) { + String proxyIP = getStringOption(options, "proxyIP", ""); + String proxyPort = getStringOption(options, "proxyPort", ""); + + if (proxyIP.isEmpty() || proxyPort.isEmpty()) { + throw new StepException("Proxy IP and Proxy Port are required to use Proxy Settings.", StepFailureReason.ConfigurationFailure); + } - HttpHost proxy = new HttpHost(options.get("proxyIP").toString(), Integer.parseInt((String)options.get("proxyPort")), "http"); + log.log(5, "proxy IP set in job: " + proxyIP); + log.log(5, "proxy Port set in job: " + proxyPort); + HttpHost proxy = new HttpHost(proxyIP, Integer.parseInt(proxyPort), "http"); httpClientBuilder.setProxy(proxy); } From 3b085ee7b47352683fae2bb7fa3230784e2d0bdf Mon Sep 17 00:00:00 2001 From: jmanuelosunamoreno Date: Wed, 14 Aug 2024 17:39:11 -0400 Subject: [PATCH 14/14] add unit test --- .../edu/ohio/ais/rundeck/HttpBuilderTest.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/test/java/edu/ohio/ais/rundeck/HttpBuilderTest.java diff --git a/src/test/java/edu/ohio/ais/rundeck/HttpBuilderTest.java b/src/test/java/edu/ohio/ais/rundeck/HttpBuilderTest.java new file mode 100644 index 0000000..91189a6 --- /dev/null +++ b/src/test/java/edu/ohio/ais/rundeck/HttpBuilderTest.java @@ -0,0 +1,78 @@ +package edu.ohio.ais.rundeck; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static edu.ohio.ais.rundeck.HttpBuilder.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class HttpBuilderTest { + + @Test + public void testGetStringOption() { + Map options = new HashMap<>(); + + String result = getStringOption(options, "missingKey"); + assertNull("Expected null when key is missing", result); + + options.put("nullKey", null); + result = getStringOption(options, "nullKey"); + assertNull("Expected null when value is null", result); + + options.put("key", "value"); + result = getStringOption(options, "key"); + assertEquals("Expected the value associated with the key", "value", result); + } + + @Test + public void testGetStringOptionWithDefault() { + Map options = new HashMap<>(); + + String result = getStringOption(options, "missingKey", "defaultValue"); + assertEquals("Expected the default value when key is missing", "defaultValue", result); + + options.put("nullKey", null); + result = getStringOption(options, "nullKey", "defaultValue"); + assertEquals("Expected the default value when value is null", "defaultValue", result); + + options.put("key", "value"); + result = getStringOption(options, "key", "defaultValue"); + assertEquals("Expected the value associated with the key", "value", result); + } + + @Test + public void testGetIntOption() { + Map options = new HashMap<>(); + + Integer result = getIntOption(options, "missingKey", 42); + assertEquals("Expected the default value when key is missing", Integer.valueOf(42), result); + + options.put("nullKey", null); + result = getIntOption(options, "nullKey", 42); + assertEquals("Expected the default value when value is null", Integer.valueOf(42), result); + + options.put("key", 99); + result = getIntOption(options, "key", 42); + assertEquals("Expected the value associated with the key", Integer.valueOf(99), result); + } + + @Test + public void testGetBooleanOption() { + Map options = new HashMap<>(); + + Boolean result = getBooleanOption(options, "missingKey", true); + assertEquals("Expected the default value when key is missing", Boolean.TRUE, result); + + options.put("nullKey", null); + result = getBooleanOption(options, "nullKey", true); + assertEquals("Expected the default value when value is null", Boolean.TRUE, result); + + options.put("key", false); + result = getBooleanOption(options, "key", true); + assertEquals("Expected the value associated with the key", Boolean.FALSE, result); + } + +}