I got pretty stuck with a problem in Xamarin.Forms (Forms though, but I only have an Android project, I need to support only that).
The app must post to the backend, and the backend do SSL cert validation.
I have a test device, an Android 11 Samsung. Among the user certificates on the device, there is the cert I need (Settings - Security - User certificates).
When I open a Google Chrome on my phone, it loads the swagger UI of the backend, and I think it first asked me if I wanted to use my cert.
The swagger works, I was able to try the endpoints there.
The problem is that I can't make a backend call from the app because it immediately drops my request with an SSL certification validation failed message.
I wrote some quick test code with exact namespaces to understand what I'm doing:
// This returns the cert of the user's certificates:
Java.Security.Cert.X509Certificate myJavaCert = KeyChain.GetCertificateChain(this.ApplicationContext, "MyCertAlias").FirstOrDefault();
//Convert to X509Certificate2:
var myDotNetCert = new System.Security.Cryptography.X509Certificates.X509Certificate2(myJavaCert.GetEncoded());
//I'm doing HttpClient manually, I don't want to use IHttpClientFactory yet:
var httpClientHandler = new HttpClientHandler();
httpClientHandler.ClientCertificates.Add(myDotNetCert);
var httpClient = new HttpClient(httpClientHandler);
// Finally I call the post that runs for the above mentioned error:
await httpClient.PostAsync(url, objectToPost);
I’m pretty stuck with this task, I don’t really know where to try.
Thanks for the help in advance too!
After one week of research I finally figured it out to myself.
Here is the full-detailed answer for my own question:
Xamarin Forms (Android) Client certificate from KeyStore vs PFX file
Related
so here's a quick explanation of my issue - my current setup is and IdentityServer4 implementation with ASP.NET Core Identity, an API resource protected by it and a Xamarin.Android application that is the client. My current issue is that the client(Android) cannot get anything from the API because of the following error(from the API logs):
"Bearer" was not authenticated. Failure message: "IDX10205: Issuer validation failed. Issuer: 'http://10.0.2.2:5000'. Did not match: validationParameters.ValidIssuer: 'null' or validationParameters.ValidIssuers: 'http://127.0.0.1:5000'."
Basically, since I'm using the Android emulator, in order to call something that's on localhost on my machine, I need to use the 10.0.2.2 URL for it. Then the problem pops up - the Identity Server is fine with authenticating, I can login fine, I get an access token, but after that I need to call the API. And that's where the error happens - it's expecting an issuer that is with the same authority(127.0.0.1:5000) but receives the 10.0.2.2:5000, which is the authority for the Android client.
So, my question is - is there a way to somehow specify that 10.0.2.2 is also a valid issuer, or do I have to start thinking about deploying both the API and the Identity Server just so I can test the client. I'd really like it if there was a way to have the whole solution running on my local machine rather than having to deploy for every little thing I want to try out.
Any help will be appreciated very much.
First: Given the standard, you manage just one Issuer.
Are you managing your own Identity / Token generation? It sounds like this isn't the case.
You could customize your API for creating your tokens explicitly. Then, you can indicate a global Issuer (like your project url) so anyone can validate against the same.
var token = new JwtSecurityToken(
issuer: "http://my-perfect-proj.net",
claims: ...,
notBefore: DateTime.Now,
expires: DateTime.Now.AddHours(1),
signingCredentials: ...)
);
After your token is created and sent, validate your incoming request based on your tastes (checking time, user's data, issuer).
ASP.NET Core JWT Bearer Token Custom Validation
Creating RESTful API with Authentication
EDIT: Using Xamarin and Visual Studio on the same machine, didn't gave me this kind of problems but in that case, I was using Visual Studio Emulator. You could give it a try and avoid doing other types of workarounds.
So, I managed to work around the issue by simply running the Web part of it so it's visible on my local network. What I did in more detail - in the Program.cs where I create the host, I use the .UseUrls("http://*:5001") method, and then I run the app with dotnet run.
In this way your app is accessible in your local network via the IP address of your machine and the port you've specified. Also, in order for this to work, you'd have to define a new Outbound Rule in your Firewall to allow traffic through that port you're using. Hope this helps someone else as well, this turned out to be the easiest way to get what I need to work, and that's after fighting with IIS for a while trying to get it to work through there as well.
Short answer: In IIS, don't leave the site binding host name set as blank.
Longer explenation:
I received a similar error, but could see that for some reason it was trying to match the issuer domain name vs IP (the domain does point to the IP, but I guess it tries to validate the two strings). I could see this error after allowing logging : IdentityModelEventSource.ShowPII = true.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidIssuerException:
IDX10205: Issuer validation failed. Issuer: 'http://ec2XXXXXom'. Did
not match: validationParameters.ValidIssuer: 'http://34.111.111.29' or
validationParameters.ValidIssuers: 'null'. at
Microsoft.IdentityModel.Tokens.Validators.ValidateIssuer(String
issuer, SecurityToken securityToken, TokenValidationParameters
validationParameters)
In IIS I previously had the host name set as blank (I am using the server name as domain name) - and therefore it set the issuer using the IP of the server. When I specifically set the site domain name, it worked.
I am developing a Xamarin mobile Android app. For data access, the app uses a Portable class library to make webservice calls to the back end. I’m using the Portable class library so that I can share it with an iOS version of the mobile app later. The data is sensitive and requires SSL for all communications which is configured in the WebAPI web service project. It uses oAuth for authentication.
The challenge I’m running into is that the initial request to authenticate is failing when I run it locally with the following error:
System.Net.Http.HttpRequestException: An error occurred while sending the request
System.Net.WebException: Error: TrustFailure (The authentication or decryption has failed.)
System.IO.IOException: The authentication or decryption has failed.
Some additional information:
I am using the following built in Visual Studio emulator and version - Android_Accelerated_x86 (Android 6.0 – API 23).
I am currently running it on localhost and following is the code snippet for this call:
HttpClient client = new HttpClient(new NativeMessageHandler())
{
BaseAddress = new Uri("https://10.0.2.2:44342/") // I also tried installing it on IIS and using port 443 on localhost. Same problem.
};
var content = new StringContent("grant_type=password&username=[USER_NAME]&password=[PASSWORD]", Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsync("Token", content).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
var stuffList = JsonConvert.DeserializeObject<List<Stuff>>(data);
return stuffList;
}
else
{
return new List<Stuff>();
}
The call works when I test it through Fiddler on localhost, so I know that everything is configured correctly on the web service end and with authentication. But from the emulator my understanding is that I need to use IP address 10.0.2.2. I have create a self-signed cert and that hasn’t seemed to help.
I have also attempted to use Fiddler as a middleman, but I’m not seeing any activity in Fiddler when I run the app locally. I have also tried to change the network settings of the emulator, but it doesn’t appear to be having any affect. The base emulator seems to be fairly limited in these settings, but I also don’t want to pay for a more advanced one at this point in time. I have seen a number of posts with similar issues, but none of the existing recommendations that I have found are helping. Any help would be greatly appreciated!
There was recently certificate change on staging servers of my app. The server passes Qualys SSL test with grade A- ("The server does not support Forward Secrecy with the reference browsers. Grade reduced to A-") so I should be able to connect via https without adding any certs to my app, keystore or whatever. Indeed, the standard Android connection method works well (http://developer.android.com/training/basics/network-ops/connecting.html).
The problem is, I am using android-async-http all over the code, which uses org.apache.http.client. And that returns javax.net.ssl.SSLPeerUnverifiedException: No peer certificate when I connect to the site!
I can't really change the connection method in current circumstances. I'd like to stay with android-async-http and connect to my site without bypassing the SSL security.
Any tips? Some additional settings to android-async-http? Or maybe altering android-async-http source code would help?
I encountered a same problem 6 months back.
I think you will be able to solve it by :
MySSLSocketFactory extends SSLSocketFactory
Then u need to use this Class where you are creating an instace of HTTPClient and pass some parameters...
I think the link below would be helpful. If it doesn't help then i can share concrete code later...
https://stackoverflow.com/a/13812958/1386533
I'm trying to make a connection to an LDAP server in my Android app, and am using the UnboundID SDK. Recently, a change was made from unsecured to secured LDAP, and I have to change the app accordingly. I have been given the SSL certificates file to validate against. I've already used the file to make a keystore as described here. I've got this keystore file in the assets folder of my app, and am pulling from that. The code below does not currently work, and throws the exception:
LDAPException(resultCode=01 (connect error), errorMessage=('An error occurred while attempting to connect to server place.myserver.com:636: javax.net.ssl.SSLHandShakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found
// code from above link
AssetManager assetManager = getApplicationContext().getAssets();
InputStream keyStoreInputStream = assetManager.open("yourapp.store");
KeyStore trustStore = KeyStore.getInstance("BKS");
trustStore.load(keyStoreInputStream, "myPassword".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustStore);
// my code
SSLUtil sslUtil = new SSLUtil(tmf.getTrustManagers());
LDAPConnection connection = new LDAPConnection(sslUtil.createSSLSocketFactory());
connection.connect("place.myserver.com", 636);
However, the code segment:
SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
LDAPConnection connection = new LDAPConnection(sslUtil.createSSLSocketFactory());
connection.connect("place.myserver.com", 636);
does work (although I was informed by the higher-ups that this would be insecure).
I'm not quite sure as to what exactly I'm doing wrong here, so any help would be appreciated. Also, if there is a better way of accomplishing this than what I'm attempting to do above, feel free to let me know :) I would like to stick with the UnboundID library though, since the rest of the code is already written using that as well, and everything works if I use the TrustAllTrustManager.
It's true that the trust all trust manager isn't secure. It's convenient for testing purposes, but it will allow a bad guy to set up his own server with a certificate he generates for himself and use it to impersonate the real server, or to operate as a man in the middle, intercepting and potentially alerting any communication between the client and the real server. With a more strict trust manager in place, the client should reject the bogus certificate that the fake server will present.
Unfortunately, though, it looks like the trust manager you're trying to use in this case doesn't like the certificate that your server is presenting to it. Because the trust all trust manager allows you to establish the connection, that means that your server does have a certificate and is capable of performing SSL communication, but there's something about that certificate that your trust manager doesn't like. It's almost certainly not an issue with the LDAP SDK, since the same problem should arise with any other LDAP API if you're using the same trust store.
If you look at the result, it has a message of "Trust anchor for certification path not found". This implies that neither the certificate the server is using nor those of any of its issuers was found in the trust store. You'll need to import the server certificate (or the certificate of one of its issuers) into the trust store that you're using. It sounds like you've tried to do that, but since it's not working then something must not be quite right with the way it was done. I'd recommend working wit the directory server administrator to ensure that you're trying to import the right certificate based on the server configuration.
I'm trying to hit an https url with my app. I've followed this tutorial. The store I've created has the correct CA. However, when I try to make the connection, I get the following error:
ERROR/IOException(1843): webPost: javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
I've done some reading about this error and people have decided to allow their apps to accept all certificates. I don't think that's really acceptable. What should I check next to see what the issue is?
You can configure your device to ignore SSL certificates:
http://www.virtualzone.de/2011-02-27/how-to-use-apache-httpclient-with-httpsssl-on-android/(dead link)
UPDATE: Much better answer is visible here:
Trusting all certificates using HttpClient over HTTPS
Or do things specific to your HttpClient version:
HttpGet with HTTPS : SSLPeerUnverifiedException