Add support of authentication in the download operation (#194)

Issue #126 - Add support of authentication in the download settings
pull/195/head
Torsten 2017-04-11 22:37:44 +02:00 committed by Oleg Nenashev
parent 1b93f81752
commit 5803d3ce15
3 changed files with 109 additions and 2 deletions

View File

@ -147,8 +147,29 @@ This feature should be used only for debugging, as some operating systems and ha
This optional element can be specified multiple times to have the service wrapper retrieve resources from URL and place it locally as a file. This optional element can be specified multiple times to have the service wrapper retrieve resources from URL and place it locally as a file.
This operation runs when the service is started, before the application specified by `<executable>` is launched. This operation runs when the service is started, before the application specified by `<executable>` is launched.
For servers requiring authentication some parameters must be specified depending on the type of authentication. Only the basic authentication requires additional sub-parameters. Supported authentication types are:
* `none`: default, must not be specified
* `sspi`: Microsoft [authentication](https://en.wikipedia.org/wiki/Security_Support_Provider_Interface) including Kerberos, NTLM etc.
* `basic`: Basic authentication, sub-parameters:
* `username=“UserName”`
* `password=“Passw0rd”`
* `unsecureAuth=“enabled”: default=“disabled"`
The parameter “unsecureAuth” is only effective when the transfer protocol is HTTP - unencrypted data transfer. This is a security vulnerability because the credentials are send in clear text! For a SSPI authentication this is not relevant because the authentication tokens are encrypted.
For target servers using the HTTPS transfer protocol it is necessary, that the CA which issued the server certificate is trusted by the client. This is normally the situation when the server ist located in the Internet. When an organisation is using a self issued CA for the intranet this probably is not the case. In this case it is necessary to import the CA to the Certificate MMC of the Windows client. Have a look to the instructions on this [site](https://msdn.microsoft.com/de-de/library/system.net.credentialcache.defaultcredentials(v=vs.85).aspx). The self issued CA must be imported to the Trusted Root Certification Authorities for the computer.
``` ```
<download from="http://example.com/some.dat" to="%BASE%\some.dat"/> <download from="http://example.com/some.dat" to="%BASE%\some.dat" />
<download from="https://example.com/some.dat" to="%BASE%\some.dat" auth="sspi" />
<download from="https://example.com/some.dat" to="%BASE%\some.dat"
auth="basic" username="aUser" password="aPassw0rd" />
<download from="http://example.com/some.dat" to="%BASE%\some.dat"
auth="basic" unsecureAuth=“enabled”
username="aUser" password=“aPassw0rd" />
``` ```
This is another useful building block for developing a self-updating service. This is another useful building block for developing a self-updating service.

View File

@ -252,6 +252,18 @@ SECTION: Environment setup
<!-- <!--
<download from="http://www.google.com/" to="%BASE%\index.html" /> <download from="http://www.google.com/" to="%BASE%\index.html" />
<download from="http://www.nosuchhostexists.com/" to="%BASE%\dummy.html" /> <download from="http://www.nosuchhostexists.com/" to="%BASE%\dummy.html" />
An example for unsecure Basic authentication because the connection is not encrypted:
<download from="http://example.com/some.dat" to="%BASE%\some.dat"
auth="basic" unsecureAuth=“enabled”
username="aUser" password=“aPassw0rd" />
Secure Basic authentication via HTTPS:
<download from="https://example.com/some.dat" to="%BASE%\some.dat"
auth="basic" username="aUser" password="aPassw0rd" />
Secure authentication when the target server and the client are members of domain:
<download from="https://example.com/some.dat" to="%BASE%\some.dat" auth="sspi" />
--> -->
<!-- <!--

76
src/Core/WinSWCore/Download.cs Executable file → Normal file
View File

@ -1,6 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Text;
using System.Xml; using System.Xml;
namespace winsw namespace winsw
@ -11,18 +12,91 @@ namespace winsw
/// </summary> /// </summary>
public class Download public class Download
{ {
public enum AuthType { none = 0, sspi, basic }
public readonly string From; public readonly string From;
public readonly string To; public readonly string To;
public readonly AuthType Auth = AuthType.none;
public readonly string Username;
public readonly string Password;
public readonly bool UnsecureAuth = false;
internal Download(XmlNode n) internal Download(XmlNode n)
{ {
From = Environment.ExpandEnvironmentVariables(n.Attributes["from"].Value); From = Environment.ExpandEnvironmentVariables(n.Attributes["from"].Value);
To = Environment.ExpandEnvironmentVariables(n.Attributes["to"].Value); To = Environment.ExpandEnvironmentVariables(n.Attributes["to"].Value);
string tmpStr = "";
try
{
tmpStr = Environment.ExpandEnvironmentVariables(n.Attributes["auth"].Value);
}
catch (Exception)
{
}
Auth = tmpStr != "" ? (AuthType)Enum.Parse(typeof(AuthType), tmpStr) : AuthType.none;
try
{
tmpStr = Environment.ExpandEnvironmentVariables(n.Attributes["username"].Value);
}
catch (Exception)
{
}
Username = tmpStr;
try
{
tmpStr = Environment.ExpandEnvironmentVariables(n.Attributes["password"].Value);
}
catch (Exception)
{
}
Password = tmpStr;
try
{
tmpStr = Environment.ExpandEnvironmentVariables(n.Attributes["unsecureAuth"].Value);
}
catch (Exception)
{
}
UnsecureAuth = tmpStr == "enabled" ? true : false;
if (Auth == AuthType.basic)
{
if (From.StartsWith("http:") && UnsecureAuth == false)
{
throw new Exception("Warning: you're sending your credentials in clear text to the server. If you really want this you must enable this in the configuration!");
}
}
}
// Source: http://stackoverflow.com/questions/2764577/forcing-basic-authentication-in-webrequest
public void SetBasicAuthHeader(WebRequest request, String username, String password)
{
string authInfo = username + ":" + password;
authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(authInfo));
request.Headers["Authorization"] = "Basic " + authInfo;
} }
public void Perform() public void Perform()
{ {
WebRequest req = WebRequest.Create(From); WebRequest req = WebRequest.Create(From);
switch (Auth)
{
case AuthType.sspi:
req.UseDefaultCredentials = true;
req.PreAuthenticate = true;
req.Credentials = CredentialCache.DefaultCredentials;
break;
case AuthType.basic:
SetBasicAuthHeader(req, Username, Password);
break;
}
WebResponse rsp = req.GetResponse(); WebResponse rsp = req.GetResponse();
FileStream tmpstream = new FileStream(To + ".tmp", FileMode.Create); FileStream tmpstream = new FileStream(To + ".tmp", FileMode.Create);
CopyStream(rsp.GetResponseStream(), tmpstream); CopyStream(rsp.GetResponseStream(), tmpstream);