/**
* Copyright (c) 2008-2016, XebiaLabs B.V., All rights reserved.
*
*
* Overthere is licensed under the terms of the GPLv2
* <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most XebiaLabs Libraries.
* There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
* this software, see the FLOSS License Exception
* <http://github.com/xebialabs/overthere/blob/master/LICENSE>.
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation; version 2
* of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
package com.xebialabs.overthere.winrs;
import com.xebialabs.overthere.*;
import com.xebialabs.overthere.cifs.CifsConnectionType;
import com.xebialabs.overthere.spi.ProcessConnection;
import com.xebialabs.overthere.spi.AddressPortMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import static com.xebialabs.overthere.ConnectionOptions.*;
import static com.xebialabs.overthere.OperatingSystemFamily.WINDOWS;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.*;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_ENABLE_HTTPS;
import static com.xebialabs.overthere.cifs.CifsConnectionBuilder.WINRM_ENABLE_HTTPS_DEFAULT;
import static com.xebialabs.overthere.cifs.ConnectionValidator.checkIsWindowsHost;
import static com.xebialabs.overthere.cifs.ConnectionValidator.checkNoSingleQuoteInPassword;
import static com.xebialabs.overthere.cifs.ConnectionValidator.checkNotThroughJumpstation;
import static com.xebialabs.overthere.smb.SmbConnectionBuilder.SMB_PROTOCOL;
import static com.xebialabs.overthere.util.OverthereUtils.checkArgument;
import static com.xebialabs.overthere.util.OverthereUtils.checkNotNull;
import static com.xebialabs.overthere.util.OverthereUtils.closeQuietly;
import static java.lang.String.format;
import static java.net.InetSocketAddress.createUnresolved;
/**
* A connection to a Windows host using Windows native implementation of WinRM, i.e. the <tt>winrs</tt> command.
*/
public class WinrsConnection implements ProcessConnection {
private OperatingSystemFamily os;
private OverthereFile workingDirectory;
private String address;
private int port;
private String password;
private String username;
private String protocol;
private CifsConnectionType connectionType = CifsConnectionType.WINRM_NATIVE;
private ConnectionOptions options;
private OverthereConnection winrsProxyConnection;
public WinrsConnection(ConnectionOptions options, AddressPortMapper mapper, OverthereFile workingDirectory) {
this.workingDirectory = workingDirectory;
this.options = options;
this.os = options.getEnum(OPERATING_SYSTEM, OperatingSystemFamily.class);
String unmappedAddress = options.get(ADDRESS);
int unmappedPort = options.get(PORT, connectionType.getDefaultPort(options));
InetSocketAddress addressPort = mapper.map(createUnresolved(unmappedAddress, unmappedPort));
this.address = addressPort.getHostName();
this.port = addressPort.getPort();
this.username = options.get(USERNAME);
this.password = options.get(PASSWORD);
this.protocol = options.get(PROTOCOL);
checkIsWindowsHost(os, protocol, connectionType);
checkNotThroughJumpstation(mapper, protocol, connectionType);
checkNoSingleQuoteInPassword(password, protocol, connectionType);
}
@Override
public void connect() {
connectToWinrsProxy(options);
if (winrsProxyConnection.getHostOperatingSystem() != WINDOWS) {
disconnectFromWinrsProxy();
throw new IllegalArgumentException(format("Cannot create a " + SMB_PROTOCOL + ":%s connection with a winrs proxy that is not running Windows", connectionType.toString().toLowerCase()));
}
}
@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, WINRS_NOECHO_DEFAULT)) {
winrsCmd.addArgument("-noecho");
}
if (options.getBoolean(WINRS_NOPROFILE, WINRS_NOPROFILE_DEFAULT)) {
winrsCmd.addArgument("-noprofile");
}
if (options.getBoolean(WINRS_ALLOW_DELEGATE, DEFAULT_WINRS_ALLOW_DELEGATE)) {
winrsCmd.addArgument("-allowdelegate");
}
if (options.getBoolean(WINRS_COMPRESSION, WINRS_COMPRESSION_DEFAULT)) {
winrsCmd.addArgument("-compression");
}
if (options.getBoolean(WINRS_UNENCRYPTED, WINRS_UNENCRYPTED_DEFAULT)) {
winrsCmd.addArgument("-unencrypted");
}
if (options.getBoolean(WINRM_ENABLE_HTTPS, WINRM_ENABLE_HTTPS_DEFAULT)) {
winrsCmd.addArgument("-usessl");
}
winrsCmd.add(cmd.getArguments());
return winrsProxyConnection.startProcess(winrsCmd);
}
@Override
public void close() {
disconnectFromWinrsProxy();
}
@Override
public void setWorkingDirectory(OverthereFile workingDirectory) {
this.workingDirectory = workingDirectory;
}
OverthereConnection connectToWinrsProxy(ConnectionOptions options) {
logger.debug("Connecting to winrs proxy");
String winrsProxyProtocol = options.get(WINRS_PROXY_PROTOCOL, WINRS_PROXY_PROTOCOL_DEFAULT);
ConnectionOptions winrsProxyConnectionOptions = options.get(WINRS_PROXY_CONNECTION_OPTIONS, new ConnectionOptions());
winrsProxyConnection = Overthere.getConnection(winrsProxyProtocol, winrsProxyConnectionOptions);
return winrsProxyConnection;
}
void disconnectFromWinrsProxy() {
logger.debug("Disconnecting from winrs proxy");
closeQuietly(winrsProxyConnection);
}
private static final Logger logger = LoggerFactory.getLogger(WinrsConnection.class);
}