| @@ -1,88 +1,252 @@ | ||
| /*************************GO-LICENSE-START********************************* | ||
| * Copyright 2014 ThoughtWorks, Inc. | ||
| /* | ||
| * Copyright 2016 ThoughtWorks, Inc. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| *************************GO-LICENSE-END***********************************/ | ||
| */ | ||
| package com.thoughtworks.go.agent.bootstrapper.osx; | ||
| import java.awt.BorderLayout; | ||
| import java.awt.FlowLayout; | ||
| import java.awt.event.ActionListener; | ||
| import java.awt.event.ActionEvent; | ||
| import javax.swing.JFrame; | ||
| import javax.swing.JLabel; | ||
| import javax.swing.JButton; | ||
| import javax.swing.JTextField; | ||
| import javax.swing.JPanel; | ||
| import com.beust.jcommander.ParameterException; | ||
| import com.thoughtworks.go.agent.common.AgentBootstrapperArgs; | ||
| import com.thoughtworks.go.agent.common.CertificateFileValidator; | ||
| import com.thoughtworks.go.agent.common.ServerUrlValidator; | ||
| import org.apache.commons.logging.Log; | ||
| import org.apache.commons.logging.LogFactory; | ||
| import javax.swing.*; | ||
| import java.awt.*; | ||
| import java.awt.event.ActionEvent; | ||
| import java.awt.event.ActionListener; | ||
| import java.io.File; | ||
| import java.net.MalformedURLException; | ||
| import java.net.URL; | ||
| import java.util.Arrays; | ||
| public class MacPreferencesPane extends JFrame { | ||
| private static final Log LOG = LogFactory.getLog(AgentMacWindow.class); | ||
| private JTextField serverTextField; | ||
| private String originalHost; | ||
| private FileBrowser fileBrowser; | ||
| private JButton okButton; | ||
| private AgentMacWindow agentMacWindow; | ||
| private SslModeComponent sslModeComponent; | ||
| public MacPreferencesPane(final AgentMacWindow agentMacWindow) { | ||
| super(); | ||
| this.agentMacWindow = agentMacWindow; | ||
| BorderLayout border = new BorderLayout(10, 10); | ||
| getContentPane().setLayout(border); | ||
| createView(); | ||
| sslModeComponent.noneModeRadioButton.addActionListener(new ActionListener() { | ||
| @Override | ||
| public void actionPerformed(ActionEvent e) { | ||
| fileBrowser.setEnabled(!sslModeComponent.noneModeRadioButton.isSelected()); | ||
| } | ||
| }); | ||
| okButton.addActionListener(new ActionListener() { | ||
| public void actionPerformed(ActionEvent newEvent) { | ||
| try { | ||
| AgentBootstrapperArgs newArgs = new AgentBootstrapperArgs( | ||
| new URL(serverTextField.getText()), | ||
| fileBrowser.getFile(), sslModeComponent.getSslMode()); | ||
| try { | ||
| new ServerUrlValidator().validate("The server url", newArgs.getServerUrl().toExternalForm()); | ||
| } catch (ParameterException e) { | ||
| JOptionPane.showMessageDialog(getContentPane(), e.getMessage(), "Invalid server url", JOptionPane.ERROR_MESSAGE); | ||
| return; | ||
| } | ||
| if (newArgs.getRootCertFile() != null) { | ||
| try { | ||
| new CertificateFileValidator().validate("The server root certificate", newArgs.getRootCertFile().getPath()); | ||
| } catch (ParameterException e) { | ||
| JOptionPane.showMessageDialog(getContentPane(), e.getMessage(), "Invalid server root certificate", JOptionPane.ERROR_MESSAGE); | ||
| return; | ||
| } | ||
| } | ||
| if (!newArgs.equals(agentMacWindow.getBootstrapperArgs())) { | ||
| agentMacWindow.setBootstrapperArgs(newArgs); | ||
| LOG.info("Updating preferences to " + newArgs); | ||
| } else { | ||
| LOG.info("Preferences are unchanged " + newArgs); | ||
| } | ||
| setVisible(false); | ||
| } catch (MalformedURLException e) { | ||
| JOptionPane.showMessageDialog(getContentPane(), "The server url must be an HTTPS url and must begin with https://", "Invalid server url", JOptionPane.ERROR_MESSAGE); | ||
| } | ||
| } | ||
| }); | ||
| getContentPane().setLayout(new BorderLayout(10, 10)); | ||
| JLabel prefsText = new JLabel("Go Server Hostname or IP"); | ||
| setSize(getPreferredSize()); | ||
| setLocation(20, 30); | ||
| setResizable(false); | ||
| } | ||
| private void createView() { | ||
| JPanel controlsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 10)); | ||
| serverTextField = new JTextField(""); | ||
| serverTextField.setColumns(15); | ||
| serverTextField.selectAll(); | ||
| JPanel textPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 10)); | ||
| textPanel.add(prefsText); | ||
| JPanel textPanel = new JPanel(new GridLayout(4, 2, 0, 10)); | ||
| textPanel.add(new JLabel("Go Server Hostname or IP")); | ||
| textPanel.add(serverTextField); | ||
| getContentPane().add(textPanel, BorderLayout.NORTH); | ||
| textPanel.add(new JLabel("SSL Mode")); | ||
| sslModeComponent = new SslModeComponent(); | ||
| textPanel.add(sslModeComponent); | ||
| textPanel.add(new JLabel("Server root certificate")); | ||
| fileBrowser = new FileBrowser(); | ||
| textPanel.add(fileBrowser); | ||
| controlsPanel.add(textPanel); | ||
| getContentPane().add(controlsPanel, BorderLayout.NORTH); | ||
| JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 10)); | ||
| JButton okButton = new JButton("OK"); | ||
| okButton = new JButton("OK"); | ||
| buttonPanel.add(okButton); | ||
| okButton.addActionListener(new ActionListener() { | ||
| public void actionPerformed(ActionEvent newEvent) { | ||
| String newHost = serverTextField.getText(); | ||
| if (!originalHost.equals(newHost)) { | ||
| LOG.info("Server changed to " + newHost); | ||
| agentMacWindow.setHost(newHost); | ||
| } else { | ||
| LOG.info("Server is still " + originalHost); | ||
| } | ||
| setVisible(false); | ||
| } | ||
| }); | ||
| getContentPane().add(buttonPanel, BorderLayout.SOUTH); | ||
| setSize(getPreferredSize()); | ||
| setLocation(20, 40); | ||
| setResizable(false); | ||
| } | ||
| public void ask() { | ||
| this.serverTextField.setText(originalHost); | ||
| AgentBootstrapperArgs bootstrapperArgs = agentMacWindow.getBootstrapperArgs(); | ||
| this.serverTextField.setText(bootstrapperArgs.getServerUrl().toString()); | ||
| this.fileBrowser.setFile(bootstrapperArgs.getRootCertFile()); | ||
| this.sslModeComponent.setSslMode(bootstrapperArgs.getSslMode()); | ||
| serverTextField.selectAll(); | ||
| serverTextField.grabFocus(); | ||
| setVisible(true); | ||
| } | ||
| public void setOriginalHost(String originalHost) { | ||
| this.originalHost = originalHost; | ||
| private class FileBrowser extends JPanel { | ||
| private File file; | ||
| private final JTextField textField; | ||
| private final JButton browse; | ||
| FileBrowser() { | ||
| super(); | ||
| setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); | ||
| textField = new JTextField(15); | ||
| textField.setEnabled(false); | ||
| add(textField); | ||
| browse = new JButton("Browse"); | ||
| add(browse); | ||
| browse.addActionListener(new ActionListener() { | ||
| @Override | ||
| public void actionPerformed(ActionEvent e) { | ||
| JFileChooser jFileChooser = new JFileChooser(file != null ? file.getParentFile() : null); | ||
| int returnVal = jFileChooser.showOpenDialog(FileBrowser.this); | ||
| if (returnVal == JFileChooser.APPROVE_OPTION) { | ||
| setFile(jFileChooser.getSelectedFile()); | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| @Override | ||
| public void setEnabled(boolean enabled) { | ||
| super.setEnabled(enabled); | ||
| browse.setEnabled(enabled); | ||
| } | ||
| public File getFile() { | ||
| return file; | ||
| } | ||
| public void setFile(File file) { | ||
| this.file = file; | ||
| if (file != null) { | ||
| textField.setText(file.toString()); | ||
| } | ||
| } | ||
| } | ||
| private class SslModeComponent extends JPanel { | ||
| private AgentBootstrapperArgs.SslMode sslVerificationMode; | ||
| private final JRadioButton fullModeRadioButton; | ||
| private final JRadioButton noneModeRadioButton; | ||
| private final JRadioButton noHostVerifyModeRadioButton; | ||
| SslModeComponent() { | ||
| super(); | ||
| setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); | ||
| fullModeRadioButton = new JRadioButton("Full Verification"); | ||
| fullModeRadioButton.putClientProperty("SSL_MODE", AgentBootstrapperArgs.SslMode.FULL); | ||
| fullModeRadioButton.setToolTipText("Perform a complete SSL verification before connecting to the agent."); | ||
| noneModeRadioButton = new JRadioButton("No verification"); | ||
| noneModeRadioButton.putClientProperty("SSL_MODE", AgentBootstrapperArgs.SslMode.NONE); | ||
| noneModeRadioButton.setToolTipText("Completely disable any SSL verification"); | ||
| noHostVerifyModeRadioButton = new JRadioButton("Don't verify host"); | ||
| noHostVerifyModeRadioButton.putClientProperty("SSL_MODE", AgentBootstrapperArgs.SslMode.NO_VERIFY_HOST); | ||
| noHostVerifyModeRadioButton.setToolTipText("Verify the server certificate, but not the hostname."); | ||
| ButtonGroup sslModeButtonGroup = new ButtonGroup(); | ||
| ActionListener actionListener = new ActionListener() { | ||
| @Override | ||
| public void actionPerformed(ActionEvent e) { | ||
| JRadioButton b = (JRadioButton) e.getSource(); | ||
| setSslMode((AgentBootstrapperArgs.SslMode) b.getClientProperty("SSL_MODE")); | ||
| } | ||
| }; | ||
| for (JRadioButton button : Arrays.asList(fullModeRadioButton, noneModeRadioButton, noHostVerifyModeRadioButton)) { | ||
| sslModeButtonGroup.add(button); | ||
| add(button); | ||
| button.addActionListener(actionListener); | ||
| } | ||
| } | ||
| private void setSslMode(AgentBootstrapperArgs.SslMode sslVerificationMode) { | ||
| switch (sslVerificationMode) { | ||
| case FULL: | ||
| fullModeRadioButton.setSelected(true); | ||
| fileBrowser.setEnabled(true); | ||
| break; | ||
| case NONE: | ||
| noneModeRadioButton.setSelected(true); | ||
| fileBrowser.setEnabled(false); | ||
| break; | ||
| case NO_VERIFY_HOST: | ||
| noHostVerifyModeRadioButton.setSelected(true); | ||
| fileBrowser.setEnabled(true); | ||
| break; | ||
| } | ||
| this.sslVerificationMode = sslVerificationMode; | ||
| } | ||
| public AgentBootstrapperArgs.SslMode getSslMode() { | ||
| return sslVerificationMode; | ||
| } | ||
| } | ||
| } |
| @@ -1,46 +1,39 @@ | ||
| /*************************GO-LICENSE-START********************************* | ||
| * Copyright 2014 ThoughtWorks, Inc. | ||
| /* | ||
| * Copyright 2016 ThoughtWorks, Inc. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| *************************GO-LICENSE-END***********************************/ | ||
| */ | ||
| package com.thoughtworks.go.agent.bootstrapper; | ||
| import java.util.HashSet; | ||
| import java.util.Map; | ||
| import java.util.Set; | ||
| import com.thoughtworks.cruise.agent.common.launcher.AgentLaunchDescriptorKeys; | ||
| import com.thoughtworks.go.agent.common.AgentBootstrapperArgs; | ||
| import org.junit.Test; | ||
| import static org.hamcrest.Matchers.is; | ||
| import static org.junit.Assert.assertThat; | ||
| import java.net.URL; | ||
| import java.util.Map; | ||
| import static org.junit.Assert.assertEquals; | ||
| public class DefaultAgentLaunchDescriptorImplTest { | ||
| @Test | ||
| public void contextShouldContainEnvAndPropertiesAndHostAndPort() throws Exception { | ||
| String hostname = "xx.xx.xx"; | ||
| int port = 20; | ||
| DefaultAgentLaunchDescriptorImpl launchDescriptor = new DefaultAgentLaunchDescriptorImpl(hostname, port, new AgentBootstrapper()); | ||
| AgentBootstrapperArgs bootstrapperArgs = new AgentBootstrapperArgs(new URL("https://" + hostname + ":" + port + "/go"), null, AgentBootstrapperArgs.SslMode.NONE); | ||
| DefaultAgentLaunchDescriptorImpl launchDescriptor = new DefaultAgentLaunchDescriptorImpl(bootstrapperArgs, new AgentBootstrapper()); | ||
| Map context = launchDescriptor.context(); | ||
| assertThat((String) context.get(AgentLaunchDescriptorKeys.HOSTNAME), is(hostname)); | ||
| assertThat((Integer) context.get(AgentLaunchDescriptorKeys.PORT), is(port)); | ||
| Set<String> envkeys = new HashSet<String>(System.getenv().keySet()); | ||
| envkeys.removeAll(context.keySet()); | ||
| assertThat(envkeys.isEmpty(), is(true)); | ||
| Set<Object> propkeys = new HashSet<Object>(System.getProperties().keySet()); | ||
| propkeys.removeAll(context.keySet()); | ||
| assertThat(propkeys.isEmpty(), is(true)); | ||
| assertEquals(context, bootstrapperArgs.toProperties()); | ||
| } | ||
| } |
| @@ -0,0 +1,89 @@ | ||
| /* | ||
| * Copyright 2016 ThoughtWorks, Inc. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package com.thoughtworks.go.agent.common; | ||
| import com.thoughtworks.go.agent.ServerUrlGenerator; | ||
| import com.thoughtworks.go.util.SslVerificationMode; | ||
| import org.apache.commons.logging.Log; | ||
| import org.apache.commons.logging.LogFactory; | ||
| import org.apache.http.client.utils.URIBuilder; | ||
| import java.io.File; | ||
| import java.net.MalformedURLException; | ||
| import java.net.URISyntaxException; | ||
| import java.util.Map; | ||
| import static com.thoughtworks.go.util.ExceptionUtils.bomb; | ||
| public class AgentBootstrapperBackwardCompatibility { | ||
| private static final Log LOG = LogFactory.getLog(AgentBootstrapperBackwardCompatibility.class); | ||
| private final Map context; | ||
| public AgentBootstrapperBackwardCompatibility(Map context) { | ||
| this.context = context; | ||
| } | ||
| public File rootCertFile() { | ||
| return rootCertFileAsString() != null ? new File(rootCertFileAsString()) : null; | ||
| } | ||
| public String rootCertFileAsString() { | ||
| return context.containsKey(AgentBootstrapperArgs.ROOT_CERT_FILE) ? (String) context.get(AgentBootstrapperArgs.ROOT_CERT_FILE) : null; | ||
| } | ||
| public SslVerificationMode sslVerificationMode() { | ||
| try { | ||
| return SslVerificationMode.valueOf((String) context.get(AgentBootstrapperArgs.SSL_VERIFICATION_MODE)); | ||
| } catch (Exception e) { | ||
| LOG.warn("SslVerificationMode could not parsed. Disabling SSL verification."); | ||
| return SslVerificationMode.NONE; | ||
| } | ||
| } | ||
| public ServerUrlGenerator getUrlGenerator() throws MalformedURLException { | ||
| return new UrlConstructor(serverUrl()); | ||
| } | ||
| // Backward compatibility | ||
| // Bootstrappers <= 16.4 are invoked using java -jar agent-bootstrapper.jar 1.2.3.4 [8153] | ||
| // and they stuff "hostname" and "port" in the context, the new bootstrapper stuffs the (ssl) serverUrl directly | ||
| private String serverUrl() { | ||
| if (context.containsKey(AgentBootstrapperArgs.SERVER_URL)) { | ||
| return (String) context.get(AgentBootstrapperArgs.SERVER_URL); | ||
| } else { | ||
| return "http://" + context.get("hostname") + ":" + context.get("port") + "/go"; | ||
| } | ||
| } | ||
| public String sslServerUrl(String sslPort) { | ||
| String serverUrl = serverUrl(); | ||
| try { | ||
| // backward compatibility, since the agent.jar requires an ssl url, but the old bootstrapper does not have one. | ||
| URIBuilder url = new URIBuilder(serverUrl); | ||
| if (url.getScheme().equals("http")) { | ||
| url.setPort(Integer.valueOf(sslPort)); | ||
| url.setScheme("https"); | ||
| } | ||
| return url.toString(); | ||
| } catch (URISyntaxException e) { | ||
| throw bomb(e); | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,40 @@ | ||
| /* | ||
| * Copyright 2016 ThoughtWorks, Inc. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package com.thoughtworks.go.agent.common; | ||
| import com.thoughtworks.go.agent.ServerUrlGenerator; | ||
| import java.net.MalformedURLException; | ||
| public class UrlConstructor implements ServerUrlGenerator { | ||
| private final String serverUrl; | ||
| public UrlConstructor(String serverUrl) throws MalformedURLException { | ||
| if (serverUrl.endsWith("/")) { | ||
| serverUrl = serverUrl.substring(0, serverUrl.length() - 1); | ||
| } | ||
| this.serverUrl = serverUrl; | ||
| } | ||
| public String serverUrlFor(String subPath) { | ||
| if (subPath == null || subPath.trim().length() == 0) { | ||
| return serverUrl; | ||
| } | ||
| return serverUrl + "/" + subPath; | ||
| } | ||
| } |
| @@ -1,25 +1,25 @@ | ||
| /*************************GO-LICENSE-START********************************* | ||
| * Copyright 2014 ThoughtWorks, Inc. | ||
| /* | ||
| * Copyright 2016 ThoughtWorks, Inc. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| *************************GO-LICENSE-END***********************************/ | ||
| */ | ||
| package com.thoughtworks.go.agent.common.launcher; | ||
| import java.util.Map; | ||
| import com.thoughtworks.go.agent.ServerUrlGenerator; | ||
| import java.util.Map; | ||
| public interface AgentProcessParent { | ||
| int run(String launcherVersion, String launcherMd5, ServerUrlGenerator urlGenerator, Map<String, String> env); | ||
| int run(String launcherVersion, String launcherMd5, ServerUrlGenerator urlGenerator, Map<String, String> env, Map context); | ||
| } |
| @@ -0,0 +1,54 @@ | ||
| /* | ||
| * Copyright 2016 ThoughtWorks, Inc. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package com.thoughtworks.go.agent.common; | ||
| import com.thoughtworks.go.util.SslVerificationMode; | ||
| import org.junit.Test; | ||
| import java.io.File; | ||
| import java.net.URL; | ||
| import java.util.HashMap; | ||
| import static org.junit.Assert.assertEquals; | ||
| import static org.junit.Assert.assertNull; | ||
| public class AgentBootstrapperBackwardCompatibilityTest { | ||
| @Test | ||
| public void shouldBeBackwardCompatible() throws Exception { | ||
| HashMap context = new HashMap(); | ||
| context.put("hostname", "ci.example.com"); | ||
| context.put("port", "8153"); | ||
| AgentBootstrapperBackwardCompatibility compatibility = new AgentBootstrapperBackwardCompatibility(context); | ||
| assertNull(compatibility.rootCertFileAsString()); | ||
| assertNull(compatibility.rootCertFile()); | ||
| assertEquals(SslVerificationMode.NONE, compatibility.sslVerificationMode()); | ||
| assertEquals("https://ci.example.com:8154/go", compatibility.sslServerUrl("8154")); | ||
| } | ||
| @Test | ||
| public void shouldReturnCLIArgsIfStuffedInContext() throws Exception { | ||
| AgentBootstrapperArgs args = new AgentBootstrapperArgs(new URL("https://go.example.com:8154/go"), new File("/path/to/certfile"), AgentBootstrapperArgs.SslMode.NO_VERIFY_HOST); | ||
| AgentBootstrapperBackwardCompatibility compatibility = new AgentBootstrapperBackwardCompatibility(args.toProperties()); | ||
| assertEquals("/path/to/certfile", compatibility.rootCertFileAsString()); | ||
| assertEquals(new File("/path/to/certfile"), compatibility.rootCertFile()); | ||
| assertEquals(SslVerificationMode.NO_VERIFY_HOST, compatibility.sslVerificationMode()); | ||
| assertEquals("https://go.example.com:8154/go", compatibility.sslServerUrl("8154")); | ||
| } | ||
| } |
| @@ -1,53 +1,86 @@ | ||
| /*************************GO-LICENSE-START********************************* | ||
| * Copyright 2014 ThoughtWorks, Inc. | ||
| /* | ||
| * Copyright 2016 ThoughtWorks, Inc. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| *************************GO-LICENSE-END***********************************/ | ||
| */ | ||
| package com.thoughtworks.go.agent.launcher; | ||
| import java.util.List; | ||
| import com.thoughtworks.go.agent.testhelper.FakeBootstrapperServer; | ||
| import com.thoughtworks.go.mothers.ServerUrlGeneratorMother; | ||
| import org.apache.commons.httpclient.methods.GetMethod; | ||
| import com.thoughtworks.go.util.SslVerificationMode; | ||
| import org.apache.commons.io.IOUtils; | ||
| import org.apache.http.client.methods.HttpGet; | ||
| import org.junit.Test; | ||
| import org.junit.runner.RunWith; | ||
| import java.io.File; | ||
| import java.util.List; | ||
| import static org.hamcrest.CoreMatchers.containsString; | ||
| import static org.hamcrest.Matchers.equalTo; | ||
| import static org.hamcrest.core.Is.is; | ||
| import static org.junit.Assert.assertThat; | ||
| import static org.junit.Assert.fail; | ||
| @RunWith(FakeBootstrapperServer.class) | ||
| public class ServerCallTest { | ||
| @Test | ||
| public void shouldBeAbleToReadTheResponseBody() throws Exception { | ||
| GetMethod getMethod = new GetMethod(DownloadableFile.AGENT.url(ServerUrlGeneratorMother.generatorFor("localhost", 9090))); | ||
| ServerCall.ServerResponseWrapper response = ServerCall.invoke(getMethod); | ||
| HttpGet getMethod = new HttpGet(DownloadableFile.AGENT.url(ServerUrlGeneratorMother.generatorFor("localhost", 9090))); | ||
| ServerCall.ServerResponseWrapper response = new ServerCall().invoke(getMethod, null, SslVerificationMode.NONE); | ||
| List list = IOUtils.readLines(response.body); | ||
| assertThat(list.isEmpty(), is(false)); | ||
| } | ||
| @Test | ||
| public void shouldThrowSpecifiCExceptionIncaseOf404() throws Exception { | ||
| GetMethod getMethod = new GetMethod("http://localhost:9090/go/not-found"); | ||
| HttpGet getMethod = new HttpGet("http://localhost:9090/go/not-found"); | ||
| try { | ||
| ServerCall.invoke(getMethod); | ||
| new ServerCall().invoke(getMethod, null, SslVerificationMode.NONE); | ||
| fail("Was expecting an exception!"); | ||
| } catch (Exception ex) { | ||
| assertThat(ex.getMessage().contains( | ||
| "This agent might be incompatible with your Go Server." | ||
| + "Please fix the version mismatch between Go Server and Go Agent."), is(true)); | ||
| } | ||
| } | ||
| @Test | ||
| public void shouldConnectToAServerWithACertSignedByAKnownCA() throws Exception { | ||
| ServerCall.ServerResponseWrapper invoke = new ServerCall().invoke(new HttpGet("https://example.com"), null, SslVerificationMode.FULL); | ||
| assertThat(IOUtils.toString(invoke.body), containsString("This domain is established to be used for illustrative examples in documents")); | ||
| } | ||
| @Test | ||
| public void shouldConnectToAnSSLServerWithSelfSignedCertWhenInsecureModeIsInsecure() throws Exception { | ||
| ServerCall.ServerResponseWrapper invoke = new ServerCall().invoke(new HttpGet("https://localhost:9091/go/hello"), null, SslVerificationMode.NONE); | ||
| assertThat(IOUtils.toString(invoke.body).trim(), equalTo("Hello")); | ||
| } | ||
| @Test | ||
| public void shouldConnectToAnSSLServerWithSelfSignedCertWhenInsecureModeIsNoVerifyHost() throws Exception { | ||
| ServerCall.ServerResponseWrapper invoke = new ServerCall().invoke(new HttpGet("https://localhost:9091/go/hello"), new File("testdata/test_cert.pem"), SslVerificationMode.NO_VERIFY_HOST); | ||
| assertThat(IOUtils.toString(invoke.body).trim(), equalTo("Hello")); | ||
| } | ||
| @Test | ||
| public void shouldRaiseExceptionWhenSelfSignedCertDoesNotMatchTheHostName() throws Exception { | ||
| try { | ||
| new ServerCall().invoke(new HttpGet("https://localhost:9091/go/hello"), new File("testdata/test_cert.pem"), SslVerificationMode.FULL); | ||
| fail("Was expecting an exception!"); | ||
| } catch (Exception expected) { | ||
| assertThat(expected.getMessage(), containsString("Host name 'localhost' does not match the certificate subject provided by the peer")); | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,16 @@ | ||
| -----BEGIN CERTIFICATE----- | ||
| MIIDCjCCAfICBX3OuM15MA0GCSqGSIb3DQEBBQUAMEkxGTAXBgNVBAMTEElOanVoaWphcmkubG9j | ||
| YWwxLDAqBgNVBAsTI0NydWlzZSBzZXJ2ZXIgd2Vic2VydmVyIGNlcnRpZmljYXRlMB4XDTcwMDEw | ||
| MTAwMDAwMFoXDTI2MDQxMTEwMTQxMFowSTEZMBcGA1UEAxMQSU5qdWhpamFyaS5sb2NhbDEsMCoG | ||
| A1UECxMjQ3J1aXNlIHNlcnZlciB3ZWJzZXJ2ZXIgY2VydGlmaWNhdGUwggEiMA0GCSqGSIb3DQEB | ||
| AQUAA4IBDwAwggEKAoIBAQCBL8Wn/n8jGOcHzJus22RrM/XqyNq1k11KNqFh5blvIUkLsbmveOSb | ||
| BpCzjnx7CtMB/fXF6VfapMDxF+068V9lOJx79GMbeuGxcU/iQX78sW8oC9TZFqbWUKdLO0MD3OBR | ||
| U2TJKl6wEOmetZU9CfMdWzAKK8jXQjYpVmfInhR5jmmeLf7pcnmhPbRhmyY9JB4PHHYRaT9MRbNu | ||
| lhF2Lhc2+tUIhAmntIhs9hlSadn2ab2+ZqysBs6Y8W/Z0lF7Vv1HaApMgBWidwToFY1iyUwiSwRr | ||
| JVMMp8m0Z/ZA68KtwEmi3PwcxRxnKskpwNCMXCcdhm8gBK+o5qpnzGgRVNfnAgMBAAEwDQYJKoZI | ||
| hvcNAQEFBQADggEBAADB3E9PMuf6ZM6uPxDktZG93wg99JWSU21z1h1DvzXekwKZEt7igYSSSBu1 | ||
| cT2vf0YyIRml8YbvR0beWexajTVxLSHphKj1Cvp0kEQph4e2fs6Ipu+T8ZKN7rPigYEZmciE/sKy | ||
| y9x0Fb0z/fyo6dxP90cfbuutAJ6O/x/ZR4lkCzS9oFJr46/FAYkDQ95LA2Gz95oQZaSncFrtcyj2 | ||
| a9VJoqXE03GMAr7E8o3Ltu2RHykMQzOtbA4EMoIqVFn1i3Z+7V7oxvrS4s7ABFpfEzXbsLUVIH/W | ||
| Pm+TEvFyyO1gsb7TAPubKyP74UCXshr4FzAiFvMQJD5xaoavFDkNanE= | ||
| -----END CERTIFICATE----- |
| @@ -1,37 +1,35 @@ | ||
| /*************************GO-LICENSE-START********************************* | ||
| * Copyright 2014 ThoughtWorks, Inc. | ||
| /* | ||
| * Copyright 2016 ThoughtWorks, Inc. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| *************************GO-LICENSE-END***********************************/ | ||
| */ | ||
| package com.thoughtworks.go.agent.launcher; | ||
| import com.thoughtworks.go.agent.common.UrlConstructor; | ||
| import org.junit.Test; | ||
| import java.net.MalformedURLException; | ||
| import static org.hamcrest.core.Is.is; | ||
| import static org.junit.Assert.assertThat; | ||
| public class UrlConstructorTest { | ||
| @Test | ||
| public void shouldGenerateCorrectUrlForGivenPath() { | ||
| UrlConstructor urlConstructor = new UrlConstructor("localhost", 8080); | ||
| assertThat(urlConstructor.serverUrlFor("foo/bar"), is("http://localhost:8080/go/foo/bar")); | ||
| assertThat(urlConstructor.serverUrlFor("admin/agent"), is("http://localhost:8080/go/admin/agent")); | ||
| } | ||
| @Test | ||
| public void shouldGenerateCorrectServerBaseUrl() { | ||
| UrlConstructor urlConstructor = new UrlConstructor("localhost", 8080); | ||
| assertThat(urlConstructor.serverSslBaseUrl(8443), is("https://localhost:8443/go/")); | ||
| public void shouldGenerateCorrectUrlForGivenPath() throws MalformedURLException { | ||
| UrlConstructor urlConstructor = new UrlConstructor("https://example.com:8443/go/"); | ||
| assertThat(urlConstructor.serverUrlFor(""), is("https://example.com:8443/go")); | ||
| assertThat(urlConstructor.serverUrlFor("foo/bar"), is("https://example.com:8443/go/foo/bar")); | ||
| assertThat(urlConstructor.serverUrlFor("admin/agent"), is("https://example.com:8443/go/admin/agent")); | ||
| } | ||
| } |
| @@ -1,56 +1,42 @@ | ||
| /*************************GO-LICENSE-START********************************* | ||
| * Copyright 2014 ThoughtWorks, Inc. | ||
| /* | ||
| * Copyright 2016 ThoughtWorks, Inc. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| *************************GO-LICENSE-END***********************************/ | ||
| */ | ||
| package com.thoughtworks.go.agent; | ||
| import java.util.regex.Matcher; | ||
| import java.util.regex.Pattern; | ||
| import com.thoughtworks.go.agent.common.AgentBootstrapperArgs; | ||
| import com.thoughtworks.go.agent.common.AgentCLI; | ||
| import com.thoughtworks.go.agent.common.util.LoggingHelper; | ||
| import com.thoughtworks.go.util.GoConstants; | ||
| import com.thoughtworks.go.util.SystemEnvironment; | ||
| import org.springframework.context.support.ClassPathXmlApplicationContext; | ||
| public final class AgentMain { | ||
| private static final String QUOTE = "\""; | ||
| public static void main(String... argv) throws Exception { | ||
| AgentBootstrapperArgs args = new AgentCLI().parse(argv); | ||
| private AgentMain() { | ||
| } | ||
| LoggingHelper.configureLoggerIfNoneExists("go-agent.log", "go-agent-log4j.properties"); | ||
| new SystemEnvironment().setProperty(SystemEnvironment.SERVICE_URL, args.getServerUrl().toString()); | ||
| new SystemEnvironment().setProperty(SystemEnvironment.AGENT_SSL_VERIFICATION_MODE, args.getSslMode().toString()); | ||
| public static void main(String... args) throws Exception { | ||
| if (args.length != 1) { | ||
| throw new RuntimeException( | ||
| "Usage: java -jar agent.jar https://<cruise server hostname>:<cruise server port>/go/"); | ||
| if (args.getRootCertFile() != null) { | ||
| new SystemEnvironment().setProperty(SystemEnvironment.AGENT_ROOT_CERT_FILE, args.getRootCertFile().toString()); | ||
| } | ||
| LoggingHelper.configureLoggerIfNoneExists("go-agent.log", "go-agent-log4j.properties"); | ||
| setServiceUrl(args[0]); | ||
| ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); | ||
| ctx.registerShutdownHook(); | ||
| } | ||
| static void setServiceUrl(String url) { | ||
| String target = String.format(".*(%s/?)$", GoConstants.OLD_URL_CONTEXT); | ||
| Pattern pattern = Pattern.compile(target); | ||
| Matcher matcher = pattern.matcher(url); | ||
| if (matcher.matches()) { | ||
| String context = matcher.group(1); | ||
| url = url.substring(0, url.lastIndexOf(context)) + GoConstants.GO_URL_CONTEXT + "/"; | ||
| } | ||
| new SystemEnvironment().setProperty("serviceUrl", url); | ||
| } | ||
| } |