Files
2020-09-29 16:52:17 +03:00

308 lines
12 KiB
C#

// **************************************************************************
// Copyright (c) VMware, Inc. All rights reserved. -- VMware Confidential.
// **************************************************************************
using System;
using System.Collections.Generic;
using System.IdentityModel.Selectors;
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 {
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 {
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;
}
#endregion
}
}