Merge pull request #386 from dmilov/topic/dmilov/SsoAdminModule

PowerShell Module for managing VMware vSphere SSO Admin functionality
This commit is contained in:
dmilov
2020-10-05 10:50:25 +03:00
committed by GitHub
53 changed files with 26638 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
# PowerCLI Example module for managing vSphere SSO Admin
This module is combination of .NET binary libraries for accessing vSphere SSO Admin API and PowerShell advanced functions exposing cmdlet-like interface to the SSO Admin features.<br/>
<br/>
The module supports PowerShell 5.1 and PowerShell 7.0 and above.<br/>
# Using the module
The module can be used without the '/src' directory. The '/src' directory contains the source code of the module.<br/>
This module depends on PowerCLI 'VMware.VimAutomation.Common', Version 12.0 module<br/>
# Using the source code
## '/src' directory
This directory contains the .NET binaries sources code and Pester integration tests that cover both the binaries and the module advanced functions functionality.<br/>
## Required build tools
- PowerShell 7.0<br/>
- dotnet sdk<br/>
## Required test tools
- PowerShell 7.0
- PowerCLI 12.0<br/>
- Pester 4.8.1<br/>
## '/src/build.ps1' script
The script builds the binaries and publishes them to the 'net45' and 'netcoreapp2.0' directories of the module.<br/>
It has also the option to run module Pester tests. The optional parameters for VC server and credentials has to be specified in order the script to run the tests. Tests run in separate PowreShell process because PowerShell has to load the module binaries which are build output.<br/>
## '/src/test/RunTests.ps1' script
This script can be used to run the tests<br/>

View File

@@ -0,0 +1,47 @@
#
# Module manifest for module 'VMware.vSphere.SsoAdmin'
#
# Generated by: dmilov@vmware.com
#
# Generated on: 9/25/20
@{
# Script module or binary module file associated with this manifest
RootModule = 'VMware.vSphere.SsoAdmin.psm1'
# Version number of this module.
ModuleVersion = '1.0.0'
# ID used to uniquely identify this module
GUID = 'b3e25326-e809-4d68-a252-ca5fcaf1eb8b'
# Author of this module
Author = 'Dimitar Milov'
# Company or vendor of this module
CompanyName = 'VMware, Inc.'
# Copyright statement for this module
Copyright = 'Copyright (c) VMware, Inc. All rights reserved.'
# Description of the functionality provided by this module
Description = 'PowerShell Module for Managing VMware vSphere SSO Admin functionality.'
# Modules that must be imported into the global environment prior to importing this module
RequiredModules = @(
@{"ModuleName"="VMware.VimAutomation.Common";"ModuleVersion"="12.0.0.15939652"}
)
# Functions to export from this module
FunctionsToExport = @('Connect-SsoAdminServer', 'Disconnect-SsoAdminServer', 'New-SsoPersonUser', 'Get-SsoPersonUser', 'Set-SsoPersonUser', 'Remove-SsoPersonUser', 'Get-SsoGroup', 'Get-SsoPasswordPolicy', 'Set-SsoPasswordPolicy', 'Get-SsoLockoutPolicy', 'Set-SsoLockoutPolicy', 'Get-SsoTokenLifetime', 'Set-SsoTokenLifetime', 'Add-ActiveDirectoryIdentitySource')
# Cmdlets to export from this module
CmdletsToExport = @()
# Variables to export from this module
VariablesToExport = ''
# Aliases to export from this module
AliasesToExport = '*'
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,86 @@
#
# Module manifest for module 'VMware.vSphere.SsoAdmin'
#
# Generated by: dmilov@vmware.com
#
# Generated on: 9/25/20
@{
# Version number of this module.
ModuleVersion = '1.0.0'
# ID used to uniquely identify this module
GUID = 'dd2b1928-e8ee-4c3a-a364-1caec6d3bd58'
# Author of this module
Author = 'Dimitar Milov'
# Company or vendor of this module
CompanyName = 'VMware, Inc.'
# Copyright statement for this module
Copyright = 'Copyright (c) VMware, Inc. All rights reserved.'
# Description of the functionality provided by this module
Description = 'PowerShell Module for Managing VMware vSphere SSO Admin functionality.'
# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '5.1'
# Name of the Windows PowerShell host required by this module
PowerShellHostName = ''
# Minimum version of the Windows PowerShell host required by this module
PowerShellHostVersion = ''
# Minimum version of the .NET Framework required by this module
DotNetFrameworkVersion = '4.5'
# Minimum version of the common language runtime (CLR) required by this module
CLRVersion = '4.0'
# Processor architecture (None, X86, Amd64, IA64) required by this module
ProcessorArchitecture = ''
# Assemblies that must be loaded prior to importing this module
RequiredAssemblies = @(
'VMware.vSphere.SsoAdmin.Utils.dll',
'VMware.vSphere.SsoAdminClient.dll',
'VMware.vSphere.LsClient.dll'
)
# Script files (.ps1) that are run in the caller's environment prior to importing this module
# ScriptsToProcess = @()
# Type files (.ps1xml) to be loaded when importing this module
# TypesToProcess = @()
# Format files (.ps1xml) to be loaded when importing this module
#FormatsToProcess = 'VMware.vSphere.SsoAdmin.Format.ps1xml'
# Modules to import as nested modules of the module specified in ModuleToProcess
#NestedModules= @()
# Functions to export from this module
FunctionsToExport = '*'
# Cmdlets to export from this module
CmdletsToExport = '*'
# Variables to export from this module
VariablesToExport = '*'
# Aliases to export from this module
AliasesToExport = '*'
# List of all modules packaged with this module
ModuleList = @()
# List of all files packaged with this module
FileList = ''
# Private data to pass to the module specified in ModuleToProcess
PrivateData = ''
}

View File

@@ -0,0 +1,83 @@
#
# Module manifest for module 'VMware.vSphere.SsoAdmin'
#
# Generated by: dmilov@vmware.com
#
# Generated on: 9/25/20
@{
# Version number of this module.
ModuleVersion = '1.0.0'
# ID used to uniquely identify this module
GUID = '29f1ed8b-311a-4ea1-80a6-0f3ec56e8259'
# Author of this module
Author = 'Dimitar Milov'
# Company or vendor of this module
CompanyName = 'VMware, Inc.'
# Copyright statement for this module
Copyright = 'Copyright (c) VMware, Inc. All rights reserved.'
# Description of the functionality provided by this module
Description = 'PowerShell Module for Managing VMware vSphere SSO Admin functionality.'
# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '6.0.1'
# Specifies the compatible PSEditions of the module.
CompatiblePSEditions = @('Core')
# Name of the Windows PowerShell host required by this module
PowerShellHostName = ''
# Minimum version of the Windows PowerShell host required by this module
PowerShellHostVersion = ''
# Processor architecture (None, X86, Amd64, IA64) required by this module
ProcessorArchitecture = ''
# Assemblies that must be loaded prior to importing this module
RequiredAssemblies = @(
'VMware.vSphere.SsoAdmin.Utils.dll',
'VMware.vSphere.SsoAdminClient.dll',
'VMware.vSphere.LsClient.dll'
)
# Script files (.ps1) that are run in the caller's environment prior to importing this module
# ScriptsToProcess = @()
# Type files (.ps1xml) to be loaded when importing this module
# TypesToProcess = @()
# Format files (.ps1xml) to be loaded when importing this module
#FormatsToProcess = 'VMware.vSphere.SsoAdmin.Format.ps1xml'
# Modules to import as nested modules of the module specified in ModuleToProcess
#NestedModules= @()
# Functions to export from this module
FunctionsToExport = '*'
# Cmdlets to export from this module
CmdletsToExport = '*'
# Variables to export from this module
VariablesToExport = '*'
# Aliases to export from this module
AliasesToExport = '*'
# List of all modules packaged with this module
ModuleList = @()
# List of all files packaged with this module
FileList = ''
# Private data to pass to the module specified in ModuleToProcess
PrivateData = ''
}

View File

@@ -0,0 +1,3 @@
**/.vs
**/bin
**/obj

View File

@@ -0,0 +1,5 @@
<configuration>
<packageSources>
<add key="LocalPackages" value="packages" />
</packageSources>
</configuration>

View File

@@ -0,0 +1,24 @@
{
"ProviderId": "Microsoft.VisualStudio.ConnectedService.Wcf",
"Version": "15.0.20628.921",
"ExtendedData": {
"Uri": "https://10.23.80.205/lookupservice/wsdl/lookup.wsdl",
"Namespace": "LookupServiceReference",
"SelectedAccessLevelForGeneratedClass": "Public",
"GenerateMessageContract": false,
"ReuseTypesinReferencedAssemblies": true,
"ReuseTypesinAllReferencedAssemblies": true,
"CollectionTypeReference": {
"Item1": "System.Array",
"Item2": "System.Runtime.dll"
},
"DictionaryCollectionTypeReference": {
"Item1": "System.Collections.Generic.Dictionary`2",
"Item2": "System.Collections.dll"
},
"CheckedReferencedAssemblies": [],
"InstanceId": null,
"Name": "LookupServiceReference",
"Metadata": {}
}
}

View File

@@ -0,0 +1,136 @@
// **************************************************************************
// Copyright 2020 VMware, Inc.
// **************************************************************************
using System;
using System.Collections;
using System.Collections.Generic;
using System.IdentityModel.Selectors;
using System.Linq;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Security;
using System.Text;
using LookupServiceReference;
namespace VMware.vSphere.LsClient
{
public class LookupServiceClient {
private const int WEB_OPERATION_TIMEOUT_SECONDS = 30;
private LsPortTypeClient _lsClient;
private static readonly ManagedObjectReference RootMoRef = new ManagedObjectReference
{
type = "LookupServiceInstance",
Value = "ServiceInstance"
};
public LookupServiceClient(string hostname, X509CertificateValidator serverCertificateValidator) {
var lsUri = $"https://{hostname}/lookupservice/sdk";
_lsClient = new LsPortTypeClient(GetBinding(), new EndpointAddress(new Uri(lsUri)));
var serverAuthentication = GetServerAuthentication(serverCertificateValidator);
if (serverAuthentication != null)
{
_lsClient
.ChannelFactory
.Credentials
.ServiceCertificate
.SslCertificateAuthentication = serverAuthentication;
}
}
#region Private Helpers
private X509ServiceCertificateAuthentication GetServerAuthentication(X509CertificateValidator serverCertificateValidator)
{
if (serverCertificateValidator != null) {
return new X509ServiceCertificateAuthentication {
CertificateValidationMode = X509CertificateValidationMode.Custom,
CustomCertificateValidator = serverCertificateValidator
};
}
// Default .NET behavior for TLS certificate validation
return null;
}
private static MessageEncodingBindingElement GetWcfEncoding()
{
return new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
}
private static HttpsTransportBindingElement GetWcfTransport(bool useSystemProxy)
{
HttpsTransportBindingElement transport = new HttpsTransportBindingElement
{
RequireClientCertificate = false
};
transport.UseDefaultWebProxy = useSystemProxy;
transport.MaxBufferSize = 2147483647;
transport.MaxReceivedMessageSize = 2147483647;
return transport;
}
private static Binding GetBinding() {
var binding = new CustomBinding(GetWcfEncoding(), GetWcfTransport(true));
var timeout = TimeSpan.FromSeconds(WEB_OPERATION_TIMEOUT_SECONDS);
binding.CloseTimeout = timeout;
binding.OpenTimeout = timeout;
binding.ReceiveTimeout = timeout;
binding.SendTimeout = timeout;
return binding;
}
#endregion
public Uri GetSsoAdminEndpointUri() {
var product = "com.vmware.cis";
var endpointType = "com.vmware.cis.cs.identity.admin";
var type = "sso:admin";
return FindServiceEndpoint(product, type, endpointType);
}
public Uri GetStsEndpointUri() {
var product = "com.vmware.cis";
var type = "cs.identity";
var endpointType = "com.vmware.cis.cs.identity.sso";
return FindServiceEndpoint(product, type, endpointType);
}
private Uri FindServiceEndpoint(string product, string type, string endpointType) {
Uri result = null;
var svcContent = _lsClient.RetrieveServiceContentAsync(RootMoRef).Result;
var filterCriteria = new LookupServiceRegistrationFilter() {
searchAllSsoDomains = true,
serviceType = new LookupServiceRegistrationServiceType {
product = product,
type = type
}
};
var lsRegInfo = _lsClient.
ListAsync(svcContent.serviceRegistration, filterCriteria)
.Result?
.returnval?
.FirstOrDefault();
if (lsRegInfo != null) {
var registrationEndpooint = lsRegInfo.
serviceEndpoints?.
Where(a => a.endpointType.type == endpointType)?.
FirstOrDefault<LookupServiceRegistrationEndpoint>();
if (registrationEndpooint != null) {
result = new Uri(registrationEndpooint.url);
}
}
return result;
}
}
}

View File

@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>VMware.vSphere.LsClient</RootNamespace>
<AssemblyName>VMware.vSphere.LsClient</AssemblyName>
<Description>vSphere Lookup Service API client.</Description>
<TargetFrameworks>net45;netcoreapp2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
<Reference Include="System.IdentityModel" />
<PackageReference Include="System.ServiceModel.Primitives" Version="4.4.0" />
<PackageReference Include="System.ServiceModel.Duplex" Version="4.4.0" />
<PackageReference Include="System.ServiceModel.Http" Version="4.4.0" />
<PackageReference Include="System.ServiceModel.NetTcp" Version="4.4.0" />
<PackageReference Include="System.ServiceModel.Security" Version="4.4.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.0'">
<PackageReference Include="VMware.System.Private.ServiceModel" Version="4.4.4" />
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Connected Services" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,43 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30503.244
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VMware.vSphere.SsoAdminClient", "VMware.vSphere.SsoAdminClient\VMware.vSphere.SsoAdminClient.csproj", "{BD48E0DD-4048-48FD-B0BE-560E2417A2CC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VMware.vSphere.LsClient", "VMware.vSphere.LsClient\VMware.vSphere.LsClient.csproj", "{EEC4C335-3E6C-4FA5-84CD-CBADCD720F35}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VMware.vSphere.SsoAdmin.Utils", "VMware.vSphere.SsoAdmin.Utils\VMware.vSphere.SsoAdmin.Utils.csproj", "{1523743E-C01E-4D37-845F-0BB8DAF9EE7E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VMware.vSphere.SsoAdminClient.Tests", "VMware.vSphere.SsoAdminClient.Tests\VMware.vSphere.SsoAdminClient.Tests.csproj", "{90E6C4A6-FDB4-43FC-B156-ADBCF2B85CCE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BD48E0DD-4048-48FD-B0BE-560E2417A2CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD48E0DD-4048-48FD-B0BE-560E2417A2CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD48E0DD-4048-48FD-B0BE-560E2417A2CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD48E0DD-4048-48FD-B0BE-560E2417A2CC}.Release|Any CPU.Build.0 = Release|Any CPU
{EEC4C335-3E6C-4FA5-84CD-CBADCD720F35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EEC4C335-3E6C-4FA5-84CD-CBADCD720F35}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EEC4C335-3E6C-4FA5-84CD-CBADCD720F35}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EEC4C335-3E6C-4FA5-84CD-CBADCD720F35}.Release|Any CPU.Build.0 = Release|Any CPU
{1523743E-C01E-4D37-845F-0BB8DAF9EE7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1523743E-C01E-4D37-845F-0BB8DAF9EE7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1523743E-C01E-4D37-845F-0BB8DAF9EE7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1523743E-C01E-4D37-845F-0BB8DAF9EE7E}.Release|Any CPU.Build.0 = Release|Any CPU
{90E6C4A6-FDB4-43FC-B156-ADBCF2B85CCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{90E6C4A6-FDB4-43FC-B156-ADBCF2B85CCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90E6C4A6-FDB4-43FC-B156-ADBCF2B85CCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90E6C4A6-FDB4-43FC-B156-ADBCF2B85CCE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9A376526-4487-43FF-A527-E34AD4764F12}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,20 @@
// **************************************************************************
// Copyright 2020 VMware, Inc.
// **************************************************************************
using System;
using System.IdentityModel.Selectors;
using System.Security.Cryptography.X509Certificates;
namespace VMware.vSphere.SsoAdmin.Utils
{
public class AcceptAllX509CertificateValidator : X509CertificateValidator
{
public override void Validate(X509Certificate2 certificate) {
// Check that there is a certificate.
if (certificate == null) {
throw new ArgumentNullException(nameof(certificate));
}
}
}
}

View File

@@ -0,0 +1,38 @@
// **************************************************************************
// Copyright 2020 VMware, Inc.
// **************************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Security;
using System.Text;
using System.Threading.Tasks;
namespace VMware.vSphere.SsoAdmin.Utils
{
public class StirngToSecureStringArgumentTransformationAttribute : ArgumentTransformationAttribute
{
private static class SecureStringConverter
{
public static SecureString ToSecureString(string value) {
var result = new SecureString();
foreach (var c in value.ToCharArray()) {
result.AppendChar(c);
}
return result;
}
}
public override object Transform(EngineIntrinsics engineIntrinsics, object inputData) {
object result = inputData;
if (inputData is string s) {
result = SecureStringConverter.ToSecureString(s);
}
return result;
}
}
}

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>VMware.vSphere.SsoAdmin.Utils</RootNamespace>
<AssemblyName>VMware.vSphere.SsoAdmin.Utils</AssemblyName>
<Description>vSphere Lookup SsoAdmin utility types.</Description>
<TargetFrameworks>net45;netcoreapp2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
<Reference Include="System.IdentityModel" />
<PackageReference Include="System.ServiceModel.Primitives" Version="4.4.0" />
<PackageReference Include="System.ServiceModel.Duplex" Version="4.4.0" />
<PackageReference Include="System.ServiceModel.Http" Version="4.4.0" />
<PackageReference Include="System.ServiceModel.NetTcp" Version="4.4.0" />
<PackageReference Include="System.ServiceModel.Security" Version="4.4.0" />
<PackageReference Include="Microsoft.PowerShell.5.ReferenceAssemblies" Version="1.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.0'">
<PackageReference Include="Microsoft.WSMan.Runtime" Version="6.1.0" />
<PackageReference Include="VMware.System.Private.ServiceModel" Version="4.4.4" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,268 @@
// **************************************************************************
// Copyright 2020 VMware, Inc.
// **************************************************************************
using NUnit.Framework;
using System.Linq;
using System.Security;
using VMware.vSphere.SsoAdmin.Utils;
using VMware.vSphere.SsoAdminClient.DataTypes;
namespace VMware.vSphere.SsoAdminClient.Tests
{
public class Tests
{
private string _vc = "<vc>";
private string _user = "<user>";
private string _rawPassword = "<password>";
private SecureString _password;
[SetUp]
public void Setup() {
_password = new SecureString();
foreach (char c in _rawPassword) {
_password.AppendChar(c);
}
}
[Test]
public void AddRemoveLocalUser() {
// Arrange
var ssoAdminClient = new SsoAdminClient(_vc, _user, _password, new AcceptAllX509CertificateValidator());
var expectedUserName = "test-user2";
var expectedPassword = "te$tPa$sW0rd";
var expectedDescription = "test-description";
var expectedEmail = "testuse@testdomain.loc";
var expectedFirstName = "Test";
var expectedLastName = "User";
// Act Create User
var actual = ssoAdminClient.CreateLocalUser(
expectedUserName,
expectedPassword,
expectedDescription,
expectedEmail,
expectedFirstName,
expectedLastName);
// Assert Created User
Assert.AreEqual(expectedUserName, actual.Name);
Assert.AreEqual(expectedDescription, actual.Description);
Assert.AreEqual(expectedEmail, actual.EmailAddress);
Assert.AreEqual(expectedFirstName, actual.FirstName);
Assert.AreEqual(expectedLastName, actual.LastName);
// Act Delete User
ssoAdminClient.DeleteLocalUser(
actual);
}
[Test]
public void GetAllLocalOsUsers() {
// Arrange
var ssoAdminClient = new SsoAdminClient(_vc, _user, _password, new AcceptAllX509CertificateValidator());
// Act
var actual = ssoAdminClient.GetLocalUsers("", "localos").ToArray();
// Assert
Assert.NotNull(actual);
Assert.Greater(actual.Length, 0);
}
[Test]
public void GetRootLocalOsUsers() {
// Arrange
var ssoAdminClient = new SsoAdminClient(_vc, _user, _password, new AcceptAllX509CertificateValidator());
// Act
var actual = ssoAdminClient.GetLocalUsers("root", "localos").ToArray();
// Assert
Assert.NotNull(actual);
Assert.AreEqual(1, actual.Length);
Assert.AreEqual("root", actual[0].Name);
Assert.AreEqual("localos", actual[0].Domain);
}
[Test]
public void GetRootLocalOsGroups() {
// Arrange
var ssoAdminClient = new SsoAdminClient(_vc, _user, _password, new AcceptAllX509CertificateValidator());
// Act
var actual = ssoAdminClient.GetGroups("", "localos").ToArray();
// Assert
Assert.NotNull(actual);
Assert.Greater(actual.Length, 1);
Assert.AreEqual("localos", actual[0].Domain);
}
[Test]
public void AddRemoveUserFromGroup() {
// Arrange
var ssoAdminClient = new SsoAdminClient(_vc, _user, _password, new AcceptAllX509CertificateValidator());
var expectedUserName = "test-user5";
var expectedPassword = "te$tPa$sW0rd";
var newUser = ssoAdminClient.CreateLocalUser(
expectedUserName,
expectedPassword);
var group = ssoAdminClient.GetGroups("administrators", newUser.Domain).FirstOrDefault<Group>();
// Act
var addActual = ssoAdminClient.AddPersonUserToGroup(newUser, group);
var removeActual = ssoAdminClient.RemovePersonUserFromGroup(newUser, group);
// Assert
Assert.IsTrue(addActual);
Assert.IsTrue(removeActual);
// Cleanup
ssoAdminClient.DeleteLocalUser(
newUser);
}
[Test]
public void ResetUserPassword() {
// Arrange
var ssoAdminClient = new SsoAdminClient(_vc, _user, _password, new AcceptAllX509CertificateValidator());
var expectedUserName = "test-user6";
var expectedPassword = "te$tPa$sW0rd";
var updatePassword = "TE$tPa$sW0rd";
var newUser = ssoAdminClient.CreateLocalUser(
expectedUserName,
expectedPassword);
// Act
// Assert
Assert.DoesNotThrow(() => {
ssoAdminClient.ResetPersonUserPassword(newUser, updatePassword);
});
// Cleanup
ssoAdminClient.DeleteLocalUser(
newUser);
}
[Test]
public void GetPasswordPolicy() {
// Arrange
var ssoAdminClient = new SsoAdminClient(_vc, _user, _password, new AcceptAllX509CertificateValidator());
// Act
var actual = ssoAdminClient.GetPasswordPolicy();
// Assert
Assert.NotNull(actual);
}
[Test]
public void SetPasswordPolicy() {
// Arrange
var ssoAdminClient = new SsoAdminClient(_vc, _user, _password, new AcceptAllX509CertificateValidator());
var originalPasswordPolicy = ssoAdminClient.GetPasswordPolicy();
var expectedDescription = "TestDescription";
var expectedProhibitedPreviousPasswordsCount = originalPasswordPolicy.ProhibitedPreviousPasswordsCount + 1;
var expectedMinLength = originalPasswordPolicy.MinLength + 1;
var expectedMaxLength = originalPasswordPolicy.MaxLength + 1;
var exptectedMaxIdenticalAdjacentCharacters = originalPasswordPolicy.MaxIdenticalAdjacentCharacters + 1;
var expectedMinNumericCount = originalPasswordPolicy.MinNumericCount + 1;
var expectedMinSpecialCharCount = originalPasswordPolicy.MinSpecialCharCount + 1;
var expectedMinAlphabeticCount = originalPasswordPolicy.MinAlphabeticCount + 2;
var expectedMinUppercaseCount = 0;
var expectedMinLowercaseCount = originalPasswordPolicy.MinLowercaseCount + 2;
var expectedPasswordLifetimeDays = originalPasswordPolicy.PasswordLifetimeDays - 2;
// Act
var actual = ssoAdminClient.SetPasswordPolicy(
description: expectedDescription,
prohibitedPreviousPasswordsCount: expectedProhibitedPreviousPasswordsCount,
minLength: expectedMinLength,
maxLength: expectedMaxLength,
maxIdenticalAdjacentCharacters: exptectedMaxIdenticalAdjacentCharacters,
minNumericCount: expectedMinNumericCount,
minSpecialCharCount: expectedMinSpecialCharCount,
minAlphabeticCount: expectedMinAlphabeticCount,
minUppercaseCount: expectedMinUppercaseCount,
minLowercaseCount: expectedMinLowercaseCount,
passwordLifetimeDays: expectedPasswordLifetimeDays);
// Assert
Assert.NotNull(actual);
Assert.AreEqual(expectedDescription, actual.Description);
Assert.AreEqual(expectedProhibitedPreviousPasswordsCount, actual.ProhibitedPreviousPasswordsCount);
Assert.AreEqual(expectedMinLength, actual.MinLength);
Assert.AreEqual(expectedMaxLength, actual.MaxLength);
Assert.AreEqual(exptectedMaxIdenticalAdjacentCharacters, actual.MaxIdenticalAdjacentCharacters);
Assert.AreEqual(expectedMinNumericCount, actual.MinNumericCount);
Assert.AreEqual(expectedMinAlphabeticCount, actual.MinAlphabeticCount);
Assert.AreEqual(expectedMinUppercaseCount, actual.MinUppercaseCount);
Assert.AreEqual(expectedMinLowercaseCount, actual.MinLowercaseCount);
Assert.AreEqual(expectedPasswordLifetimeDays, actual.PasswordLifetimeDays);
// Cleanup
ssoAdminClient.SetPasswordPolicy(
description: originalPasswordPolicy.Description,
prohibitedPreviousPasswordsCount: originalPasswordPolicy.ProhibitedPreviousPasswordsCount,
minLength: originalPasswordPolicy.MinLength,
maxLength: originalPasswordPolicy.MaxLength,
maxIdenticalAdjacentCharacters: originalPasswordPolicy.MaxIdenticalAdjacentCharacters,
minNumericCount: originalPasswordPolicy.MinNumericCount,
minSpecialCharCount: originalPasswordPolicy.MinSpecialCharCount,
minAlphabeticCount: originalPasswordPolicy.MinAlphabeticCount,
minUppercaseCount: originalPasswordPolicy.MinUppercaseCount,
minLowercaseCount: originalPasswordPolicy.MinLowercaseCount,
passwordLifetimeDays: originalPasswordPolicy.PasswordLifetimeDays);
}
[Test]
public void GetLockoutPolicy() {
// Arrange
var ssoAdminClient = new SsoAdminClient(_vc, _user, _password, new AcceptAllX509CertificateValidator());
// Act
var actual = ssoAdminClient.GetLockoutPolicy();
// Assert
Assert.NotNull(actual);
}
[Test]
public void SetLockoutPolicy() {
// Arrange
var ssoAdminClient = new SsoAdminClient(_vc, _user, _password, new AcceptAllX509CertificateValidator());
var originalLockoutPolicy = ssoAdminClient.GetLockoutPolicy();
var expectedDescription = "TestDescription";
var expectedAutoUnlockIntervalSec = 20;
var expectedFailedAttemptIntervalSec = 30;
var expectedMaxFailedAttempts = 5;
// Act
var actual = ssoAdminClient.SetLockoutPolicy(
expectedDescription,
expectedAutoUnlockIntervalSec,
expectedFailedAttemptIntervalSec,
expectedMaxFailedAttempts);
// Assert
Assert.NotNull(actual);
Assert.AreEqual(expectedDescription, actual.Description);
Assert.AreEqual(expectedAutoUnlockIntervalSec, actual.AutoUnlockIntervalSec);
Assert.AreEqual(expectedFailedAttemptIntervalSec, actual.FailedAttemptIntervalSec);
Assert.AreEqual(expectedMaxFailedAttempts, actual.MaxFailedAttempts);
// Cleanup
ssoAdminClient.SetLockoutPolicy(
originalLockoutPolicy.Description,
originalLockoutPolicy.AutoUnlockIntervalSec,
originalLockoutPolicy.FailedAttemptIntervalSec,
originalLockoutPolicy.MaxFailedAttempts
);
}
}
}

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VMware.vSphere.SsoAdmin.Utils\VMware.vSphere.SsoAdmin.Utils.csproj" />
<ProjectReference Include="..\VMware.vSphere.SsoAdminClient\VMware.vSphere.SsoAdminClient.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,21 @@
// **************************************************************************
// Copyright 2020 VMware, Inc.
// **************************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VMware.vSphere.SsoAdminClient.DataTypes
{
public class Group
{
public string Name { get; set; }
public string Domain { get; set; }
public override string ToString() {
return $"{Name}@{Domain}";
}
}
}

View File

@@ -0,0 +1,30 @@
// **************************************************************************
// Copyright 2020 VMware, Inc.
// **************************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Security;
using System.Text;
using System.Threading.Tasks;
namespace VMware.vSphere.SsoAdminClient.DataTypes
{
public class LockoutPolicy
{
SsoAdminClient _client;
public LockoutPolicy(SsoAdminClient client) {
_client = client;
}
public SsoAdminClient GetClient() {
return _client;
}
public string Description { get; set; }
public long AutoUnlockIntervalSec { get; set; }
public long FailedAttemptIntervalSec { get; set; }
public int MaxFailedAttempts { get; set; }
}
}

View File

@@ -0,0 +1,36 @@
// **************************************************************************
// Copyright 2020 VMware, Inc.
// **************************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VMware.vSphere.SsoAdminClient.DataTypes
{
public class PasswordPolicy
{
SsoAdminClient _client;
public PasswordPolicy(SsoAdminClient client) {
_client = client;
}
public string Description { get; set; }
public int ProhibitedPreviousPasswordsCount { get; set; }
public int MinLength { get; set; }
public int MaxLength { get; set; }
public int MinNumericCount { get; set; }
public int MinSpecialCharCount { get; set; }
public int MaxIdenticalAdjacentCharacters { get; set; }
public int MinAlphabeticCount { get; set; }
public int MinUppercaseCount { get; set; }
public int MinLowercaseCount { get; set; }
public int PasswordLifetimeDays { get; set; }
public SsoAdminClient GetClient() {
return _client;
}
}
}

View File

@@ -0,0 +1,34 @@
// **************************************************************************
// Copyright 2020 VMware, Inc.
// **************************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VMware.vSphere.SsoAdminClient.DataTypes
{
public class PersonUser
{
SsoAdminClient _client;
public PersonUser(SsoAdminClient client) {
_client = client;
}
public string Name { get; set; }
public string Domain { get; set; }
public string Description { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public SsoAdminClient GetClient() {
return _client;
}
public override string ToString() {
return $"{Name}@{Domain}";
}
}
}

View File

@@ -0,0 +1,74 @@
// **************************************************************************
// Copyright 2020 VMware, Inc.
// **************************************************************************
using System;
using System.Collections.Generic;
using System.IdentityModel.Selectors;
using System.Linq;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using VMware.Binding.Sts.StsService;
namespace VMware.vSphere.SsoAdminClient.DataTypes
{
public class SsoAdminServer {
private SsoAdminClient _client;
public SsoAdminServer(string hostname,
string user,
SecureString password,
X509CertificateValidator serverCertificateValidator) {
Name = hostname;
_client = new SsoAdminClient(
hostname,
user,
password,
serverCertificateValidator);
Id = $"/SsoAdminServer={NormalizeUserName()}@{Name}";
}
private string NormalizeUserName() {
string result = User;
if (User.Contains('@')) {
var parts = User.Split('@');
var userName = parts[0];
var domain = parts[1];
result = $"{domain}/{userName}";
}
return result;
}
public string Name { get; }
public Uri ServiceUri => _client?.ServiceUri;
public string User => _client?.User;
public string Id { get; set; }
public bool IsConnected => _client != null;
public SsoAdminClient Client => _client;
public void Disconnect() {
_client = null;
}
public override string ToString() {
return Name;
}
public override int GetHashCode() {
return Id != null ? Id.GetHashCode() : base.GetHashCode();
}
public override bool Equals(object obj) {
bool result = false;
if (obj is SsoAdminServer target) {
result = string.Equals(Id, target.Id);
}
return result;
}
}
}

View File

@@ -0,0 +1,27 @@
// **************************************************************************
// Copyright 2020 VMware, Inc.
// **************************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VMware.vSphere.SsoAdminClient.DataTypes
{
public class TokenLifetime
{
SsoAdminClient _client;
public TokenLifetime(SsoAdminClient client) {
_client = client;
}
public SsoAdminClient GetClient() {
return _client;
}
public long MaxHoKTokenLifetime { get; set; }
public long MaxBearerTokenLifetime { get; set; }
}
}

View File

@@ -0,0 +1,661 @@
// **************************************************************************
// Copyright 2020 VMware, Inc.
// **************************************************************************
using System;
using System.Collections.Generic;
using System.IdentityModel.Selectors;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Security;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Security;
using System.Text;
using System.Text.RegularExpressions;
using VMware.Binding.WsTrust;
using VMware.Binding.WsTrust.SecurityContext;
using VMware.vSphere.LsClient;
using VMware.vSphere.SsoAdminClient.DataTypes;
using VMware.vSphere.SsoAdminClient.SsoAdminServiceReferencer;
namespace VMware.vSphere.SsoAdminClient
{
public class SsoAdminClient
{
private const int WEB_OPERATION_TIMEOUT_SECONDS = 30;
private SsoPortTypeClient _ssoAdminBindingClient;
private UserPassSecurityContext _securityContext;
public SsoAdminClient(string hostname, string user, SecureString password, X509CertificateValidator serverCertificateValidator) {
if (hostname == null) throw new ArgumentNullException(nameof(hostname));
if (user == null) throw new ArgumentNullException(nameof(user));
if (password == null) throw new ArgumentNullException(nameof(password));
var lsClient = new LookupServiceClient(hostname, serverCertificateValidator);
// Create STS Client
var stsUri = lsClient.GetStsEndpointUri();
_securityContext = new UserPassSecurityContext(user, password, stsUri, serverCertificateValidator);
// Initialize security context with Saml token by username and password
_securityContext.GetToken();
// Create SSO Admin Binding Client
var ssoAdminUri = lsClient.GetSsoAdminEndpointUri();
ServiceUri = ssoAdminUri;
User = user;
_ssoAdminBindingClient = new SsoPortTypeClient(GetBinding(), new EndpointAddress(ssoAdminUri));
_ssoAdminBindingClient.ChannelFactory.Endpoint.EndpointBehaviors.Add(new WsTrustBehavior());
var serverAuthentication = GetServerAuthentication(serverCertificateValidator);
if (serverAuthentication != null) {
_ssoAdminBindingClient
.ChannelFactory
.Credentials
.ServiceCertificate
.SslCertificateAuthentication = serverAuthentication;
}
}
#region Private Helpers
private X509ServiceCertificateAuthentication GetServerAuthentication(X509CertificateValidator serverCertificateValidator) {
if (serverCertificateValidator != null) {
return new X509ServiceCertificateAuthentication {
CertificateValidationMode = X509CertificateValidationMode.Custom,
CustomCertificateValidator = serverCertificateValidator
};
}
// Default .NET behavior for TLS certificate validation
return null;
}
private static MessageEncodingBindingElement GetWcfEncoding() {
// VMware STS requires SOAP version 1.1
return new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
}
private static HttpsTransportBindingElement GetWcfTransport(bool useSystemProxy) {
// Communication with the STS is over https
HttpsTransportBindingElement transport = new HttpsTransportBindingElement {
RequireClientCertificate = false
};
transport.UseDefaultWebProxy = useSystemProxy;
transport.MaxBufferSize = 2147483647;
transport.MaxReceivedMessageSize = 2147483647;
return transport;
}
private static CustomBinding GetBinding() {
// There is no build-in WCF binding capable of communicating
// with VMware STS, so we create a plain custom one.
// This binding does not provide support for WS-Trust,
// that support is currently implemented as a WCF endpoint behaviour.
var binding = new CustomBinding(GetWcfEncoding(), GetWcfTransport(true));
var timeout = TimeSpan.FromSeconds(WEB_OPERATION_TIMEOUT_SECONDS);
binding.CloseTimeout = timeout;
binding.OpenTimeout = timeout;
binding.ReceiveTimeout = timeout;
binding.SendTimeout = timeout;
return binding;
}
private WsSecurityContext CreateAuthorizedInvocationContext() {
// Issue Bearer token to authorize create solution user to SSO Admin service
var bearerToken = _securityContext.GetToken();
// Set WS Trust Header Serialization with issued bearer SAML token
var securityContext = new WsSecurityContext {
ClientChannel = _ssoAdminBindingClient.InnerChannel,
Properties = {
Credentials = {
BearerToken = bearerToken
}
}
};
return securityContext;
}
#endregion
#region Public interface
public Uri ServiceUri { get; }
public string User { get; }
public PersonUser CreateLocalUser(
string userName,
string password,
string description = null,
string emailAddress = null,
string firstName = null,
string lastName = null) {
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
// Invoke SSO Admin CreateLocalSolutionUser operation
var ssoPrincipalId = authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.CreateLocalPersonUserAsync(
new ManagedObjectReference {
type = "SsoAdminPrincipalManagementService",
Value = "principalManagementService"
},
userName,
new SsoAdminPersonDetails {
description = description,
emailAddress = emailAddress,
firstName = firstName,
lastName = lastName
},
password)).Result;
return GetLocalUsers(ssoPrincipalId.name, ssoPrincipalId.domain, authorizedInvocationContext);
}
private PersonUser GetLocalUsers(string userName, string domain, WsSecurityContext wsSecurityContext) {
// Invoke SSO Admin FindPersonUserAsync operation
var personUser = wsSecurityContext.
InvokeOperation(() =>
_ssoAdminBindingClient.FindPersonUserAsync(
new ManagedObjectReference {
type = "SsoAdminPrincipalDiscoveryService",
Value = "principalDiscoveryService"
},
new SsoPrincipalId {
name = userName,
domain = domain
})).Result;
return new PersonUser(this) {
Name = personUser.id.name,
Domain = personUser.id.domain,
Description = personUser.details.description,
FirstName = personUser.details.firstName,
LastName = personUser.details.lastName,
EmailAddress = personUser.details.emailAddress
};
}
public IEnumerable<PersonUser> GetLocalUsers(string searchString, string domain) {
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
// Invoke SSO Admin FindPersonUsersAsync operation
var personUsers = authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.FindPersonUsersAsync(
new ManagedObjectReference {
type = "SsoAdminPrincipalDiscoveryService",
Value = "principalDiscoveryService"
},
new SsoAdminPrincipalDiscoveryServiceSearchCriteria {
searchString = searchString,
domain = domain
},
int.MaxValue)).Result.returnval;
if (personUsers != null) {
foreach (var personUser in personUsers) {
yield return new PersonUser(this) {
Name = personUser.id.name,
Domain = personUser.id.domain,
Description = personUser.details.description,
FirstName = personUser.details.firstName,
LastName = personUser.details.lastName,
EmailAddress = personUser.details.emailAddress
};
}
}
}
public void DeleteLocalUser(
PersonUser principal) {
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
// Invoke SSO Admin DeleteLocalPrincipal operation
authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.DeleteLocalPrincipalAsync(
new ManagedObjectReference {
type = "SsoAdminPrincipalManagementService",
Value = "principalManagementService"
},
principal.Name));
}
public IEnumerable<DataTypes.Group> GetGroups(string searchString, string domain) {
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
// Invoke SSO Admin FindGroupsAsync operation
var ssoAdminGroups = authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.FindGroupsAsync(
new ManagedObjectReference {
type = "SsoAdminPrincipalDiscoveryService",
Value = "principalDiscoveryService"
},
new SsoAdminPrincipalDiscoveryServiceSearchCriteria {
searchString = searchString,
domain = domain
},
int.MaxValue)).Result.returnval;
if (ssoAdminGroups != null) {
foreach (var group in ssoAdminGroups) {
yield return new DataTypes.Group {
Name = group.id.name,
Domain = group.id.domain
};
}
}
}
public bool AddPersonUserToGroup(PersonUser user, DataTypes.Group group) {
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
// Invoke SSO Admin AddUserToLocalGroupAsync operation
return authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.AddUserToLocalGroupAsync(
new ManagedObjectReference {
type = "SsoAdminPrincipalManagementService",
Value = "principalManagementService"
},
new SsoPrincipalId {
name = user.Name,
domain = user.Domain
},
group.Name)).Result;
}
public bool RemovePersonUserFromGroup(PersonUser user, DataTypes.Group group) {
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
// Invoke SSO Admin RemoveFromLocalGroupAsync operation
return authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.RemoveFromLocalGroupAsync(
new ManagedObjectReference {
type = "SsoAdminPrincipalManagementService",
Value = "principalManagementService"
},
new SsoPrincipalId {
name = user.Name,
domain = user.Domain
},
group.Name)).Result;
}
public void ResetPersonUserPassword(PersonUser user, string newPassword) {
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
// Invoke SSO Admin ResetLocalPersonUserPasswordAsync operation
authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.ResetLocalPersonUserPasswordAsync(
new ManagedObjectReference {
type = "SsoAdminPrincipalManagementService",
Value = "principalManagementService"
},
user.Name,
newPassword)).Wait();
}
public bool UnlockPersonUser(PersonUser user) {
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
// Invoke SSO Admin UnlockUserAccountAsync operation
return authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.UnlockUserAccountAsync(
new ManagedObjectReference {
type = "SsoAdminPrincipalManagementService",
Value = "principalManagementService"
},
new SsoPrincipalId {
name = user.Name,
domain = user.Domain
})).Result;
}
public PasswordPolicy GetPasswordPolicy() {
PasswordPolicy result = null;
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
// Invoke SSO Admin GetLocalPasswordPolicyAsync operation
var ssoAdminPasswordPolicy = authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.GetLocalPasswordPolicyAsync(
new ManagedObjectReference {
type = "SsoAdminPasswordPolicyService",
Value = "passwordPolicyService"
})).Result;
if (ssoAdminPasswordPolicy != null) {
result = new PasswordPolicy(this) {
Description = ssoAdminPasswordPolicy.description,
ProhibitedPreviousPasswordsCount = ssoAdminPasswordPolicy.prohibitedPreviousPasswordsCount,
MinLength = ssoAdminPasswordPolicy.passwordFormat.lengthRestriction.minLength,
MaxLength = ssoAdminPasswordPolicy.passwordFormat.lengthRestriction.maxLength,
MaxIdenticalAdjacentCharacters = ssoAdminPasswordPolicy.passwordFormat.maxIdenticalAdjacentCharacters,
MinNumericCount = ssoAdminPasswordPolicy.passwordFormat.minNumericCount,
MinSpecialCharCount = ssoAdminPasswordPolicy.passwordFormat.minSpecialCharCount,
MinAlphabeticCount = ssoAdminPasswordPolicy.passwordFormat.alphabeticRestriction.minAlphabeticCount,
MinUppercaseCount = ssoAdminPasswordPolicy.passwordFormat.alphabeticRestriction.minUppercaseCount,
MinLowercaseCount = ssoAdminPasswordPolicy.passwordFormat.alphabeticRestriction.minLowercaseCount,
PasswordLifetimeDays = ssoAdminPasswordPolicy.passwordLifetimeDays
};
}
return result;
}
public PasswordPolicy SetPasswordPolicy(
string description = null,
int? prohibitedPreviousPasswordsCount = null,
int? minLength = null,
int? maxLength = null,
int? maxIdenticalAdjacentCharacters = null,
int? minNumericCount = null,
int? minSpecialCharCount = null,
int? minAlphabeticCount = null,
int? minUppercaseCount = null,
int? minLowercaseCount = null,
int? passwordLifetimeDays = null) {
if (description != null ||
prohibitedPreviousPasswordsCount != null ||
minLength != null ||
maxLength != null ||
maxIdenticalAdjacentCharacters != null ||
minNumericCount != null ||
minSpecialCharCount != null ||
minAlphabeticCount != null ||
minUppercaseCount != null ||
minLowercaseCount != null ||
passwordLifetimeDays != null) {
var ssoAdminPasswordPolicy = new SsoAdminPasswordPolicy();
ssoAdminPasswordPolicy.description = description;
if (passwordLifetimeDays != null) {
ssoAdminPasswordPolicy.passwordLifetimeDays = passwordLifetimeDays.Value;
ssoAdminPasswordPolicy.passwordLifetimeDaysSpecified = true;
}
if (prohibitedPreviousPasswordsCount != null) {
ssoAdminPasswordPolicy.prohibitedPreviousPasswordsCount = prohibitedPreviousPasswordsCount.Value;
}
// Update SsoAdminPasswordFormat if needed
if (minLength != null ||
maxLength != null ||
maxIdenticalAdjacentCharacters != null ||
minNumericCount != null ||
minSpecialCharCount != null ||
minAlphabeticCount != null ||
minUppercaseCount != null ||
minLowercaseCount != null) {
ssoAdminPasswordPolicy.passwordFormat = new SsoAdminPasswordFormat();
if (maxIdenticalAdjacentCharacters != null) {
ssoAdminPasswordPolicy.passwordFormat.maxIdenticalAdjacentCharacters = maxIdenticalAdjacentCharacters.Value;
}
if (minNumericCount != null) {
ssoAdminPasswordPolicy.passwordFormat.minNumericCount = minNumericCount.Value;
}
if (minSpecialCharCount != null) {
ssoAdminPasswordPolicy.passwordFormat.minSpecialCharCount = minSpecialCharCount.Value;
}
// Update LengthRestriction if needed
if (minLength != null ||
maxLength != null) {
ssoAdminPasswordPolicy.passwordFormat.lengthRestriction = new SsoAdminPasswordFormatLengthRestriction();
if (maxLength != null) {
ssoAdminPasswordPolicy.passwordFormat.lengthRestriction.maxLength = maxLength.Value;
}
if (minLength != null) {
ssoAdminPasswordPolicy.passwordFormat.lengthRestriction.minLength = minLength.Value;
}
}
// Update AlphabeticRestriction if needed
if (minAlphabeticCount != null ||
minUppercaseCount != null ||
minLowercaseCount != null) {
ssoAdminPasswordPolicy.passwordFormat.alphabeticRestriction = new SsoAdminPasswordFormatAlphabeticRestriction();
if (minAlphabeticCount != null) {
ssoAdminPasswordPolicy.passwordFormat.alphabeticRestriction.minAlphabeticCount = minAlphabeticCount.Value;
}
if (minUppercaseCount != null) {
ssoAdminPasswordPolicy.passwordFormat.alphabeticRestriction.minUppercaseCount = minUppercaseCount.Value;
}
if (minLowercaseCount != null) {
ssoAdminPasswordPolicy.passwordFormat.alphabeticRestriction.minLowercaseCount = minLowercaseCount.Value;
}
}
}
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
// Invoke SSO Admin UpdateLocalPasswordPolicyAsync operation
authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.UpdateLocalPasswordPolicyAsync(
new ManagedObjectReference {
type = "SsoAdminPasswordPolicyService",
Value = "passwordPolicyService"
},
ssoAdminPasswordPolicy)).Wait();
}
return GetPasswordPolicy();
}
public LockoutPolicy GetLockoutPolicy() {
LockoutPolicy result = null;
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
// Invoke SSO Admin GetLockoutPolicyAsync operation
var ssoAdminLockoutPolicy = authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.GetLockoutPolicyAsync(
new ManagedObjectReference {
type = "SsoAdminLockoutPolicyService",
Value = "lockoutPolicyService"
})).Result;
if (ssoAdminLockoutPolicy != null) {
result = new LockoutPolicy(this) {
Description = ssoAdminLockoutPolicy.description,
AutoUnlockIntervalSec = ssoAdminLockoutPolicy.autoUnlockIntervalSec,
FailedAttemptIntervalSec = ssoAdminLockoutPolicy.failedAttemptIntervalSec,
MaxFailedAttempts = ssoAdminLockoutPolicy.maxFailedAttempts
};
}
return result;
}
public LockoutPolicy SetLockoutPolicy(
string description,
long? autoUnlockIntervalSec,
long? failedAttemptIntervalSec,
int? maxFailedAttempts) {
if (description != null ||
autoUnlockIntervalSec != null ||
failedAttemptIntervalSec != null ||
maxFailedAttempts != null) {
var ssoAdminLockoutPolicy = new SsoAdminLockoutPolicy();
ssoAdminLockoutPolicy.description = description;
if (autoUnlockIntervalSec != null) {
ssoAdminLockoutPolicy.autoUnlockIntervalSec = autoUnlockIntervalSec.Value;
}
if (failedAttemptIntervalSec != null) {
ssoAdminLockoutPolicy.failedAttemptIntervalSec = failedAttemptIntervalSec.Value;
}
if (maxFailedAttempts != null) {
ssoAdminLockoutPolicy.maxFailedAttempts = maxFailedAttempts.Value;
}
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
// Invoke SSO Admin GetLockoutPolicyAsync operation
authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.UpdateLockoutPolicyAsync(
new ManagedObjectReference {
type = "SsoAdminLockoutPolicyService",
Value = "lockoutPolicyService"
},
ssoAdminLockoutPolicy)).Wait();
}
return GetLockoutPolicy();
}
public TokenLifetime GetTokenLifetime() {
// Create Authorization Invocation Context
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
var maxHoKTokenLifetime = authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.GetMaximumHoKTokenLifetimeAsync(
new ManagedObjectReference {
type = "SsoAdminConfigurationManagementService",
Value = "configurationManagementService"
})).Result;
var maxBearerTokenLifetime = authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.GetMaximumBearerTokenLifetimeAsync(
new ManagedObjectReference {
type = "SsoAdminConfigurationManagementService",
Value = "configurationManagementService"
})).Result;
return new TokenLifetime(this) {
MaxHoKTokenLifetime = maxHoKTokenLifetime,
MaxBearerTokenLifetime = maxBearerTokenLifetime
};
}
public TokenLifetime SetTokenLifetime(
long? maxHoKTokenLifetime,
long? maxBearerTokenLifetime) {
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
if (maxHoKTokenLifetime != null) {
authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.SetMaximumHoKTokenLifetimeAsync(
new ManagedObjectReference {
type = "SsoAdminConfigurationManagementService",
Value = "configurationManagementService"
},
maxHoKTokenLifetime.Value)).Wait();
}
if (maxBearerTokenLifetime != null) {
authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.SetMaximumBearerTokenLifetimeAsync(
new ManagedObjectReference {
type = "SsoAdminConfigurationManagementService",
Value = "configurationManagementService"
},
maxBearerTokenLifetime.Value)).Wait();
}
return GetTokenLifetime();
}
public void AddActiveDirectoryExternalDomain(
string domainName,
string domainAlias,
string friendlyName,
string primaryUrl,
string baseDNUsers,
string baseDNGroups,
string authenticationUserName,
string authenticationPassword) {
string serverType = "ActiveDirectory";
string authenticationType = "password";
var authorizedInvocationContext =
CreateAuthorizedInvocationContext();
authorizedInvocationContext.
InvokeOperation(() =>
_ssoAdminBindingClient.AddExternalDomainAsync(
new ManagedObjectReference {
type = "SsoAdminConfigurationManagementService",
Value = "configurationManagementService"
},
serverType,
domainName,
domainAlias,
new SsoAdminExternalDomainDetails {
friendlyName = friendlyName,
primaryUrl = primaryUrl,
userBaseDn = baseDNUsers,
groupBaseDn = baseDNGroups
},
authenticationType,
new SsoAdminDomainManagementServiceAuthenticationCredentails {
username = authenticationUserName,
password = authenticationPassword
})).Wait();
}
#endregion
}
}

View File

@@ -0,0 +1,57 @@
// **************************************************************************
// Copyright 2020 VMware, Inc.
// **************************************************************************
using System;
using System.Collections.Generic;
using System.IdentityModel.Selectors;
using System.Linq;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using VMware.Binding.Sts;
namespace VMware.vSphere.SsoAdminClient
{
public class UserPassSecurityContext
{
private string _user;
private SecureString _password;
private VmwareSecruityTokenService _stsClient;
private SamlSecurityToken _validToken;
public UserPassSecurityContext(
string user,
SecureString password,
Uri stsUri,
X509CertificateValidator serverCertificateValidator) {
if (user == null) throw new ArgumentNullException(nameof(user));
if (password == null) throw new ArgumentNullException(nameof(password));
if (stsUri == null) throw new ArgumentNullException(nameof(stsUri));
_user = user;
_password = password;
Action<X509Certificate2> certHandler = null;
if (serverCertificateValidator != null) {
certHandler = serverCertificateValidator.Validate;
}
_stsClient = new VmwareSecruityTokenService(stsUri, false, certHandler);
}
private void RenewIfNeeded() {
if (_validToken == null ||
_validToken.Expires < (DateTime.Now + new TimeSpan(0, 0, 30))) {
_validToken = _stsClient.IssueBearerTokenByUserCredential(
_user,
_password);
}
}
public XmlElement GetToken() {
RenewIfNeeded();
return _validToken.RawToken;
}
}
}

