I am facing an issue regarding certificate pinning on Xamarin Forms, bot android and ios.
public static async Task<HttpResponseMessage> SendWebApiRequest(HttpRequestMessage msg)
{
try
{
int timeout = 60;
var handler = new HttpClientHandler
{
UseProxy = true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
handler.ServerCertificateCustomValidationCallback = CheckCertificate;
using (HttpClient client = new HttpClient(handler))
{
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
using (CancellationTokenSource cts = new CancellationTokenSource())
{
cts.CancelAfter(TimeSpan.FromSeconds(timeout));
HttpResponseMessage reply = await client.SendAsync(msg, cts.Token);
ProcessResponseStatus(reply);
if (reply.StatusCode == HttpStatusCode.Unauthorized)
throw new InvalidOperationException("The authentication failed. Please logout and logback in with a valid account");
return reply;
}
}
}
catch (InvalidOperationException) {
throw new InvalidOperationException("There was an issue connecting with the server, please try again later or contact support.");
}
catch (WebApiServiceExceptions) { throw new WebApiServiceExceptions(WebApiServiceExceptionType.NoInternetAccess, "No internet connection detect! Please check your internet connection!"); }
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw new Exception("There was an issue connecting with the server, please try again later or contact support.");
}
}
private static bool CheckCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
{
var publicKey = "MY PUBLIC KEY";
return publicKey == certificate?.GetPublicKeyString();
}
It was working fine but suddenly started throwing errors "The SSL connection could not be established, see inner exception."
On Android
Ssl error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED
Stack Trace:
at Mono.Net.Security.MobileAuthenticatedStream.ProcessAuthentication (System.Boolean runSynchronously, Mono.Net.Security.MonoSslAuthenticationOptions options, System.Threading.CancellationToken cancellationToken) [0x0025c] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System/Mono.Net.Security/MobileAuthenticatedStream.cs:310
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore (System.IO.Stream stream, System.Net.Security.SslClientAuthenticationOptions sslOptions, System.Threading.CancellationToken cancellationToken) [0x0007b] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corefx/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs:165
On iOS
The authentication or decryption has failed.
Stack Trace:
at Mono.AppleTls.AppleTlsContext.EvaluateTrust () [0x000c7] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/Mono.AppleTls/AppleTlsContext.cs:307 at Mono.AppleTls.AppleTlsContext.ProcessHandshake () [0x00075] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/Mono.AppleTls/AppleTlsContext.cs:213 at Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake (Mono.Net.Security.AsyncOperationStatus status, System.Boolean renegotiate) [0x000da] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/Mono.Net.Security/MobileAuthenticatedStream.cs:715 at Mono.Net.Security.AsyncHandshakeRequest.Run (Mono.Net.Security.AsyncOperationStatus status) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/Mono.Net.Security/AsyncProtocolRequest.cs:289 at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation (System.Threading.CancellationToken cancellationToken) [0x000fc] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/Mono.Net.Security/AsyncProtocolRequest.cs:223
P.S: It is an Azure function app certificate.
Bypass the certificate using this code:
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
HttpClient client = new HttpClient(clientHandler);
Related
I use HttpClient object for PostAsync. I need to add BackgroundSessionConfiguration for iOS while I am creating HttpClient object. So I changed my code like this:
var configuration = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration ("my.app.identifier");
_client = new HttpClient (new NSUrlSessionHandler (configuration));
This works when I send first request with PostAsync. But when I send request second time, it doesn't work.
I did it for Login Operation like this: (It works first time but if I logout and login again, it doesn't work.)
public class LoginService
{
private HttpClient _client;
public LoginService()
{
if (_client == null)
{
_client = Helper.CreateHttpClientLogin(_client);
}
}
public async Task<LoginResponse<LoginDataResponse>> Login(LoginRequest request)
{
LoginResponse<LoginDataResponse> responseModel = new LoginResponse<LoginDataResponse>();
try
{
string json = JsonConvert.SerializeObject(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var jsonBody = await _client.PostAsync(App.ServiceURL.Login_Url, content);
string jsonstr = await jsonBody.Content.ReadAsStringAsync();
if (jsonstr == null || jsonstr == "")
{
responseModel.Success = false;
responseModel.Status = 0;
responseModel.Message = AppResources.UnknownHostException;
}
else
responseModel = (LoginResponse<LoginDataResponse>)JsonConvert.DeserializeObject(jsonstr, typeof(LoginResponse<LoginDataResponse>));
}
catch (Exception ex)
{
string text = ex.ToString();
responseModel.Status = 0;
AppResources.Culture = CrossMultilingual.Current.CurrentCultureInfo;
responseModel.Message = AppResources.UnknownHostException;
}
return responseModel;
}
}
public class Helper
{
public static HttpClient CreateHttpClientLogin(HttpClient _client)
{
if (Device.RuntimePlatform == Device.iOS)
{
var configuration = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration("my.app.identifier");
_client = new HttpClient(new NSUrlSessionHandler(configuration));
}
else
{
//_client = new HttpClient(new System.Net.Http.HttpClientHandler());
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
_client = new HttpClient(handler);
}
return _client;
}
}
And I have this code on AppDelegate: (I don't know but maybe it causes the bug)
public static Action BackgroundSessionCompletionHandler;
public override void HandleEventsForBackgroundUrl(UIApplication application, string sessionIdentifier, Action completionHandler)
{
// We get a completion handler which we are supposed to call if our transfer is done.
BackgroundSessionCompletionHandler = completionHandler;
}
What must I do for this?
Edit:
I solved the problem I mentioned above by creating the Login Service object once the application was first opened. (After logout previously, I was rebuilding every time I login)
But now I have other error. When I run my app on "iPhone 7 plus - iOS 13.6" device I got this error:
System.Net.Http.HttpRequestException: unknown error ---> Foundation.NSErrorException: Error Domain=NSURLErrorDomain Code=-1 "unknown error" UserInfo={NSErrorFailingURLStringKey=https://mydomain/Api/Login, NSErrorFailingURLKey=https://mydomain/Api/Login, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"BackgroundDataTask <E69F3EAF-0AE9-4FAE-A01B-988167B7F6BC>.<3>"
), _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundDataTask <E69F3EAF-0AE9-4FAE-A01B-988167B7F6BC>.<3>, NSLocalizedDescription=unknown error}
--- End of inner exception stack trace ---
at System.Net.Http.NSUrlSessionHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x001d4] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.20.2.2/src/Xamarin.iOS/Foundation/NSUrlSessionHandler.cs:527
at System.Net.Http.HttpClient.FinishSendAsyncBuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) [0x0017e] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/System.Net.Http/src/System/Net/Http/HttpClient.cs:506
at App.Services.LoginService.Login (FileOrbis.Models.RequestModels.LoginRequest request) [0x00084] in C:\Users\PcName\Desktop\App\App\Services\LoginService.cs:40
And simulator log file is:
Startup:
arguments: --device=06098E5B-1853-4A83-8434-8071D8973A14 --launchsim=//Users/deytek/Library/Caches/Xamarin/mtbs/builds/App.iOS/b2c75f2acbd4ff91c305dba10ca791b7/bin/iPhoneSimulator/Debug/App.iOS.app -argument=-monodevelop-port -argument=51890 -setenv=__XAMARIN_DEBUG_PORT__=51890 --sdkroot=/Applications/Xcode.app -h=192.168.1.7 -ssh=deytek --launched-by=devenv-16.0
version: 16.7.0.0 (54a29526ef6f853bdd37adbcc3791ce90ca82735)
Connecting to existing client
Exit:
Exit Code: 0
I encounter with this error when I use Background Session Configuration. If I use normal HttpClient object (without Background Session Configuration), it works
NOTE: I also tried iPhone 5s iOS 12.4.8 and iPad Pro (3rd Generation) iOS 13.6.1 It works these devices. But it doesn't work on iPhone 7 Plus 13.6
I have two web applications.
From one web application, I am trying to communicate with the other application via SignalR.
I am sending data via SignalR using InvokeAsync and waiting for a result on the client.
On the server, with the data sent, I am calling a web api and then I want to send the result as HttpResponseMessage to the SignalR client which is waiting.
But when trying to do so, I get the following error :
{System.IO.InvalidDataException: Connection terminated while reading a message.
at Microsoft.AspNetCore.SignalR.Client.HubConnection.ReceiveLoop(ConnectionState connectionState)
at Microsoft.AspNetCore.SignalR.Client.HubConnection.InvokeCoreAsyncCore(String methodName, Type returnType, Object[] args, CancellationToken cancellationToken)
at Microsoft.AspNetCore.SignalR.Client.HubConnection.InvokeCoreAsync(String methodName, Type returnType, Object[] args, CancellationToken cancellationToken)
at Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.InvokeCoreAsync[TResult](HubConnection hubConnection, String methodName, Object[] args, CancellationToken cancellationToken)
at SecretariatMedical.Services.WebService.LogInAndGetToken(LoginViewModel loginViewModel) in C:\Users\SylvainB\Desktop\aspnetcore\Projet Clinique Charles\SecretariatMedical\SecretariatMedical\Services\WebService.cs:line 82}
Here is the code from the client :
connection = new HubConnectionBuilder()
.WithUrl("https://localhost:44379/ServeurWebServiceSignalRHub")
.Build();
connection.Closed += async (error) =>
{
await Task.Delay(new Random().Next(0, 5) * 1000);
await connection.StartAsync();
};
await connection.StartAsync();
HttpResponseMessage responseSignalR = await connection.InvokeAsync<HttpResponseMessage>("LogInAndGetToken", loginViewModel );
The code on the SignalR Hub Server :
public async Task<HttpResponseMessage> LogInAndGetToken(LoginViewModel loginViewModel)
{
try
{
string apiUrl = "api/authenticationapi/gettoken";
HttpResponseMessage response;
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("https://localhost:44379");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
response = await client.PostAsJsonAsync(apiUrl, loginViewModel);
//ResultLoginViewModel resultLogin = await response.Content.ReadAsAsync<ResultLoginViewModel>();
return response;
}
}
catch (Exception e)
{
HttpResponseMessage responseError = new HttpResponseMessage(HttpStatusCode.InternalServerError);
return responseError;
}
}
The code in my StartUp.cs :
services.AddSignalR().AddJsonProtocol(options =>
{
options.PayloadSerializerSettings.ContractResolver = new DefaultContractResolver();
});
On the SignalR Hub Server, when I try to read the data and send it back as an object ViewModel, the SignalR Client receives it normally.
Does anybody know why there is a problem with transporting a HttpResponseMessage ?
Thanks a lot for your help.
I've got an asp.net core 2.0 web app (Running using Kestrel) with following controller :
public IActionResult GetUpdateList(string apiCode, int softwareId, [FromBody] List<SoftwareFile> updateFiles)
{
try
{
var stream = SoftwareUpdateFilesHandler.GetUpdateZipFileStream(updateFiles, softwareId);
return File(stream.BaseStream, "application/octet-stream", "UpdateFile");
}
catch (System.Exception ex)
{
return NotFound(ex.ToString());
}
}
and this code on my client :
public async static Task<byte[]> GetUpdateAsync(string apiCode, int softwareId, List<SoftwareFile> updatefiles)
{
try
{
StringContent content = null;
if (updatefiles != null && updatefiles.Count > 0)
{
content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(updatefiles));
content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
}
string address = $"{baseAddress}GetUpdate?softwareId={softwareId}";
HttpRequestMessage request = new HttpRequestMessage(new HttpMethod("POST"), address);
request.Content = content;
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
var responseContent = await response.Content.ReadAsByteArrayAsync();
return responseContent;
}
catch(Exception ex)
{
return null;
}
}
But when code reaches to httpClient.SendAsync code hangs and after a few seconds client app crashes and I get this exception : The underlying connection was closed: The connection was closed unexpectedly
All of this works fine when I test my code in local but when I publish code and try to call GetUpdateList I get exception.
Odd thing about this is I can't handle exception in my catch block. Somehow catch block doesn't catch this exception and I can see exception in application crash.
I have been stuck all day on a stupid problem with registering a user to my application.
Here is my code once the 'Register' button is clicked:
public ICommand RegisterCommand
{
get
{
return new Command(async() =>
{
var isSuccess = await _apiServices.RegisterAsync(Email, Password, ConfirmPassword);
if (isSuccess){
Message = "Registered Successfully";
}
else
{
Message = "Retry later";
}
});
}
}
Api services Register Async method:
public async Task<bool> RegisterAsync(string email, string password, string confirmPassword)
{
try
{
System.Diagnostics.Debug.WriteLine("Email: "+email);
var client = new HttpClient();
var model = new RegisterBindingModel
{
Email = email,
Password = password,
ConfirmPassword = confirmPassword
};
var json = JsonConvert.SerializeObject(model);
HttpContent content = new StringContent(json);
// content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync("http://localhost:63724/api/Account/Register", content);
if (response.IsSuccessStatusCode)
{
return true;
}
return false;
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("Error: "+e);
throw;
}
}
}
The Error that I get is:
System.Net.Http.HttpRequestException: An error occurred while sending the request ---> System.Net.WebException: Error: ConnectFailure (Connection refused) ---> System.Net.Sockets.SocketException: Connection refused
at System.Net.Sockets.Socket.Connect (System.Net.EndPoint remoteEP) [0x000b6] in <6c708cf596db438ebfc6b7e012659eee>:0
at System.Net.WebConnection.Connect (System.Net.HttpWebRequest request) [0x0016d] in <6c708cf596db438ebfc6b7e012659eee>:0
--- End of inner exception stack trace ---
To me this is very frustrating as I can register a use using Postman with the exact same localhost address. I am following Houssem Dellai's Xamarin.Forms mvc web api tutorials which can be found here
I had an issue with httpclient during the development of my app. I believe there was an issue with the cross-platform implementation of the httpclient class. iOS didn't know how to handle it.
Instead I implemented a very simple httpclient library called flurl: http://tmenier.github.io/Flurl/
First, you will need to install flurl in all project directories (iOS, Android, and the PCL) then the implementation is very simple.
using Flurl;
using Flurl.Http;
public async Task<User> CreateUserAsync(RegisterUserModel userModel)
{
string url = "your/backend/here";
//resp is a user object received and automatically converted into a c# object through the use of .ReceiveJson<typeofobject>();
var resp = await (url).PostJsonAsync(userModel)
.ReceiveJson<User>();
if (resp.LoginSession != null)
{
//Raise my registered event to let other classes know to proceed
OnUserRegistered(resp);
}
return resp;
}
As you can see it makes httpclient implementation very simple. Hopefully this helps.
I got some exception in testing signalr .net client with custom self-signed certificate.
There was no exception on http.
Is there any problem in setting up the self-signed certificate in my code?
Note that, there is no problem in my certificate file because it runs my https mvc sites well.
server side code : asp.net, azure local fabric
[assembly: OwinStartup(typeof(BookohWebRole.Startup))]
namespace BookohWebRole
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
hubConfiguration.EnableJavaScriptProxies = false;
//GlobalHost.HubPipeline.AddModule(new ErrorHandlingPipelineModule());
app.MapSignalR(hubConfiguration);
}
}
}
public class ChatHub : Hub
{
public override Task OnConnected()
{
Trace.TraceInformation("OnConnected");
var authToken = Context.QueryString.Get("AuthToken");
Trace.TraceInformation("authToken : " + authToken);
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
Trace.TraceInformation("OnDisconnected");
return base.OnDisconnected(stopCalled);
}
public override Task OnReconnected()
{
Trace.TraceInformation("OnReconnected");
var authToken = Context.QueryString.Get("AuthToken");
Trace.TraceInformation("authToken : " + authToken);
return base.OnReconnected();
}
public void Send(string name, string message)
{
Trace.TraceInformation("Context.ConnectionId : " + Context.ConnectionId);
Clients.All.onSend(name, message);
}
}
client side code : .net client, unit test method
[TestMethod]
public void chat()
{
var ev = new AutoResetEvent(false);
Task.Run(async () =>
{
try
{
ServicePointManager.DefaultConnectionLimit = 10;
var queryString = new Dictionary<string, string>();
queryString.Add("AuthToken", Guid.NewGuid().ToString());
//https://localhost:44302/
//http://localhost:22792/
var hubConnection = new HubConnection("https://localhost:44302/");
hubConnection.Credentials = CredentialCache.DefaultCredentials;
hubConnection.AddClientCertificate(X509Certificate.CreateFromCertFile("bookoh.cer"));
hubConnection.TraceLevel = TraceLevels.All;
hubConnection.TraceWriter = Console.Out;
IHubProxy chatHubProxy = hubConnection.CreateHubProxy("ChatHub");
await hubConnection.Start();
chatHubProxy.On<string, string>("onSend", (name, message) =>
{
Trace.TraceInformation("onSend name : " + name);
Trace.TraceInformation("onSend message : " + message);
ev.Set();
});
Trace.TraceInformation("chatHubProxy.Invoke");
await chatHubProxy.Invoke("Send", "hhd2002", "hello");
}
catch (Exception ex)
{
Trace.TraceInformation("ex : " + ex);
}
});
ev.WaitOne();
}
full exception message on client program
vstest.executionengine.x86.exe Information: 0 : ex : System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
at System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)
at System.Net.PooledStream.EndWrite(IAsyncResult asyncResult)
at System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)
It looks like your actual exception message is
The remote certificate is invalid according to the validation procedure.
This is most likely due to it being self-signed and not signed by a trusted certificate authority. It looks like this has already been answered here:
C# Ignore certificate errors?
I had this issue and it was due to an expired/missing Digi Cert Global Root G2 certificate.
I believe if you raise it with Microsoft they provide you a new certificate, however I just applied it from another machine.
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel