Not able to connect from Windows Application to IdentityServer4 with SSL - 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.

Related

Unable to authenticate to http API when using public url from same machine (Kestrel/.NET7)

I have a .NET7 service which is running kestrel to host an http API (REST controller). The service uses windows authentication with a local windows account. There is an SSL certificate installed and the service is running on a Windows VM in Azure.
When I access the service using a browser or httpClient from my home PC everything works great. e.g. https://blah.myservice.com:21000/api/foo - this challenges me for credentials, I put them in and it returns data and the browser is happy with the SSL cert.
When I access the service in the same way from another Azure VM on the same network it also works as expected.
The issue is that when I access the public URL from the same machine that the service is running on I get a 401 unauthorized response from the service.
If I do https://localhost:21000/api/foo then it challenges me for credentials and returns data just fine, but the browser is not happy with the SSL cert because the domain in the browser does not match. That's not a mystery, obviously. But the service does work. It also works using the local network IP address of the machine.
I don't understand why I get a 401 when using the public URL - it's hitting the right service because I can see the request come in through the log files, it just won't authenticate after challenging me.
The reason this bothers me is that I have a number of services running on a few VMs - sometimes they take data from each other which means they have to effectively connect to localhost to call the REST controllers on another service. This will fail with a 401 if I use the public URL, but will also fail if I use "localhost" because the certificate does not validate. e.g. this code fails when going from one service to another on the same host (or just running it as a console app on the same server):
var credentials = new NetworkCredential("username", "password");
var httpClientHandler = new SocketsHttpHandler { Credentials = credentials };
HttpClient httpClient = new HttpClient(httpClientHandler, true);
try
{
string result = await httpClient.GetStringAsync("https://blah.myservice.com:21000/api/foo");
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
try
{
string result = await httpClient.GetStringAsync("https://localhost:21000/api/foo");
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Both of the above requests fail - I realise I can set the RemoteCertificateValidationCallback to always return true but that's a hack and I have a valid SSL cert so it makes no sense to do that.
Is anyone able to explain why this doesn't work and how to fix it?

WCF Request throwing error when connecting with the certificate

Am trying to connect to saop service developed by a third party they use certificate authentication. I have the certificate and the WSDL file. I tested the request in Soap UI and postman by adding the certificate, everything is working fine there.
Now I tired to implement the same in .net core using WCF connected service. This time am getting the following error even though i added the certificate from StoreLocation.
HL7SOAPEndPointSvcSoapClient hL7SOAPEndPointSvcSoapClient = new HL7SOAPEndPointSvcSoapClient(EndpointConfiguration.HL7SOAPEndPointSvcSoap, "endpointtoconnect");
hL7SOAPEndPointSvcSoapClient.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.Root, X509FindType.FindByIssuerName, "certificateiisuername");
submitMessageRequest submitMessageRequest = new submitMessageRequest() {
Body = "meesege to sent"
};
hL7SOAPEndPointSvcSoapClient.OpenAsync();
submitMessageResponse submitMessageResponse = await hL7SOAPEndPointSvcSoapClient.submitMessageAsync(submitMessageRequest);
The error am getting is
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was "".
Am not sure what is causing the issue because the same certificate is working fine in Soap UI and postman.
I find the solution for the issue, We need to add the binding settings as follow. once i added the below setting it started working
BasicHttpBinding b = new BasicHttpBinding();
b.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.Transport;
b.Security.Transport.ClientCredentialType=HttpClientCredentialType.Certificate;
It might help other, Thanks

CrateDB cannot connect in HttpEndpoint to remote secure server

I've been testing crateDB 3.3.4 for a few weeks now, and I've always been connecting through localhost (127.0.0.1) in http. I've been bulk importing data with HttpEndpoint on my localhost successfully.
I'm now testing on a cloud cluster in https. I manage to open Chrome and logon on the server, but I cannot manage to remote in C# via HttpEndpoint.
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("https://remoteServerUrl:4200/_sql");
httpWebRequest.Method = "POST";
httpWebRequest.Credentials = new NetworkCredential("username", "password");
httpWebRequest.Timeout = 600000;
httpWebRequest.ContentType = "application/json";
using(var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(request);
streamWriter.Flush();
}
HttpWebResponse response = (HttpWebResponse)httpWebRequest.GetResponse();
success = response.StatusCode == HttpStatusCode.OK;
When I try the following code, I always get "The underlying connection was closed: An unexpected error occurred on a send." and in the exception, I see "Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host."
Any Idea what I'm doing wrong here? I was doing the same thing before, on my localhost, but without specifying credentials, and it was working great.
Assuming from your code sample you are using password authentication. Permanent solution would indeed be using autorization header.
As described here https://crate.io/docs/crate/reference/en/latest/admin/auth/methods.html#password-authentication-method
It's not a permanent solution but for test purposes it works. I worked around the problem by adding the Authorization Header directly in my httpwebRequest.
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, "SomeBasicauthenticationToken");
To find the authentication token to pass, simply put the username and password in a basic authentication token generator like this one :
https://www.blitter.se/utils/basic-authentication-header-generator/
But if anyone has a permanent solution, I would still like to see what it is.

Certificates across servers and WCF

