mirror of https://github.com/winsw/winsw
Merge pull request #70 from ebsco/LogonAsAService
Adding logon as a service right to user account specified in configurationpull/75/head
commit
0105fe5214
233
Advapi32.cs
233
Advapi32.cs
|
@ -81,6 +81,162 @@ namespace winsw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class LogonAsAService
|
||||||
|
{
|
||||||
|
public static void AddLogonAsAServiceRight(string Username)
|
||||||
|
{
|
||||||
|
//Needs to be at least XP or 2003 server
|
||||||
|
//https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx
|
||||||
|
System.OperatingSystem osInfo = System.Environment.OSVersion;
|
||||||
|
|
||||||
|
if (osInfo.Version.Major >= 5 && osInfo.Version.Minor >= 1)
|
||||||
|
{
|
||||||
|
var newuser = GetLocalAccountIfLocalAccount(Username);
|
||||||
|
//Trace.WriteLine("Username for Logon as A Service: " + newuser);
|
||||||
|
long rightexitcode = SetRight(newuser, PrivlegeRights.SeServiceLogonRight.ToString());
|
||||||
|
if (rightexitcode != 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Failed to set logon as a service right");
|
||||||
|
Environment.Exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("Cannot set Logon as a Service right. Unsupported operating system detected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetDomain(string s)
|
||||||
|
{
|
||||||
|
int stop = s.IndexOf("\\");
|
||||||
|
if (stop >= 0)
|
||||||
|
return s.Substring(0, stop);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private static string GetLogin(string s)
|
||||||
|
{
|
||||||
|
int stop = s.IndexOf("\\");
|
||||||
|
return (stop > -1) ? s.Substring(stop + 1, s.Length - stop - 1) : s;
|
||||||
|
}
|
||||||
|
private static string GetLocalAccountIfLocalAccount(string username)
|
||||||
|
{
|
||||||
|
var machinename = Environment.MachineName;
|
||||||
|
string domain = GetDomain(username);
|
||||||
|
if (domain == null || domain.ToLower() == machinename.ToLower() || domain == ".")
|
||||||
|
{
|
||||||
|
return GetLogin(username);
|
||||||
|
}
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Adds a privilege to an account</summary>
|
||||||
|
/// <param name="accountName">Name of an account - "domain\account" or only "account"</param>
|
||||||
|
/// <param name="privilegeName">Name ofthe privilege</param>
|
||||||
|
/// <returns>The windows error code returned by LsaAddAccountRights</returns>
|
||||||
|
private static long SetRight(String accountName, String privilegeName)
|
||||||
|
{
|
||||||
|
long winErrorCode = 0; //contains the last error
|
||||||
|
|
||||||
|
//pointer an size for the SID
|
||||||
|
IntPtr sid = IntPtr.Zero;
|
||||||
|
int sidSize = 0;
|
||||||
|
//StringBuilder and size for the domain name
|
||||||
|
StringBuilder domainName = new StringBuilder();
|
||||||
|
int nameSize = 0;
|
||||||
|
//account-type variable for lookup
|
||||||
|
int accountType = 0;
|
||||||
|
|
||||||
|
//get required buffer size
|
||||||
|
Advapi32.LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);
|
||||||
|
|
||||||
|
//allocate buffers
|
||||||
|
domainName = new StringBuilder(nameSize);
|
||||||
|
sid = Marshal.AllocHGlobal(sidSize);
|
||||||
|
|
||||||
|
//lookup the SID for the account
|
||||||
|
bool result = Advapi32.LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize,
|
||||||
|
ref accountType);
|
||||||
|
|
||||||
|
//say what you're doing
|
||||||
|
//Console.WriteLine("LookupAccountName result = " + result);
|
||||||
|
//Console.WriteLine("IsValidSid: " + Advapi32.IsValidSid(sid));
|
||||||
|
//Console.WriteLine("LookupAccountName domainName: " + domainName.ToString());
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
winErrorCode = Kernel32.GetLastError();
|
||||||
|
Console.WriteLine("LookupAccountName failed: " + winErrorCode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
//initialize an empty unicode-string
|
||||||
|
LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING();
|
||||||
|
//combine all policies
|
||||||
|
int access = (int)(
|
||||||
|
LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
|
||||||
|
LSA_AccessPolicy.POLICY_CREATE_ACCOUNT |
|
||||||
|
LSA_AccessPolicy.POLICY_CREATE_PRIVILEGE |
|
||||||
|
LSA_AccessPolicy.POLICY_CREATE_SECRET |
|
||||||
|
LSA_AccessPolicy.POLICY_GET_PRIVATE_INFORMATION |
|
||||||
|
LSA_AccessPolicy.POLICY_LOOKUP_NAMES |
|
||||||
|
LSA_AccessPolicy.POLICY_NOTIFICATION |
|
||||||
|
LSA_AccessPolicy.POLICY_SERVER_ADMIN |
|
||||||
|
LSA_AccessPolicy.POLICY_SET_AUDIT_REQUIREMENTS |
|
||||||
|
LSA_AccessPolicy.POLICY_SET_DEFAULT_QUOTA_LIMITS |
|
||||||
|
LSA_AccessPolicy.POLICY_TRUST_ADMIN |
|
||||||
|
LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
|
||||||
|
LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION
|
||||||
|
);
|
||||||
|
//initialize a pointer for the policy handle
|
||||||
|
IntPtr policyHandle = IntPtr.Zero;
|
||||||
|
|
||||||
|
//these attributes are not used, but LsaOpenPolicy wants them to exists
|
||||||
|
LSA_OBJECT_ATTRIBUTES ObjectAttributes = new LSA_OBJECT_ATTRIBUTES();
|
||||||
|
ObjectAttributes.Length = 0;
|
||||||
|
ObjectAttributes.RootDirectory = IntPtr.Zero;
|
||||||
|
ObjectAttributes.Attributes = 0;
|
||||||
|
ObjectAttributes.SecurityDescriptor = IntPtr.Zero;
|
||||||
|
ObjectAttributes.SecurityQualityOfService = IntPtr.Zero;
|
||||||
|
|
||||||
|
//get a policy handle
|
||||||
|
uint resultPolicy = Advapi32.LsaOpenPolicy(ref systemName, ref ObjectAttributes, access, out policyHandle);
|
||||||
|
winErrorCode = Advapi32.LsaNtStatusToWinError(resultPolicy);
|
||||||
|
|
||||||
|
if (winErrorCode != 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("OpenPolicy failed: " + winErrorCode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Now that we have the SID an the policy,
|
||||||
|
//we can add rights to the account.
|
||||||
|
|
||||||
|
//initialize an unicode-string for the privilege name
|
||||||
|
LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1];
|
||||||
|
userRights[0] = new LSA_UNICODE_STRING();
|
||||||
|
userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName);
|
||||||
|
userRights[0].Length = (UInt16)(privilegeName.Length * UnicodeEncoding.CharSize);
|
||||||
|
userRights[0].MaximumLength = (UInt16)((privilegeName.Length + 1) * UnicodeEncoding.CharSize);
|
||||||
|
|
||||||
|
//add the right to the account
|
||||||
|
uint res = Advapi32.LsaAddAccountRights(policyHandle, sid, userRights, 1);
|
||||||
|
winErrorCode = Advapi32.LsaNtStatusToWinError(res);
|
||||||
|
if (winErrorCode != 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("LsaAddAccountRights failed: " + winErrorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
Advapi32.LsaClose(policyHandle);
|
||||||
|
}
|
||||||
|
Advapi32.FreeSid(sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return winErrorCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Advapi32.dll wrapper for performing additional service related operations that are not
|
/// Advapi32.dll wrapper for performing additional service related operations that are not
|
||||||
/// available in WMI.
|
/// available in WMI.
|
||||||
|
@ -105,10 +261,85 @@ namespace winsw
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
internal static extern bool CloseServiceHandle(IntPtr hSCObject);
|
internal static extern bool CloseServiceHandle(IntPtr hSCObject);
|
||||||
|
|
||||||
[DllImport("ADVAPI32.DLL")]
|
[DllImport("advapi32.DLL")]
|
||||||
internal static extern bool SetServiceStatus(IntPtr hServiceStatus, ref SERVICE_STATUS lpServiceStatus);
|
internal static extern bool SetServiceStatus(IntPtr hServiceStatus, ref SERVICE_STATUS lpServiceStatus);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", PreserveSig = true)]
|
||||||
|
internal static extern UInt32 LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, Int32 DesiredAccess,
|
||||||
|
out IntPtr PolicyHandle);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
|
||||||
|
internal static extern uint LsaAddAccountRights(IntPtr PolicyHandle, IntPtr AccountSid, LSA_UNICODE_STRING[] UserRights, uint CountOfRights);
|
||||||
|
|
||||||
|
[DllImport("advapi32")]
|
||||||
|
internal static extern void FreeSid(IntPtr pSid);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
|
||||||
|
internal static extern bool LookupAccountName(string lpSystemName, string lpAccountName, IntPtr psid, ref int cbsid, StringBuilder domainName,
|
||||||
|
ref int cbdomainLength, ref int use);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll")]
|
||||||
|
internal static extern bool IsValidSid(IntPtr pSid);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", SetLastError = true)]
|
||||||
|
internal static extern uint LsaClose(IntPtr ObjectHandle);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", SetLastError = false)]
|
||||||
|
internal static extern uint LsaNtStatusToWinError(uint status);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671(v=vs.85).aspx
|
||||||
|
internal enum PrivlegeRights
|
||||||
|
{
|
||||||
|
SeServiceLogonRight, //Required for an account to log on using the service logon type.
|
||||||
|
SeRemoteInteractiveLogonRight, //Required for an account to log on remotely using the interactive logon type.
|
||||||
|
SeNetworkLogonRight, //Required for an account to log on using the network logon type.
|
||||||
|
SeInteractiveLogonRight, //Required for an account to log on using the interactive logon type.
|
||||||
|
SeDenyServiceLogonRight, //Explicitly denies an account the right to log on using the service logon type.
|
||||||
|
SeDenyRemoteInteractiveLogonRight, //Explicitly denies an account the right to log on remotely using the interactive logon type.
|
||||||
|
SeDenyNetworkLogonRight, //Explicitly denies an account the right to log on using the network logon type.
|
||||||
|
SeDenyInteractiveLogonRight, //Explicitly denies an account the right to log on using the interactive logon type.
|
||||||
|
SeDenyBatchLogonRight, //Explicitly denies an account the right to log on using the batch logon type.
|
||||||
|
SeBatchLogonRight //Required for an account to log on using the batch logon type.
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
struct LSA_UNICODE_STRING
|
||||||
|
{
|
||||||
|
public UInt16 Length;
|
||||||
|
public UInt16 MaximumLength;
|
||||||
|
public IntPtr Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
struct LSA_OBJECT_ATTRIBUTES
|
||||||
|
{
|
||||||
|
public int Length;
|
||||||
|
public IntPtr RootDirectory;
|
||||||
|
public LSA_UNICODE_STRING ObjectName;
|
||||||
|
public UInt32 Attributes;
|
||||||
|
public IntPtr SecurityDescriptor;
|
||||||
|
public IntPtr SecurityQualityOfService;
|
||||||
|
}
|
||||||
|
|
||||||
|
// enum all policies
|
||||||
|
enum LSA_AccessPolicy : long
|
||||||
|
{
|
||||||
|
POLICY_VIEW_LOCAL_INFORMATION = 0x00000001L,
|
||||||
|
POLICY_VIEW_AUDIT_INFORMATION = 0x00000002L,
|
||||||
|
POLICY_GET_PRIVATE_INFORMATION = 0x00000004L,
|
||||||
|
POLICY_TRUST_ADMIN = 0x00000008L,
|
||||||
|
POLICY_CREATE_ACCOUNT = 0x00000010L,
|
||||||
|
POLICY_CREATE_SECRET = 0x00000020L,
|
||||||
|
POLICY_CREATE_PRIVILEGE = 0x00000040L,
|
||||||
|
POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080L,
|
||||||
|
POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100L,
|
||||||
|
POLICY_AUDIT_LOG_ADMIN = 0x00000200L,
|
||||||
|
POLICY_SERVER_ADMIN = 0x00000400L,
|
||||||
|
POLICY_LOOKUP_NAMES = 0x00000800L,
|
||||||
|
POLICY_NOTIFICATION = 0x00001000L
|
||||||
|
}
|
||||||
|
|
||||||
internal enum SCM_ACCESS : uint
|
internal enum SCM_ACCESS : uint
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace winsw
|
||||||
[In] ref STARTUPINFO lpStartupInfo,
|
[In] ref STARTUPINFO lpStartupInfo,
|
||||||
out PROCESS_INFORMATION lpProcessInformation);
|
out PROCESS_INFORMATION lpProcessInformation);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
internal static extern int GetLastError();
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
|
16
Main.cs
16
Main.cs
|
@ -549,6 +549,7 @@ namespace winsw
|
||||||
if (args[0] == "install")
|
if (args[0] == "install")
|
||||||
{
|
{
|
||||||
string username=null, password=null;
|
string username=null, password=null;
|
||||||
|
bool setallowlogonasaserviceright = false;
|
||||||
if (args.Count > 1 && args[1] == "/p")
|
if (args.Count > 1 && args[1] == "/p")
|
||||||
{
|
{
|
||||||
// we expected username/password on stdin
|
// we expected username/password on stdin
|
||||||
|
@ -556,6 +557,14 @@ namespace winsw
|
||||||
username = Console.ReadLine();
|
username = Console.ReadLine();
|
||||||
Console.Write("Password: ");
|
Console.Write("Password: ");
|
||||||
password = ReadPassword();
|
password = ReadPassword();
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.Write("Set Account rights to allow log on as a service (y/n)?: ");
|
||||||
|
var keypressed = Console.ReadKey();
|
||||||
|
Console.WriteLine();
|
||||||
|
if (keypressed.Key == ConsoleKey.Y)
|
||||||
|
{
|
||||||
|
setallowlogonasaserviceright = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -563,9 +572,15 @@ namespace winsw
|
||||||
{
|
{
|
||||||
username = d.ServiceAccountUser;
|
username = d.ServiceAccountUser;
|
||||||
password = d.ServiceAccountPassword;
|
password = d.ServiceAccountPassword;
|
||||||
|
setallowlogonasaserviceright = d.AllowServiceAcountLogonRight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (setallowlogonasaserviceright)
|
||||||
|
{
|
||||||
|
LogonAsAService.AddLogonAsAServiceRight(username);
|
||||||
|
}
|
||||||
|
|
||||||
svc.Create (
|
svc.Create (
|
||||||
d.Id,
|
d.Id,
|
||||||
d.Caption,
|
d.Caption,
|
||||||
|
@ -699,6 +714,5 @@ namespace winsw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,8 +278,11 @@ It is possible to specify the useraccount (and password) that the service will r
|
||||||
<domain>YOURDOMAIN</domain>
|
<domain>YOURDOMAIN</domain>
|
||||||
<user>useraccount</user>
|
<user>useraccount</user>
|
||||||
<password>Pa55w0rd</password>
|
<password>Pa55w0rd</password>
|
||||||
|
<allowservicelogon>true</allowservicelogon>
|
||||||
</serviceaccount>
|
</serviceaccount>
|
||||||
|
|
||||||
|
The <allowservicelogon> is optional. If set to true, will automatically set the "Allow Log On As A Service" right to the listed account.
|
||||||
|
|
||||||
### Working directory
|
### Working directory
|
||||||
Some services need to run with a working directory specified. To do this, specify a `<workingdirectory>` element like this:
|
Some services need to run with a working directory specified. To do this, specify a `<workingdirectory>` element like this:
|
||||||
|
|
||||||
|
|
|
@ -540,6 +540,14 @@ namespace winsw
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected string AllowServiceLogon
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetServiceAccountPart("allowservicelogon");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected string serviceAccountDomain
|
protected string serviceAccountDomain
|
||||||
{
|
{
|
||||||
get{
|
get{
|
||||||
|
@ -573,6 +581,22 @@ namespace winsw
|
||||||
return !string.IsNullOrEmpty(serviceAccountDomain) && !string.IsNullOrEmpty(serviceAccountName);
|
return !string.IsNullOrEmpty(serviceAccountDomain) && !string.IsNullOrEmpty(serviceAccountName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AllowServiceAcountLogonRight
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (AllowServiceLogon != null)
|
||||||
|
{
|
||||||
|
bool parsedvalue = false;
|
||||||
|
if (Boolean.TryParse(AllowServiceLogon, out parsedvalue))
|
||||||
|
{
|
||||||
|
return parsedvalue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time to wait for the service to gracefully shutdown before we forcibly kill it
|
/// Time to wait for the service to gracefully shutdown before we forcibly kill it
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace winswTests
|
||||||
private const string Username = "User";
|
private const string Username = "User";
|
||||||
private const string Password = "Password";
|
private const string Password = "Password";
|
||||||
private const string Domain = "Domain";
|
private const string Domain = "Domain";
|
||||||
|
private const string AllowServiceAccountLogonRight = "true";
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public void SetUp()
|
||||||
|
@ -32,6 +33,7 @@ namespace winswTests
|
||||||
+ "<domain>" + Domain + "</domain>"
|
+ "<domain>" + Domain + "</domain>"
|
||||||
+ "<user>" + Username + "</user>"
|
+ "<user>" + Username + "</user>"
|
||||||
+ "<password>" + Password + "</password>"
|
+ "<password>" + Password + "</password>"
|
||||||
|
+ "<allowservicelogon>" + AllowServiceAccountLogonRight + "</allowservicelogon>"
|
||||||
+ "</serviceaccount>"
|
+ "</serviceaccount>"
|
||||||
+ "<workingdirectory>"
|
+ "<workingdirectory>"
|
||||||
+ ExpectedWorkingDirectory
|
+ ExpectedWorkingDirectory
|
||||||
|
@ -48,6 +50,12 @@ namespace winswTests
|
||||||
Assert.That(extendedServiceDescriptor.WorkingDirectory, Is.EqualTo(ExpectedWorkingDirectory));
|
Assert.That(extendedServiceDescriptor.WorkingDirectory, Is.EqualTo(ExpectedWorkingDirectory));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void VerifyServiceLogonRight()
|
||||||
|
{
|
||||||
|
Assert.That(extendedServiceDescriptor.AllowServiceAcountLogonRight, Is.EqualTo(true));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void VerifyUsername()
|
public void VerifyUsername()
|
||||||
{
|
{
|
||||||
|
@ -153,5 +161,33 @@ namespace winswTests
|
||||||
Assert.That(logHandler.Period, Is.EqualTo(7));
|
Assert.That(logHandler.Period, Is.EqualTo(7));
|
||||||
Assert.That(logHandler.Pattern, Is.EqualTo("log pattern"));
|
Assert.That(logHandler.Pattern, Is.EqualTo("log pattern"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void VerifyServiceLogonRightGraceful()
|
||||||
|
{
|
||||||
|
const string SeedXml="<service>"
|
||||||
|
+ "<serviceaccount>"
|
||||||
|
+ "<domain>" + Domain + "</domain>"
|
||||||
|
+ "<user>" + Username + "</user>"
|
||||||
|
+ "<password>" + Password + "</password>"
|
||||||
|
+ "<allowservicelogon>true1</allowservicelogon>"
|
||||||
|
+ "</serviceaccount>"
|
||||||
|
+ "</service>";
|
||||||
|
var serviceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
||||||
|
Assert.That(serviceDescriptor.AllowServiceAcountLogonRight, Is.EqualTo(false));
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void VerifyServiceLogonRightOmitted()
|
||||||
|
{
|
||||||
|
const string SeedXml = "<service>"
|
||||||
|
+ "<serviceaccount>"
|
||||||
|
+ "<domain>" + Domain + "</domain>"
|
||||||
|
+ "<user>" + Username + "</user>"
|
||||||
|
+ "<password>" + Password + "</password>"
|
||||||
|
+ "</serviceaccount>"
|
||||||
|
+ "</service>";
|
||||||
|
var serviceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
||||||
|
Assert.That(serviceDescriptor.AllowServiceAcountLogonRight, Is.EqualTo(false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue