LDAPS: Using .NET 4.7.2 System.DirectoryServices.dll - vb.net

I am trying to update my code to get user information from an AD that must use LDAPS calls, not LDAP.
Currently we are using the System.DirectoryServices.dll but I cannot find a way to hit the AD using LDAPS, only LDAP.
Here is how we are defining our entry and searcher objects.
'''
If (ADactive) Then
Dim Entry As New System.DirectoryServices.DirectoryEntry(ADFullPath, Username, Password)
Dim Searcher As New System.DirectoryServices.DirectorySearcher(Entry)
Searcher.SearchScope = DirectoryServices.SearchScope.Subtree
Try
Dim Results As System.DirectoryServices.SearchResult = Searcher.FindOne
Success = Not (Results Is Nothing)
rtn_error = ""
Catch ex As Exception
Success = False
rtn_error = ex.Message
End Try
ADUserName = Username
ADPassword = Password
End If
Return Success
'''
I've verified this code works to hit our AD and I can login using my credentials. Our ADFullPath is
LDAP://XXXXXX
Where the "XXXXX" is my AD server.
Are there different properties to my searcher object that I need to set to enable LDAPS?

You need to specify the LDAPS port (636) in your LDAP path, like this:
LDAP://XXXXXX:636
That's all.
However, all the same rules for SSL apply here. This will only work if:
The domain name on the SSL certificate matches the domain name you're using. So if you use LDAP://example.com:636, then the cert must be issued to (or have a Subject Alternative Name of) example.com.
The certificate is issued by an authority that the client computer trusts. If the cert is self-signed, it will fail.

Related

Check a website using HTTPS/SSL and if the certificate is invalid give user the option to trust it anyway

I have a application which accesses devices through HTTP or HTTPS. All these devices are on the internet and usually the customer gives us direct IP access with a firewall forwarding rule allowing only our external IP address in. I.e. the connection is relatively secure as only we are allowed access.
I want my application to check the site and see if it's using a valid certificate and if not give the user the option to save the certificate to the computers store so the device is trusted in the future. I do not want to blindly accept any certificate ( re: Accept self-signed TLS/SSL certificate in VB.NET ) but more download the certificate like this python example: How to get response SSL certificate from requests in python? . But I'm trying to do the equivalent in VB.Net
I also found this example using OpelSSL to get the certificate which I would consider if there is no other way to do this: https://www.baeldung.com/linux/ssl-certificates and also a decent example in Java: https://self-learning-java-tutorial.blogspot.com/2017/12/how-to-get-client-certificate-from.html but in both cases I'm having trouble getting that into a VB.Net way of doing it.
Another option is this one listed here Is it safe to test the X509Certificate.Thumbprint property when you know an invalid certificate is safe? where they are getting the thumbprint of a certificate and then comparing it against a known list. That would also work, I would get the thumbprint on the initial connection and store it with the device record and use that. But again I'm having trouble getting this into a workable format in VB.Net.
Does anyone have a idea of how I would go about this? Currently I'm doing my test using a simple WebRequest and looking for a status OK and if I don't get that checking the exception for the invalid certificate. I have gotten that far so I know when it is a site with a invalid certificate but now I need to figure out a way to save that information so I can connect to it in the future.
After more searching I figured this out. Here is my quick check to see if there is a valid cert and prompt to install it:
Try
Dim request As HttpWebRequest = CType(WebRequest.Create(ServerAddressTextEdit.Text), HttpWebRequest)
Dim response As HttpWebResponse = Nothing
response = CType(request.GetResponse(), HttpWebResponse)
Dim responseStatus As String = (CType(response, HttpWebResponse)).StatusDescription
Debug.WriteLine(responseStatus) ' If the conection was good then we can just continue.
Catch ex As Exception ' We have a exception. Check for a invalid certificate or otherwise just let the user know.
Debug.WriteLine(ex.Message)
If ex.InnerException.Message Is Nothing Then
ResultsMemoEdit.Text = "Connection to the device failed. Reason given: " & ex.Message & vbCrLf
Else
If ex.InnerException.Message.Contains("The remote certificate is invalid according to the validation procedure") Then
If MsgBox("The connection was sucessful however the site has a invalid SSL Certificate. The program can attempt to download the invalid certificate and trust it for future communications. Only do this if you trust the device for secure communications. Do you want to do this?", MsgBoxStyle.YesNo, "Trust Invalid Certificate?") = MsgBoxResult.Yes Then
Dim cert As X509Certificate = request.ServicePoint.Certificate
Dim cert2 As New X509Certificate2(cert)
Dim certData As Byte() = cert2.Export(X509ContentType.Cert)
InstallCertificate(certData)
End If
End If
End If
Finally
If response IsNot Nothing Then response.Close()
End Try
Then the function to install it:
Private Function InstallCertificate(certData As Byte()) As Boolean
Try
Dim certificate As New X509Certificate2(certData)
Dim store As New X509Store(StoreName.TrustedPublisher, StoreLocation.LocalMachine)
store.Open(OpenFlags.ReadWrite)
store.Add(certificate)
store.Close()
Return True
Catch ex As Exception
Return False
End Try
End Function
My program already runs as a admin so this all works. Will modify to allow the certificate name to be changed, probably using the device IP address, and also some extra checks to make sure the date is valid.
Now I have to get the computer to actually trust it as I'm still getting a error on connecting.

Not able to connect from Windows Application to IdentityServer4 with SSL

