Skip to content

Commit

Permalink
Implemented of WINRM_NATIVE (winrs) connection type. Fixes #12.
Browse files Browse the repository at this point in the history
The old, Java-based WINRM connection type has been renamed to WINRM_INTERNAL.
  • Loading branch information
Vincent Partington committed Oct 24, 2013
1 parent a6f7a31 commit afd6820
Show file tree
Hide file tree
Showing 11 changed files with 415 additions and 110 deletions.
97 changes: 75 additions & 22 deletions README.md

Large diffs are not rendered by default.

40 changes: 20 additions & 20 deletions src/main/java/com/xebialabs/overthere/cifs/CifsConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,6 @@
*/
package com.xebialabs.overthere.cifs;

import static com.xebialabs.overthere.ConnectionOptions.ADDRESS;
import static com.xebialabs.overthere.ConnectionOptions.PASSWORD;
import static com.xebialabs.overthere.ConnectionOptions.PORT;
import static com.xebialabs.overthere.ConnectionOptions.USERNAME;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.CIFS_PORT;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.CONNECTION_TYPE;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_CIFS_PORT;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_TELNET_PORT;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRM_ENABLE_HTTPS;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRM_HTTPS_PORT;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRM_HTTP_PORT;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.PATH_SHARE_MAPPINGS;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.PATH_SHARE_MAPPINGS_DEFAULT;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_ENABLE_HTTPS;
import static java.net.InetSocketAddress.createUnresolved;

import java.io.IOException;
import java.net.InetSocketAddress;

Expand All @@ -54,6 +38,22 @@
import com.xebialabs.overthere.spi.AddressPortMapper;
import com.xebialabs.overthere.spi.BaseOverthereConnection;

import static com.xebialabs.overthere.ConnectionOptions.ADDRESS;
import static com.xebialabs.overthere.ConnectionOptions.PASSWORD;
import static com.xebialabs.overthere.ConnectionOptions.PORT;
import static com.xebialabs.overthere.ConnectionOptions.USERNAME;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.CIFS_PORT;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.CONNECTION_TYPE;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_CIFS_PORT;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_TELNET_PORT;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRM_ENABLE_HTTPS;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRM_HTTPS_PORT;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRM_HTTP_PORT;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.PATH_SHARE_MAPPINGS;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.PATH_SHARE_MAPPINGS_DEFAULT;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_ENABLE_HTTPS;
import static java.net.InetSocketAddress.createUnresolved;

/**
* Base class for connections to a Windows host using CIFS.
*
Expand Down Expand Up @@ -111,11 +111,11 @@ private int getDefaultPort(ConnectionOptions options) {
switch (cifsConnectionType) {
case TELNET:
return DEFAULT_TELNET_PORT;
case WINRM:
case WINRM_INTERNAL:
case WINRM_NATIVE:
if (!options.getBoolean(WINRM_ENABLE_HTTPS, DEFAULT_WINRM_ENABLE_HTTPS)) {
return DEFAULT_WINRM_HTTP_PORT;
}
else {
} else {
return DEFAULT_WINRM_HTTPS_PORT;
}
default:
Expand Down Expand Up @@ -157,7 +157,7 @@ protected OverthereFile getFileForTempFile(OverthereFile parent, String name) {
private String encodeAsSmbUrl(String hostPath) {
try {
String smbUrl = encoder.toSmbUrl(hostPath);
logger.trace("Encoded Windows host path {} to SMB URL {}", hostPath, maskSmbUrl(smbUrl));
logger.trace("Encoded Windows host path [{}] to SMB URL [{}]", hostPath, maskSmbUrl(smbUrl));
return smbUrl;
} catch (IllegalArgumentException exception) {
throw new RuntimeIOException(exception);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,24 @@
*/
package com.xebialabs.overthere.cifs;

import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.CIFS_PROTOCOL;
import static com.xebialabs.overthere.cifs.WinrmHttpsCertificateTrustStrategy.STRICT;
import static com.xebialabs.overthere.cifs.WinrmHttpsHostnameVerificationStrategy.BROWSER_COMPATIBLE;

import java.util.Map;

import com.google.common.collect.ImmutableMap;

import com.xebialabs.overthere.ConnectionOptions;
import com.xebialabs.overthere.OverthereConnection;
import com.xebialabs.overthere.cifs.telnet.CifsTelnetConnection;
import com.xebialabs.overthere.cifs.winrm.CifsWinRmConnection;
import com.xebialabs.overthere.cifs.winrs.CifsWinrsConnection;
import com.xebialabs.overthere.spi.AddressPortMapper;
import com.xebialabs.overthere.spi.OverthereConnectionBuilder;
import com.xebialabs.overthere.spi.Protocol;

import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.CIFS_PROTOCOL;
import static com.xebialabs.overthere.cifs.WinrmHttpsCertificateTrustStrategy.STRICT;
import static com.xebialabs.overthere.cifs.WinrmHttpsHostnameVerificationStrategy.BROWSER_COMPATIBLE;
import static com.xebialabs.overthere.local.LocalConnection.LOCAL_PROTOCOL;

/**
* Builds CIFS connections.
*/
Expand Down Expand Up @@ -211,6 +214,79 @@ public class CifsConnectionBuilder implements OverthereConnectionBuilder {
*/
public static final String DEFAULT_WINRM_TIMEOUT = "PT60.000S";

/**
* Connection option (Boolean) that specifies whether to allow the user's credentials to be passed to the remote
* host. Corresponds to the <code>winrs</code> command option <code>-noprofile</code>.
*/
public static final String WINRS_ALLOW_DELEGATE = "winrsAllowDelegate";

/**
* Default value (<code>false</code>) for the connection option used to specify whether to allow the user's
* credentials to be passed to the remote machine
*/
public static final boolean DEFAULT_WINRS_ALLOW_DELEGATE = false;

/**
* Connection option (Boolean) that specifies whether to enable compression. Corresponds to the <code>winrs</code>
* command option <code>-compression</code>.
*/
public static final String WINRS_COMPRESSION = "winrsCompression";

/**
* Default value (<code>false</code>) for the connection option used to specify whether to enable compression.
*/
public static final boolean DEFAULT_WINRS_COMPRESSION = false;

/**
* Connection option (Boolean) that specifies whether to disable echo. Corresponds to the <code>winrs</code> command
* option <code>-noecho</code>.
*/
public static final String WINRS_NOECHO = "winrsNoecho";

/**
* Default value (<code>false</code>) for the connection option used to specify whether to disable echo.
*/
public static final boolean DEFAULT_WINRS_NOECHO = false;

/**
* Connection option (Boolean) that specifies whether to disable loading the user profile before executing the
* command. Corresponds to the <code>winrs</code> command option <code>-noprofile</code>.
*/
public static final String WINRS_NOPROFILE = "winrsNoprofile";

/**
* Default value (<code>false</code>) for the connection option used to specify whether to disable loading the user
* profile before executing the command.
*/
public static final boolean DEFAULT_WINRS_NOPROFILE = false;

/**
* Connection option (Boolean) that specifies whether to disable encryption. Corresponds to the <code>winrs</code>
* command option <code>-unencrypted</code>.
*/
public static final String WINRS_UNENCRYPTED = "winrsUnencrypted";

/**
* Default value (<code>false</code>) for the connection option used to specify whether to disable encryption.
*/
public static final boolean DEFAULT_WINRS_UNENCRYPTED = false;

/**
* Connection option (String) that specifies the protocol for the "winrs proxy".
*/
public static final String WINRS_PROXY_PROTOCOL = "winrsProxyProtocol";

/**
* Default value (<code>local</code>) for the connection option that specifies the protocol for the "winrs proxy".
*/
public static final String DEFAULT_WINRS_PROXY_PROTOCOL = LOCAL_PROTOCOL;

/**
* Connection option (<code>ConnectionOptions</code>) that specifies the {@link ConnectionOptions connection
* options} to be used for the "winrs proxy".
*/
public static final String WINRS_PROXY_CONNECTION_OPTIONS = "winrsProxyConnectionOptions";

private OverthereConnection connection;

public CifsConnectionBuilder(String type, ConnectionOptions options, AddressPortMapper mapper) {
Expand All @@ -220,9 +296,12 @@ public CifsConnectionBuilder(String type, ConnectionOptions options, AddressPort
case TELNET:
connection = new CifsTelnetConnection(type, options, mapper);
break;
case WINRM:
case WINRM_INTERNAL:
connection = new CifsWinRmConnection(type, options, mapper);
break;
case WINRM_NATIVE:
connection = new CifsWinrsConnection(type, options, mapper);
break;
default:
throw new IllegalArgumentException("Unknown CIFS connection type " + cifsConnectionType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,19 @@
public enum CifsConnectionType {

/**
* A CIFS connection that uses Telnet to execute commands, to a Windows host.
* A CIFS connection to a Windows host that uses Telnet to execute commands.
*/
TELNET,

/**
* A CIFS connection that uses WinRM to execute commands, to a Windows host.
* A CIFS connection to a Windows host that uses a Java implementation WinRM to execute commands.
*/
WINRM,
WINRM_INTERNAL,

/**
* A CIFS connection to a Windows host that uses the <code>winrs</code> command native to Windows to execute commands.
* <em>N.B.:</em> This implementation only works when Overthere runs on Windows.
*/
WINRM_NATIVE

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import java.net.URL;

import com.google.common.io.Closeables;

import com.xebialabs.overthere.CmdLine;
import com.xebialabs.overthere.ConnectionOptions;
import com.xebialabs.overthere.Overthere;
Expand Down Expand Up @@ -233,7 +232,7 @@ public synchronized int exitValue() {
}

private WinRmClient createWinrmClient() {
final WinRmClient client = new WinRmClient(username, password, createTargetURL(options), unmappedAddress, unmappedPort);
final WinRmClient client = new WinRmClient(username, password, createWinrmURL(), unmappedAddress, unmappedPort);
client.setWinRmTimeout(options.get(WINRM_TIMEMOUT, DEFAULT_WINRM_TIMEOUT));
client.setWinRmEnvelopSize(options.get(WINRM_ENVELOP_SIZE, DEFAULT_WINRM_ENVELOP_SIZE));
client.setWinRmLocale(options.get(WINRM_LOCALE, DEFAULT_WINRM_LOCALE));
Expand All @@ -245,7 +244,7 @@ private WinRmClient createWinrmClient() {
return client;
}

private URL createTargetURL(ConnectionOptions options) {
private URL createWinrmURL() {
final String scheme = options.getBoolean(WINRM_ENABLE_HTTPS, DEFAULT_WINRM_ENABLE_HTTPS) ? "https" : "http";
final String context = options.get(WINRM_CONTEXT, DEFAULT_WINRM_CONTEXT);
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package com.xebialabs.overthere.cifs.winrs;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xebialabs.overthere.CmdLine;
import com.xebialabs.overthere.ConnectionOptions;
import com.xebialabs.overthere.Overthere;
import com.xebialabs.overthere.OverthereConnection;
import com.xebialabs.overthere.OverthereProcess;
import com.xebialabs.overthere.cifs.CifsConnection;
import com.xebialabs.overthere.spi.AddressPortMapper;
import com.xebialabs.overthere.util.DefaultAddressPortMapper;

import static java.lang.String.format;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.io.Closeables.closeQuietly;
import static com.xebialabs.overthere.OperatingSystemFamily.WINDOWS;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.CIFS_PROTOCOL;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRM_ENABLE_HTTPS;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRS_ALLOW_DELEGATE;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRS_COMPRESSION;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRS_NOECHO;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRS_NOPROFILE;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRS_PROXY_PROTOCOL;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.DEFAULT_WINRS_UNENCRYPTED;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_ENABLE_HTTPS;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRS_ALLOW_DELEGATE;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRS_COMPRESSION;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRS_NOECHO;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRS_NOPROFILE;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRS_PROXY_CONNECTION_OPTIONS;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRS_PROXY_PROTOCOL;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRS_UNENCRYPTED;

public class CifsWinrsConnection extends CifsConnection {

private ConnectionOptions options;

private OverthereConnection winrsProxyConnection;

public CifsWinrsConnection(String type, ConnectionOptions options, AddressPortMapper mapper) {
super(type, options, mapper, true);
checkArgument(os == WINDOWS, "Cannot start a " + CIFS_PROTOCOL + ":%s connection to a machine that is not running Windows", cifsConnectionType.toString().toLowerCase());
checkArgument(!username.contains("\\"), "Cannot start a " + CIFS_PROTOCOL + ":%s connection with an old-style Windows domain account [%s], use USER@DOMAIN instead.", cifsConnectionType.toString().toLowerCase(), username);
checkArgument(mapper instanceof DefaultAddressPortMapper, "Cannot create a " + CIFS_PROTOCOL + ":%s connection when connecting through a SSH jumpstation", cifsConnectionType.toString().toLowerCase());

this.options = options;

connectToWinrsProxy(options);

if(winrsProxyConnection.getHostOperatingSystem() != WINDOWS) {
disconnectFromWinrsProxy();
throw new IllegalArgumentException(format("Cannot create a " + CIFS_PROTOCOL + ":%s connection with a winrs proxy that is not running Windows", cifsConnectionType.toString().toLowerCase()));
}
}

@Override
public void doClose() {
disconnectFromWinrsProxy();
}

private void connectToWinrsProxy(ConnectionOptions options) {
logger.debug("Connecting to winrs proxy");

String winrsProxyProtocol = options.get(WINRS_PROXY_PROTOCOL, DEFAULT_WINRS_PROXY_PROTOCOL);
ConnectionOptions winrsProxyConnectionOptions = options.get(WINRS_PROXY_CONNECTION_OPTIONS, new ConnectionOptions());
winrsProxyConnection = Overthere.getConnection(winrsProxyProtocol, winrsProxyConnectionOptions);
}

private void disconnectFromWinrsProxy() {
logger.debug("Disconnecting from winrs proxy");

closeQuietly(winrsProxyConnection);
}

@Override
public OverthereProcess startProcess(final CmdLine cmd) {
checkNotNull(cmd, "Cannot execute null command line");
checkArgument(cmd.getArguments().size() > 0, "Cannot execute empty command line");

final String obfuscatedCmd = cmd.toCommandLine(os, true);
logger.info("Starting command [{}] on [{}]", obfuscatedCmd, this);

final CmdLine winrsCmd = new CmdLine();
winrsCmd.addArgument("winrs");
winrsCmd.addArgument("-remote:" + address + ":" + port);
winrsCmd.addArgument("-username:" + username);
winrsCmd.addPassword("-password:" + password);
if (workingDirectory != null) {
winrsCmd.addArgument("-directory:" + workingDirectory.getPath());
}
if (options.getBoolean(WINRS_NOECHO, DEFAULT_WINRS_NOECHO)) {
winrsCmd.addArgument("-noecho");
}
if (options.getBoolean(WINRS_NOPROFILE, DEFAULT_WINRS_NOPROFILE)) {
winrsCmd.addArgument("-noprofile");
}
if (options.getBoolean(WINRS_ALLOW_DELEGATE, DEFAULT_WINRS_ALLOW_DELEGATE)) {
winrsCmd.addArgument("-allowdelegate");
}
if (options.getBoolean(WINRS_COMPRESSION, DEFAULT_WINRS_COMPRESSION)) {
winrsCmd.addArgument("-compression");
}
if (options.getBoolean(WINRS_UNENCRYPTED, DEFAULT_WINRS_UNENCRYPTED)) {
winrsCmd.addArgument("-unencrypted");
}
if (options.getBoolean(WINRM_ENABLE_HTTPS, DEFAULT_WINRM_ENABLE_HTTPS)) {
winrsCmd.addArgument("-usessl");
}
winrsCmd.add(cmd.getArguments());

return winrsProxyConnection.startProcess(winrsCmd);
}

private static final Logger logger = LoggerFactory.getLogger(CifsWinrsConnection.class);

}
Loading

0 comments on commit afd6820

Please sign in to comment.