I have a website, wcf service, and a security token service (STS) running on one server. Everything works great. I am now trying to now seperate the peices across servers. When the website trys to login to get the token I get ssl cert errors.
This would be on Server 2008 and IIS 7.5 and my windows 7 IIS 7.5 while i debug.
An error occurred while making the HTTP request to https://x.x.x.x/STS/issue/wstrust/mixed/username. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by...
I generated a self signed cert on the STS server and exported it to the website server. I also exported the key and gave IIS access to the key on the website server. That got past a bunch of WIF errors, it would not run, but I'm not sure that its the right thing to do.
I also have tried [netsh http add sslcert ipport:0.0.0.0:44400 ect...] but im not sure what port to use, ive tried a half dozen different ones and none seem to work, and 443 wont work.
The website is using a WSTrustChannelFactory to create the connection. It bombs on the channel.issue command at the bottom.
var factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress(signInEndpoint));
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = userName;
factory.Credentials.UserName.Password = password;
var channel = factory.CreateChannel();
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointAddress(realm),
KeyType = KeyTypes.Bearer
};
try
{
var genericToken = channel.Issue(rst) as GenericXmlSecurityToken;
** EDIT **
I've also set website servers iis default website https bindings port 443 to use the cert that i imported from the STS server and get the same error.
** End Edit **
I've been all over google and stackoverflow and while many questions seem to be close, none of the approved answers have worked.
Ideas? I'm a server/hardware noob so the "for dummies version" would be nice.
Thanks!
Since u are using a self signed certificate, have u made sure to turn off Certificate Chain Validation or else add it to the trusted store. It looks like u are using the url of IdentityServer, in there u can turn off strong endpoint requirements and on the client use a UserNameWSTrustBinding with only message security.

Issue Contacting ADFS Endpoint When on Server

I have a service that is setup to retrieve a secure token from ADFS and use that token to communicate with other services. When I contact my ADFS windowsmixed endpoint from my local development machine hitting the ADFS service I am able to successfuly retrieve the token. However, when I install my service on the same machine that is running ADFS I receive the following error:
Secure channel cannot be opened because security negotiation with the remote endpoint has failed. This may be due to absent or incorrectly specified EndpointIdentity in the EndpointAddress used to create the channel. Please verify the EndpointIdentity specified or implied by the EndpointAddress correctly identifies the remote endpoint.
I am able to reproduce the error with the following code that simply gets the token. Again this code works when I am on my dev machine hitting the remote server, but it fails when on the server directly. I am using the same user credentials on both. I get the same error within the IIS web service using the app pool credentials and with a simple test client using the code below.
private static SecurityToken GetToken()
{
string stsEndpoint = "https://adfsserver.com/adfs/services/trust/13/windowsmixed";
string appliesTo = "http://domain.com/application/myapplication";
var factory = new WSTrustChannelFactory(
new WindowsWSTrustBinding(SecurityMode.TransportWithMessageCredential),
stsEndpoint);
factory.TrustVersion = TrustVersion.WSTrust13;
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointAddress(appliesTo),
KeyType = KeyTypes.Symmetric
};
var channel = factory.CreateChannel();
return channel.Issue(rst);
}
I turned on tracing in the Windows Event Log for ADFS 2.0 debug. When hitting that windowsmixed endpoint directly on the server, I do not receive any entries which leads me to belive that it is not actually getting to the endpoint.
I do receive quite a few audit failures in the security log that are related to the services that I am running:
A handle to an object was requested.
Subject:
Security ID: DOMAIN\ODI$ODIController
Account Name: ODI$ODIController
Account Domain: DOMAIN
Logon ID: 0x1a574b5
Object:
Object Server: SC Manager
Object Type: SERVICE OBJECT
Object Name: WinHttpAutoProxySvc
Handle ID: 0x0
Process Information:
Process ID: 0x1f8
Process Name: C:\Windows\System32\services.exe
Access Request Information:
Transaction ID: {00000000-0000-0000-0000-000000000000}
Accesses: Query status of service
Start the service
Query information from service
Access Reasons: -
Access Mask: 0x94
Privileges Used for Access Check: -
I am able to access the usernamemixed endpoint using stored credentials and receive the proper token, so it seems to be something with authenticating the user to even be able to communicate with the ADFS endpoint.
If I set specific credentials in the code above, it is able to connect. Which again leads me to believe that it is not passing the correct credentials for my Windows user when on the same machine.
factory.Credentials.Windows.ClientCredential = new System.Net.NetworkCredential("UserID", "password1", "dev.domain");
Thank you for any assistance you can provide.
Brian
I had a similar issue. I was able to get it working using the example from here: http://blogs.southworks.net/mwoloski/2009/07/17/getting-a-token-from-adfs-ex-geneva-server-using-wcf/
The difference between your code and the working example is that you modify the message security to use the current security credentials in the binding rather than on the client. If you are using WIF 4.0, you need to modify the code to use a WSTrustChannelFactory instead of WSTrustClient. The other code doesn't change much though.
My code for the factory looks like this:
var binding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential);
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
binding.Security.Message.EstablishSecurityContext = false;
var factory = new WSTrustChannelFactory(
binding,
new EndpointAddress(new Uri(sts), EndpointIdentity.CreateUpnIdentity(adfsUpn)));