I have a Windows application that is using the "password" grant type. It is able to authenticate to the Identityserver4 without SSL, but not with SSL. The problem is that it is giving an error:
The underlying connection was closed: An unexpected error occurred on a send
I tried it from postman, and it worked, but not from my Windows Application. Below is the code:
var tokenClient = new TokenClient($"{IdentityServer}/connect/token", Constants.ClientId, Constants.ClientSecret);
var tokenResponseTask = tokenClient.RequestResourceOwnerPasswordAsync(username, password, Constants.Scope);
tokenResponseTask.Wait();
return tokenResponseTask.Result;
Below also is another code the I tried, but it doesn't work:
TokenResponse tokenResponse;
string request = $"client_id={clientId}&client_secret={clientSecret}&grant_type={grantType}&scope={scope}&username={username}&password={password}";
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
byte[] result = client.UploadData(endpointUrl, "POST", Encoding.UTF8.GetBytes(request));
string resultJson = Encoding.UTF8.GetString(result, 0, result.Length);
tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(resultJson);
}
Finally, I was able to find the solution under the following link:
Authentication failed because remote party has closed the transport stream
'The underlying connection was closed' error is often seen when the SSL handshake fails.
SSL handshake failure usually has something to do with the relevant SSL certificate and whether or not the certificate is trusted.
Check ...
Whether IdentityServer is configured to run under HTTP and HTTPS.
Your Windows Application is correctly configured for SSL.
Test some of the IdentityServer endpoints using a browser with the https protocol.
Hope this gets you going on a helpful investigation path.

Identifying correct client certificate for ServerXMLHTTP.SetOption

I have three client certificates installed in Windows 7 and need to use a specific one to authenticate a ServerXMLHTTP60 call using VBA.
Calling ServerXMLHTTP60.SetOption with the friendly name of the certificate returns with no error. But the subsequent .send fails with "A certificate is required to complete client authentication".
Code example:
Public Sub TestCert()
Dim myHTTP as New ServerXMLHTTP60
Dim myURL as String
' Open the connection to the secure server
myHTTP.Open "GET", "https://server/finalpath", False
' Attempt to set the correct client certificate
' I have also tried just the friendly name as well as
' LOCAL_MACHINE\My\cert friendly name'
myHTTP.SetOption 3, "CURRENT_USER\My\cert friendly name"
' Send request fails with "A certificate is required ..."
myHTTP.Send
End Sub
The specified certificate is working fine via IE or Firefox with this site. I must be using an incorrect pathname for the certificate. Is there a way to determine the correct client certificate pathname to ensure success?
This drove me mad for a couple of days but...
Assuming you install your client to default store under current user and your certificate has subject cn=mycert then this seems to work. Running office16, windows 10, winhttp5.1
Dim apiConnection As New WinHttp.WinHttpRequest
' Set the authentication settings
apiConnection.SetClientCertificate "mycert"
apiConnection.Open "Get", "https://localhost:8443", False
apiConnection.Send

EWS Connections Issues - 401 Unauthorized

Trying to connect to exchange 2010 SP1 using EWS & VB.Net. When i try to use autodiscovery it works just fine. The problem being is it connects to my local exchange mailbox and thats not what i need. We have a mailbox that the exchange admins set up that all the programmers can connect to (call it TestMailbox). So when i do:
exchange.AutoDiscoverUrl("TestMailbox#MyDomain.com")
It connects to my local mailbox rather than the "TestMailbox". I got the password for the TestMailbox NT account from our admin and tried all of the following:
exchange.Credentials = New WebCredentials("TestMailbox#MyDomain.com", "Password")
exchange.Credentials = New WebCredentials("TestMailbox", "Password")
exchange.Credentials = New WebCredentials("TestMailbox", "Password","MyDomain")
exchange.Credentials = New WebCredentials("MyDomain\TestMailbox", "Password")
all of them fail. Say my NT username on my local net work is "User" i even tried:
exchange.Credentials = New WebCredentials("User#MyDomain.com", "MyPassword")
and it failed. I have been using the following Link for reference.
Edit 1: i have tried all the above with NetworkCredential rather than WebCredential and it still fails.
We figured it out. TheTestMailbox & ProdMailbox domain accounts were both setup to only allow certain computer to login locally.

Unable to sign security tokens with certificate in WIF scenario

I'm trying to implement a custom STS for a WIF scenario I'm investigating, but it's failing. It's failing when trying to obtain the private key from the certificate used to sign the tokens. I create the STS with the following configuration:
var signingCert = new X509Certificate2(#"C:\<path>\MySigningCertificate.pfx");
var config
= new SecurityTokenServiceConfiguration()
{
DisableWsdl = true,
TokenIssuerName = "Tribold",
SecurityTokenService = typeof(TriboldSecurityTokenService),
SigningCredentials = new X509SigningCredentials(signingCert),
CertificateValidationMode = X509CertificateValidationMode.Custom,
CertificateValidator = new CertificateValidator()
};
However, with WCF diagnostic logging configured, I get the following message in the Service Trace Viewer:
The private key is not present in the X.509 certificate.
This appears to be logged as the code comes out of my custom STS (i.e., after calling GetOutputClaimsIdentity(...) on my custom STS class, and therefore I can only assume that it's now trying to sign the issued security token and failing because it can't obtain a private key to do so.
The private key appears to be present on the loaded certificate:
Debug.Assert(signingCert.HasPrivateKey == true);
but it fails later on. I'm having no luck resolving this, please help!
It looks like thread "cant use .pfx file for X.509 certificates" in the Geneva (= AD FS 2.0) forums covers the same problem which you report. So the resolution reported there might work, which is "specifying the X509KeyStorageFlags.PersistKeySet flag when initiating the X509Certificate2 object".
I'd be surprised if you didn't have to specify a password when opening a PFX file. X509Certificate2 has overloads that take a password in the form of a string or a SecureString.