View File

@@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>VMware.vSphere.SsoAdminClient</RootNamespace>
<AssemblyName>VMware.vSphere.SsoAdminClient</AssemblyName>
<Description>SSO Admin API client.</Description>
<TargetFrameworks>net45;netcoreapp2.0</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net45' ">
<DefineConstants>$(DefineConstants);NET45</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">
<DefineConstants>$(DefineConstants);NETCORE20</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
<Reference Include="System.IdentityModel" />
<PackageReference Include="System.ServiceModel.Primitives" Version="4.4.0" />
<PackageReference Include="System.ServiceModel.Duplex" Version="4.4.0" />
<PackageReference Include="System.ServiceModel.Http" Version="4.4.0" />
<PackageReference Include="System.ServiceModel.NetTcp" Version="4.4.0" />
<PackageReference Include="System.ServiceModel.Security" Version="4.4.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.0'">
<PackageReference Include="VMware.System.Private.ServiceModel" Version="4.4.4" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="VMware.Binding.Sts" Version="12.0.0.15939652" />
<PackageReference Include="VMware.Binding.WsTrust" Version="12.0.0.15939652" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VMware.vSphere.LsClient\VMware.vSphere.LsClient.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,147 @@
# **************************************************************************
# Copyright 2020 VMware, Inc.
# **************************************************************************
param(
[ValidateSet("Debug", "Release")]
[string]
$Configuration = "Release",
[string]
$TestVc,
[string]
$TestVcUser,
[string]
$TestVcPassword
)
function Test-BuildToolsAreAvailable {
$dotnetSdk = Get-Command 'dotnet'
if (-not $dotnetSdk) {
throw "'dotnet' sdk is not available"
}
}
function LogInfo($message) {
$dt = (Get-Date).ToLongTimeString()
Write-Host "[$dt] INFO: $message" -ForegroundColor Green
}
function Build {
$srcRoot = Join-Path $PSScriptRoot "VMware.vSphere.SsoAdmin.Client"
Push-Location $srcRoot
dotnet build -c $Configuration
Pop-Location
}
function Publish {
param($OutputFolder)
if (Test-Path $OutputFolder) {
$netcoreLsSource = [IO.Path]::Combine(
$PSScriptRoot,
"VMware.vSphere.SsoAdmin.Client",
"VMware.vSphere.LsClient",
"bin",
$Configuration,
"netcoreapp2.0",
"VMware.vSphere.LsClient.dll")
$net45LsSource = [IO.Path]::Combine(
$PSScriptRoot,
"VMware.vSphere.SsoAdmin.Client",
"VMware.vSphere.LsClient",
"bin",
$Configuration,
"net45",
"VMware.vSphere.LsClient.dll")
$netcoreSsoAdminSource = [IO.Path]::Combine(
$PSScriptRoot,
"VMware.vSphere.SsoAdmin.Client",
"VMware.vSphere.SsoAdminClient",
"bin",
$Configuration,
"netcoreapp2.0",
"VMware.vSphere.SsoAdminClient.dll")
$net45SsoAdminSource = [IO.Path]::Combine(
$PSScriptRoot,
"VMware.vSphere.SsoAdmin.Client",
"VMware.vSphere.SsoAdminClient",
"bin",
$Configuration,
"net45",
"VMware.vSphere.SsoAdminClient.dll")
$netcoreUtilsSource = [IO.Path]::Combine(
$PSScriptRoot,
"VMware.vSphere.SsoAdmin.Client",
"VMware.vSphere.SsoAdmin.Utils",
"bin",
$Configuration,
"netcoreapp2.0",
"VMware.vSphere.SsoAdmin.Utils.dll")
$net45UtilsSource = [IO.Path]::Combine(
$PSScriptRoot,
"VMware.vSphere.SsoAdmin.Client",
"VMware.vSphere.SsoAdmin.Utils",
"bin",
$Configuration,
"net45",
"VMware.vSphere.SsoAdmin.Utils.dll")
$netcoreTarget = Join-Path $OutputFolder "netcoreapp2.0"
$net45Target = Join-Path $OutputFolder "net45"
Copy-Item -Path $netcoreLsSource -Destination $netcoreTarget -Force
Copy-Item -Path $net45LsSource -Destination $net45Target -Force
Copy-Item -Path $netcoreSsoAdminSource -Destination $netcoreTarget -Force
Copy-Item -Path $net45SsoAdminSource -Destination $net45Target -Force
Copy-Item -Path $netcoreUtilsSource -Destination $netcoreTarget -Force
Copy-Item -Path $net45UtilsSource -Destination $net45Target -Force
}
}
function Test {
if (-not [string]::IsNullOrEmpty($TestVc) -and `
-not [string]::IsNullOrEmpty($TestVcUser) -and `
-not [string]::IsNullOrEmpty($TestVcPassword)) {
# Run Tests in external process because it will load build output binaries
LogInfo "Run VC integration tests"
$usePowerShell = (Get-Process -Id $pid).ProcessName
$testLauncherScript = Join-Path (Join-Path $PSScriptRoot 'test') 'RunTests.ps1'
$arguments = "-Command $testLauncherScript -VcAddress $TestVc -User $TestVcUser -Password $TestVcPassword"
Start-Process `
-FilePath $usePowerShell `
-ArgumentList $arguments `
-PassThru `
-NoNewWindow | `
Wait-Process
}
}
# 1. Test Build Tools
LogInfo "Test build tools are available"
Test-BuildToolsAreAvailable
# 2. Build
LogInfo "Build"
Build
# 3. Publish
$OutputFolder = Split-Path $PSScriptRoot
LogInfo "Publish binaries to '$OutputFolder'"
Publish $OutputFolder
# 4. Test
Test

View File

@@ -0,0 +1,106 @@
# **************************************************************************
# Copyright 2020 VMware, Inc.
# **************************************************************************
param(
[Parameter(Mandatory = $true)]
[string]
$VcAddress,
[Parameter(Mandatory = $true)]
[string]
$User,
[Parameter(Mandatory = $true)]
[string]
$Password
)
# Import Vmware.vSphere.SsoAdmin Module
$modulePath = Join-Path (Split-Path $PSScriptRoot | Split-Path) "VMware.vSphere.SsoAdmin.psd1"
Import-Module $modulePath
Describe "Connect-SsoAdminServer and Disconnect-SsoAdminServer Tests" {
AfterEach {
$connectionsToCleanup = $global:DefaultSsoAdminServers.ToArray()
foreach ($connection in $connectionsToCleanup) {
Disconnect-SsoAdminServer -Server $connection
}
}
Context "Connect-SsoAdminServer" {
It 'Connect-SsoAdminServer returns SsoAdminServer object and updates DefaultSsoAdminServers variable' {
# Act
$actual = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
# Assert
$actual | Should Not Be $null
$actual.GetType().FullName | Should Be 'VMware.vSphere.SsoAdminClient.DataTypes.SsoAdminServer'
$actual.IsConnected | Should Be $true
$actual.Name | Should Be $VcAddress
$global:DefaultSsoAdminServers | Should Contain $actual
}
It 'Connect-SsoAdminServer throws error on invalid password' {
# Act
# Assert
{ Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password ($Password + "invalid") `
-SkipCertificateCheck } | `
Should Throw "Invalid credentials"
}
It 'Connect-SsoAdminServer throws error on invalid Tls Certificate' {
# Act
# Assert
{ Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password} | `
Should Throw "The SSL connection could not be established, see inner exception."
}
}
Context "Disconnect-SsoAdminServer" {
It 'Diconnect-SsoAdminServer removes server from DefaultSsoAdminServers and makes the object not connected' {
# Arrange
$expected = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
# Act
$expected | Disconnect-SsoAdminServer
# Assert
$global:DefaultSsoAdminServers | Should Not Contain $expected
$expected.IsConnected | Should Be $false
}
It 'Disconnects disconnected object' {
# Arrange
$expected = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
$expected | Disconnect-SsoAdminServer
# Act
{ Disconnect-SsoAdminServer -Server $expected } | `
Should Not Throw
# Assert
$global:DefaultSsoAdminServers | Should Not Contain $expected
$expected.IsConnected | Should Be $false
}
}
}

View File

@@ -0,0 +1,76 @@
# **************************************************************************
# Copyright 2020 VMware, Inc.
# **************************************************************************
param(
[Parameter(Mandatory = $true)]
[string]
$VcAddress,
[Parameter(Mandatory = $true)]
[string]
$User,
[Parameter(Mandatory = $true)]
[string]
$Password
)
# Import Vmware.vSphere.SsoAdmin Module
$modulePath = Join-Path (Split-Path $PSScriptRoot | Split-Path) "VMware.vSphere.SsoAdmin.psd1"
Import-Module $modulePath
Describe "Get-SsoGroup Tests" {
BeforeEach {
Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
}
AfterEach {
$connectionsToCleanup = $global:DefaultSsoAdminServers.ToArray()
foreach ($connection in $connectionsToCleanup) {
Disconnect-SsoAdminServer -Server $connection
}
}
Context "Get-SsoGroup" {
It 'Gets groups without filters' {
# Act
$actual = Get-SsoGroup
# Assert
$actual | Should Not Be $null
$actual.Count | Should BeGreaterThan 0
$actual[0].Name | Should Not Be $null
$actual[0].Domain | Should Be 'localos'
}
It 'Gets groups for default domain' {
# Arrange
$newUserName = "NewUser1"
$password = '$tr0NG_TestPa$$w0rd'
## Create Person User to determine default domain name
## Person Users are created in the default domain
$newPersonUser = New-SsoPersonUser `
-UserName $newUserName `
-Password $password
# Act
$actual = Get-SsoGroup `
-Domain $newPersonUser.Domain
# Assert
$actual | Should Not Be $null
$actual.Count | Should BeGreaterThan 0
$actual[0].Name | Should Not Be $null
$actual[0].Domain | Should Be $newPersonUser.Domain
# Cleanup
Remove-SsoPersonUser -User $newPersonUser
}
}
}

View File

@@ -0,0 +1,73 @@
# **************************************************************************
# Copyright 2020 VMware, Inc.
# **************************************************************************
param(
[Parameter(Mandatory = $true)]
[string]
$VcAddress,
[Parameter(Mandatory = $true)]
[string]
$User,
[Parameter(Mandatory = $true)]
[string]
$Password
)
# Import Vmware.vSphere.SsoAdmin Module
$modulePath = Join-Path (Split-Path $PSScriptRoot | Split-Path) "VMware.vSphere.SsoAdmin.psd1"
Import-Module $modulePath
Describe "LockoutPolicy Tests" {
BeforeEach {
Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
}
AfterEach {
$connectionsToCleanup = $global:DefaultSsoAdminServers.ToArray()
foreach ($connection in $connectionsToCleanup) {
Disconnect-SsoAdminServer -Server $connection
}
}
Context "Get-SsoLockoutPolicy" {
It 'Gets lockout policy' {
# Act
$actual = Get-SsoLockoutPolicy
# Assert
$actual | Should Not Be $null
}
}
Context "Set-SsoLockoutPolicy" {
It 'Updates lockout policy AutoUnlockIntervalSec and MaxFailedAttempts' {
# Arrange
$lockoutPolicyToUpdate = Get-SsoLockoutPolicy
$expectedAutoUnlockIntervalSec = 33
$expectedMaxFailedAttempts = 7
# Act
$actual = Set-SsoLockoutPolicy `
-LockoutPolicy $lockoutPolicyToUpdate `
-AutoUnlockIntervalSec $expectedAutoUnlockIntervalSec `
-MaxFailedAttempts $expectedMaxFailedAttempts
# Assert
$actual | Should Not Be $null
$actual.AutoUnlockIntervalSec | Should Be $expectedAutoUnlockIntervalSec
$actual.MaxFailedAttempts | Should Be $expectedMaxFailedAttempts
$actual.FailedAttemptIntervalSec | Should Be $lockoutPolicyToUpdate.FailedAttemptIntervalSec
$actual.Description | Should Be $lockoutPolicyToUpdate.Description
# Cleanup
$lockoutPolicyToUpdate | Set-SsoLockoutPolicy
}
}
}

View File

@@ -0,0 +1,56 @@
# **************************************************************************
# Copyright 2020 VMware, Inc.
# **************************************************************************
param(
[Parameter(Mandatory = $true)]
[string]
$VcAddress,
[Parameter(Mandatory = $true)]
[string]
$User,
[Parameter(Mandatory = $true)]
[string]
$Password
)
# Import Vmware.vSphere.SsoAdmin Module
$modulePath = Join-Path (Split-Path $PSScriptRoot | Split-Path) "VMware.vSphere.SsoAdmin.psd1"
Import-Module $modulePath
$script:lsClient = $null
Describe "Lookup Service Client Integration Tests" {
Context "Retrieval of Service API Url" {
BeforeAll {
## Create LsClient
$skipCertificateCheckValidator = New-Object `
'VMware.vSphere.SsoAdmin.Utils.AcceptAllX509CertificateValidator'
$script:lsClient = New-Object `
'VMware.vSphere.LsClient.LookupServiceClient' `
-ArgumentList @($VCAddress, $skipCertificateCheckValidator)
}
It 'Gets SsoAdmin API Url' {
# Act
$actual = $script:lsClient.GetSsoAdminEndpointUri()
# Assert
$actual | Should Not Be $null
$actual.ToString().StartsWith("https://$VCAddress/sso-adminserver/sdk/") | Should Be $true
}
It 'Gets STS API Url' {
# Act
$actual = $script:lsClient.GetStsEndpointUri()
# Assert
$actual | Should Not Be $null
$actual.ToString().StartsWith("https://$VCAddress/sts/STSService") | Should Be $true
}
}
}

View File

@@ -0,0 +1,109 @@
# **************************************************************************
# Copyright 2020 VMware, Inc.
# **************************************************************************
param(
[Parameter(Mandatory = $true)]
[string]
$VcAddress,
[Parameter(Mandatory = $true)]
[string]
$User,
[Parameter(Mandatory = $true)]
[string]
$Password
)
# Import Vmware.vSphere.SsoAdmin Module
$modulePath = Join-Path (Split-Path $PSScriptRoot | Split-Path) "VMware.vSphere.SsoAdmin.psd1"
Import-Module $modulePath
Describe "PasswordPolicy Tests" {
BeforeEach {
Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
}
AfterEach {
$connectionsToCleanup = $global:DefaultSsoAdminServers.ToArray()
foreach ($connection in $connectionsToCleanup) {
Disconnect-SsoAdminServer -Server $connection
}
}
Context "Get-SsoPasswordPolicy" {
It 'Gets password policy' {
# Act
$actual = Get-SsoPasswordPolicy
# Assert
$actual | Should Not Be $null
}
}
Context "Set-SsoPasswordPolicy" {
It 'Updates password policy MaxLength and PasswordLifetimeDays' {
# Arrange
$passwordPolicyToUpdate = Get-SsoPasswordPolicy
$expectedMaxLength = 17
$expectedPasswordLifetimeDays = 77
# Act
$actual = Set-SsoPasswordPolicy `
-PasswordPolicy $passwordPolicyToUpdate `
-MaxLength $expectedMaxLength `
-PasswordLifetimeDays $expectedPasswordLifetimeDays
# Assert
$actual | Should Not Be $null
$actual.MaxLength | Should Be $expectedMaxLength
$actual.PasswordLifetimeDays | Should Be $expectedPasswordLifetimeDays
$actual.Description | Should Be $passwordPolicyToUpdate.Description
$actual.ProhibitedPreviousPasswordsCount | Should Be $passwordPolicyToUpdate.ProhibitedPreviousPasswordsCount
$actual.MinLength | Should Be $passwordPolicyToUpdate.MinLength
$actual.MaxIdenticalAdjacentCharacters | Should Be $passwordPolicyToUpdate.MaxIdenticalAdjacentCharacters
$actual.MinNumericCount | Should Be $passwordPolicyToUpdate.MinNumericCount
$actual.MinSpecialCharCount | Should Be $passwordPolicyToUpdate.MinSpecialCharCount
$actual.MinAlphabeticCount | Should Be $passwordPolicyToUpdate.MinAlphabeticCount
$actual.MinUppercaseCount | Should Be $passwordPolicyToUpdate.MinUppercaseCount
$actual.MinLowercaseCount | Should Be $passwordPolicyToUpdate.MinLowercaseCount
# Cleanup
$passwordPolicyToUpdate | Set-SsoPasswordPolicy
}
It 'Updates password policy Description and MinUppercaseCount' {
# Arrange
$passwordPolicyToUpdate = Get-SsoPasswordPolicy
$expectedMinUppercaseCount = 0
$expectedDescription = "Test Description"
# Act
$actual = $passwordPolicyToUpdate | Set-SsoPasswordPolicy `
-Description $expectedDescription `
-MinUppercaseCount $expectedMinUppercaseCount
# Assert
$actual | Should Not Be $null
$actual.Description | Should Be $expectedDescription
$actual.MinUppercaseCount | Should Be $expectedMinUppercaseCount
$actual.MaxLength | Should Be $passwordPolicyToUpdate.MaxLength
$actual.PasswordLifetimeDays | Should Be $passwordPolicyToUpdate.PasswordLifetimeDays
$actual.ProhibitedPreviousPasswordsCount | Should Be $passwordPolicyToUpdate.ProhibitedPreviousPasswordsCount
$actual.MinLength | Should Be $passwordPolicyToUpdate.MinLength
$actual.MaxIdenticalAdjacentCharacters | Should Be $passwordPolicyToUpdate.MaxIdenticalAdjacentCharacters
$actual.MinNumericCount | Should Be $passwordPolicyToUpdate.MinNumericCount
$actual.MinSpecialCharCount | Should Be $passwordPolicyToUpdate.MinSpecialCharCount
$actual.MinAlphabeticCount | Should Be $passwordPolicyToUpdate.MinAlphabeticCount
$actual.MinLowercaseCount | Should Be $passwordPolicyToUpdate.MinLowercaseCount
# Cleanup
$passwordPolicyToUpdate | Set-SsoPasswordPolicy
}
}
}

View File

@@ -0,0 +1,418 @@
# **************************************************************************
# Copyright 2020 VMware, Inc.
# **************************************************************************
param(
[Parameter(Mandatory = $true)]
[string]
$VcAddress,
[Parameter(Mandatory = $true)]
[string]
$User,
[Parameter(Mandatory = $true)]
[string]
$Password
)
# Import Vmware.vSphere.SsoAdmin Module
$modulePath = Join-Path (Split-Path $PSScriptRoot | Split-Path) "VMware.vSphere.SsoAdmin.psd1"
Import-Module $modulePath
Describe "PersonUser Tests" {
BeforeEach {
$script:usersToCleanup = @()
}
AfterEach {
foreach ($personUser in $script:usersToCleanup) {
Remove-SsoPersonUser -User $personUser
}
$connectionsToCleanup = $global:DefaultSsoAdminServers.ToArray()
foreach ($connection in $connectionsToCleanup) {
Disconnect-SsoAdminServer -Server $connection
}
}
Context "New-SsoPersonUser" {
It 'Creates person user with details' {
# Arrange
$expectedUserName = "TestPersonUser1"
$expectedPassword = '$tr0NG_TestPa$$w0rd'
$expectedDescription = "Test Description"
$expectedEmailAddress = "testuser@testdomain.com"
$expectedFirstName = "Test"
$expectedLastName = "User"
$connection = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
# Act
$actual = New-SsoPersonUser `
-Server $connection `
-UserName $expectedUserName `
-Password $expectedPassword `
-Description $expectedDescription `
-EmailAddress $expectedEmailAddress `
-FirstName $expectedFirstName `
-LastName $expectedLastName
$script:usersToCleanup += $actual
# Assert
$actual | Should Not Be $null
$actual.GetType().FullName | Should Be 'VMware.vSphere.SsoAdminClient.DataTypes.PersonUser'
$actual.Name | Should Be $expectedUserName
$actual.Domain | Should Not Be $null
$actual.Description | Should Be $expectedDescription
$actual.FirstName | Should Be $expectedFirstName
$actual.LastName | Should Be $expectedLastName
$actual.EmailAddress | Should Be $expectedEmailAddress
}
It 'Creates person user without details' {
# Arrange
$expectedUserName = "TestPersonUser2"
$expectedPassword = '$tr0NG_TestPa$$w0rd'
$connection = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
# Act
$actual = New-SsoPersonUser `
-Server $connection `
-UserName $expectedUserName `
-Password $expectedPassword
$script:usersToCleanup += $actual
# Assert
$actual | Should Not Be $null
$actual.GetType().FullName | Should Be 'VMware.vSphere.SsoAdminClient.DataTypes.PersonUser'
$actual.Name | Should Be $expectedUserName
$actual.Domain | Should Not Be $null
$actual.Description | Should Be $null
$actual.FirstName | Should Be $null
$actual.LastName | Should Be $null
$actual.EmailAddress | Should Be $null
}
}
Context "Get-SsoPersonUser" {
It 'Gets person users without filters' {
# Arrange
$connection = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
# Act
$actual = Get-SsoPersonUser
# Assert
$actual | Should Not Be $null
$actual.Count | Should BeGreaterThan 0
$actual[0].Name | Should Not Be $null
$actual[0].Domain | Should Be 'localos'
}
It 'Gets person users by name (exact match) and domain filters' {
# Arrange
$connection = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
$expectedUserName = "TestPersonUser3"
$secondUserName = "TestPersonUser4"
$password = '$tr0NG_TestPa$$w0rd'
$personUserToSearch = New-SsoPersonUser `
-UserName $expectedUserName `
-Password $password `
-Server $connection
$script:usersToCleanup += $personUserToSearch
$secondPersonUserToSearch = New-SsoPersonUser `
-UserName $secondUserName `
-Password $password `
-Server $connection
$script:usersToCleanup += $secondPersonUserToSearch
# Act
$actual = Get-SsoPersonUser `
-Name $expectedUserName `
-Domain $personUserToSearch.Domain `
-Server $connection
# Assert
$actual | Should Not Be $null
$actual.Name | Should Be $expectedUserName
$actual.Domain | Should Not Be $null
$actual.Domain | Should Be $personUserToSearch.Domain
}
It 'Gets person users by name (* wildcard match) and domain filters' {
# Arrange
$connection = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
$expectedUserName = "TestPersonUser3"
$secondUserName = "TestPersonUser4"
$password = '$tr0NG_TestPa$$w0rd'
$personUserToSearch = New-SsoPersonUser `
-UserName $expectedUserName `
-Password $password `
-Server $connection
$script:usersToCleanup += $personUserToSearch
$secondPersonUserToSearch = New-SsoPersonUser `
-UserName $secondUserName `
-Password $password `
-Server $connection
$script:usersToCleanup += $secondPersonUserToSearch
# Act
$actual = Get-SsoPersonUser `
-Name "Test*" `
-Domain $personUserToSearch.Domain `
-Server $connection
# Assert
$actual | Should Not Be $null
$actual.Count | Should Be 2
$actual.Name | Should Contain $expectedUserName
$actual.Name | Should Contain $secondUserName
}
It 'Gets person users by name (? wildcard match) and domain filters' {
# Arrange
$connection = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
$expectedUserName = "TestPersonUser3"
$secondUserName = "TestPersonUser4"
$password = '$tr0NG_TestPa$$w0rd'
$personUserToSearch = New-SsoPersonUser `
-UserName $expectedUserName `
-Password $password `
-Server $connection
$script:usersToCleanup += $personUserToSearch
$secondPersonUserToSearch = New-SsoPersonUser `
-UserName $secondUserName `
-Password $password `
-Server $connection
$script:usersToCleanup += $secondPersonUserToSearch
# Act
$actual = Get-SsoPersonUser `
-Name "TestPersonUser?" `
-Domain $personUserToSearch.Domain `
-Server $connection
# Assert
$actual | Should Not Be $null
$actual.Count | Should Be 2
$actual.Name | Should Contain $expectedUserName
$actual.Name | Should Contain $secondUserName
}
It 'Gets person users by unexisting name does not return' {
# Arrange
$connection = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
$expectedUserName = "TestPersonUser3"
$password = '$tr0NG_TestPa$$w0rd'
$personUserToSearch = New-SsoPersonUser `
-UserName $expectedUserName `
-Password $password `
-Server $connection
$script:usersToCleanup += $personUserToSearch
# Act
$actual = Get-SsoPersonUser `
-Name "TestPersonUser" `
-Domain $personUserToSearch.Domain `
-Server $connection
# Assert
$actual | Should Be $null
}
}
Context "Set-SsoPersonUser" {
It 'Adds person user to group' {
# Arrange
$userName = "TestAddGroupPersonUserName"
$userPassword = '$tr0NG_TestPa$$w0rd'
$connection = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
$personUserToUpdate = New-SsoPersonUser `
-UserName $userName `
-Password $userPassword `
-Server $connection
$script:usersToCleanup += $personUserToUpdate
$groupUserToBeAddedTo = Get-SsoGroup `
-Name 'Administrators' `
-Domain $personUserToUpdate.Domain `
-Server $connection
# Act
$actual = Set-SsoPersonUser `
-User $personUserToUpdate `
-Group $groupUserToBeAddedTo `
-Add
# Assert
$actual | Should Not Be $null
}
It 'Removes person user from group' {
# Arrange
$userName = "TestRemoveGroupPersonUserName"
$userPassword = '$tr0NG_TestPa$$w0rd'
$connection = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
$personUserToUpdate = New-SsoPersonUser `
-UserName $userName `
-Password $userPassword `
-Server $connection
$script:usersToCleanup += $personUserToUpdate
$groupToBeUsed = Get-SsoGroup `
-Name 'Administrators' `
-Domain $personUserToUpdate.Domain `
-Server $connection
Set-SsoPersonUser `
-User $personUserToUpdate `
-Group $groupToBeUsed `
-Add
# Act
$actual = Set-SsoPersonUser `
-User $personUserToUpdate `
-Group $groupToBeUsed `
-Remove
# Assert
$actual | Should Not Be $null
}
It 'Resets person user password' {
# Arrange
$userName = "TestResetPassPersonUserName"
$userPassword = '$tr0NG_TestPa$$w0rd'
$newPassword = 'Update_TestPa$$w0rd'
$connection = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
$personUserToUpdate = New-SsoPersonUser `
-UserName $userName `
-Password $userPassword `
-Server $connection
$script:usersToCleanup += $personUserToUpdate
# Act
$actual = Set-SsoPersonUser `
-User $personUserToUpdate `
-NewPassword $newPassword
# Assert
$actual | Should Not Be $null
}
It 'Unlocks not locked person user' {
# Arrange
$userName = "TestResetPassPersonUserName"
$userPassword = '$tr0NG_TestPa$$w0rd'
$connection = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
$personUserToUpdate = New-SsoPersonUser `
-UserName $userName `
-Password $userPassword `
-Server $connection
$script:usersToCleanup += $personUserToUpdate
# Act
$actual = Set-SsoPersonUser `
-User $personUserToUpdate `
-Unlock
# Assert
$actual | Should Be $null
}
}
Context "Remove-SsoPersonUser" {
It 'Removes person user' {
# Arrange
$userName = "TestPersonUser4"
$userPassword = '$tr0NG_TestPa$$w0rd'
$connection = Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
$personUserToRemove = New-SsoPersonUser `
-UserName $userName `
-Password $userPassword `
-Server $connection
# Act
Remove-SsoPersonUser -User $personUserToRemove
# Assert
$personUserToRemove | Should Not Be $null
$userFromServer = Get-SsoPersonUser `
-Name $personUserToRemove.Name `
-Domain $personUserToRemove.Domain `
-Server $connection
$userFromServer | Should Be $null
}
}
}

View File

@@ -0,0 +1,36 @@
# **************************************************************************
# Copyright 2020 VMware, Inc.
# **************************************************************************
param(
[Parameter(Mandatory = $true)]
[string]
$VcAddress,
[Parameter(Mandatory = $true)]
[string]
$User,
[Parameter(Mandatory = $true)]
[string]
$Password
)
function Test-PesterIsAvailable() {
$pesterModule = Get-Module Pester -List
if ($pesterModule -eq $null) {
throw "Pester Module is not available"
}
}
Test-PesterIsAvailable
Invoke-Pester `
-Script @{
Path = $PSScriptRoot
Parameters = @{
VcAddress = $VcAddress
User = $User
Password = $Password
}
}

View File

@@ -0,0 +1,75 @@
# **************************************************************************
# Copyright 2020 VMware, Inc.
# **************************************************************************
param(
[Parameter(Mandatory = $true)]
[string]
$VcAddress,
[Parameter(Mandatory = $true)]
[string]
$User,
[Parameter(Mandatory = $true)]
[string]
$Password
)
# Import Vmware.vSphere.SsoAdmin Module
$modulePath = Join-Path (Split-Path $PSScriptRoot | Split-Path) "VMware.vSphere.SsoAdmin.psd1"
Import-Module $modulePath
Describe "TokenLifetime Tests" {
BeforeEach {
Connect-SsoAdminServer `
-Server $VcAddress `
-User $User `
-Password $Password `
-SkipCertificateCheck
}
AfterEach {
$connectionsToCleanup = $global:DefaultSsoAdminServers.ToArray()
foreach ($connection in $connectionsToCleanup) {
Disconnect-SsoAdminServer -Server $connection
}
}
Context "Get-SsoTokenLifetime" {
It 'Gets token lifetime settings' {
# Act
$actual = Get-SsoTokenLifetime
# Assert
$actual | Should Not Be $null
$actual.MaxHoKTokenLifetime | Should BeGreaterThan 0
$actual.MaxBearerTokenLifetime | Should BeGreaterThan 0
}
}
Context "Set-SsoTokenLifetime" {
It 'Updates MaxHoKTokenLifetime and MaxBearerTokenLifetime' {
# Arrange
$tokenLifetimeToUpdate = Get-SsoTokenLifetime
$expectedMaxHoKTokenLifetime = 60
$expectedMaxBearerTokenLifetime = 30
# Act
$actual = Set-SsoTokenLifetime `
-TokenLifetime $tokenLifetimeToUpdate `
-MaxHoKTokenLifetime $expectedMaxHoKTokenLifetime `
-MaxBearerTokenLifetime $expectedMaxBearerTokenLifetime
# Assert
$actual | Should Not Be $null
$actual.MaxHoKTokenLifetime | Should Be $expectedMaxHoKTokenLifetime
$actual.MaxBearerTokenLifetime | Should Be $expectedMaxBearerTokenLifetime
# Cleanup
$tokenLifetimeToUpdate | Set-SsoTokenLifetime `
-MaxHoKTokenLifetime $tokenLifetimeToUpdate.MaxHoKTokenLifetime `
-MaxBearerTokenLifetime $tokenLifetimeToUpdate.MaxBearerTokenLifetime
}
}
}