I'm trying to communicate with a backend server using SSL.
I'm trying using HttpClient from the System.Net.Http library, but I couldn't get it working.
This is my code (Debug.Log is just a print since I'm using Unity):
public static async Task DownloadPageAsync(string web)
{
try
{
HttpClient cl = new HttpClient();
string body = await cl.GetStringAsync(new Uri(web));
Debug.Log(web);
}
catch (HttpRequestException e)
{
Debug.Log(e.InnerException.Message);
}
catch (Exception ex)
{
Debug.Log(ex.ToString());
}
}
When I try it in a web with a bad certificate, it gives: "Error: TrustFailure (The authentication or decryption has failed.)", which is fine. The problem is that good certificates also triggers an error: "Error: SecureChannelFailure (The authentication or decryption has failed.)".
I've saw other answers saying that simply accepting all the certificates works fine, but I need to check if it's a valid certificate or not.
¿Is there a way of doing it with HttpClient? ¿Or with some other class?
Btw, I'm only using it to send POST request, and receiving a simple string.
Thank you!
For UnityWebRequest since Unity 2018.1 there is the UnityWebRequest.certificateHandler e.g.
IEnumerator GetRequest(string uri)
{
UnityWebRequest request = UnityWebRequest.Get(uri);
request.certificateHandler = new AcceptAllCertificatesSignedWithASpecificPublicKey();
yield return request.SendWebRequest ();
if (request.isNetworkError)
{
Debug.Log("Something went wrong, and returned error: " + request.error);
}
else
{
// Show results as text
Debug.Log(request.downloadHandler.text);
}
}
And the implementation of the example CertificateHandler:
using UnityEngine.Networking;
using System.Security.Cryptography.X509Certificates;
using UnityEngine;
// Based on https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#.Net
class AcceptAllCertificatesSignedWithASpecificPublicKey: CertificateHandler
{
// Encoded RSAPublicKey
private static string PUB_KEY = "mypublickey";
protected override bool ValidateCertificate(byte[] certificateData)
{
X509Certificate2 certificate = new X509Certificate2(certificateData);
string pk = certificate.GetPublicKeyString();
if (pk.ToLower().Equals(PUB_KEY.ToLower()))
{
return true;
}
return false;
}
}
(Source)
For HttpClient see Make Https call using HttpClient
Related
When I using http url for API server I receive error:
Message "One or more errors occurred. (Cleartext HTTP traffic to 194.141.118.43 not permitted)"
When I put https on the url for API server I receive error:
Message "One or more errors occurred. (Unable to parse TLS packet header)"
My RestServiceData class look like:
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;
using MaritsaTundzhaForecast.Models;
using Newtonsoft.Json;
namespace MaritsaTundzhaForecast.Services
{
public class RestServiceData
{
HttpClient _client1;
HttpClient _client2;
public RestServiceData()
{
_client1 = new HttpClient();
_client2 = new HttpClient();
}
public WaterBindingData GetWaterDataForecast(string query, string query2)
{
WaterDataJson waterData = new WaterDataJson();
WaterStationsJson waterStations = new WaterStationsJson();
WaterBindingData result = new WaterBindingData();
try
{
var task = Task.Run(() => _client1.GetAsync(query));
task.Wait();
var response = task.Result;
var task2 = Task.Run(() => _client2.GetAsync(query2));
task2.Wait();
var response2 = task2.Result;
if (response.IsSuccessStatusCode && response2.IsSuccessStatusCode)
{
var content = response.Content.ReadAsStringAsync().Result;
var content2 = response2.Content.ReadAsStringAsync().Result;
var json = content2.Replace("\"ardaforecast\":[[", "\"ardaforecast\":[ {\"items\": [")
.Replace("}],{\"fieldCount\"", "}],\"details\":{\"fieldCount\"")
.Replace("}]}", "}}]}");
waterData = JsonConvert.DeserializeObject<WaterDataJson>(content2);
waterStations = JsonConvert.DeserializeObject<WaterStationsJson>(content);
result.WaterData = waterData;
result.WaterStation = waterStations;
}
}
catch (Exception ex)
{
Debug.WriteLine("\t\tERROR {0}", ex.Message);
}
return result;
}
}
}
This is my Constants class:
using System;
using System.IO;
namespace MaritsaTundzhaForecast
{
public static class Constants
{
public static string EndPoint = "https://194.141.118.43:3001/";
}
}
What Can I do to fix this error ?
If your website does not have any certificate configuration, change https to http.
Set to allow http requests.
Add in your xxx.Android->Properties->AndroidManifest.xml:android:usesCleartextTraffic="true".
If the above method does not work,Create an xml folder under your
Resources folder and add the network_security_config.xml file. Add
code:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true"/>
</network-security-config>
Add in your xxx.Android->Properties->AndroidManifest.xml:
android:networkSecurityConfig="#xml/network_security_config"
If you should want to use the http request, you should add android:usesCleartextTraffic="true" to the application tag in the AndroidManifest.xml which only used in API level 23 and higher(This is enough for test).
You should use the https request online, you need a domain name and https will use 443 port in your server. Usually, you need Nginx or Apache to listen 443 and connect your self server.
I've been trying to figure out how to use the League of Legends live API. I've had success using the endpoints like this: /lol/summoner/v4/summoners/by-name/{summonerName}
but when it comes to using endpoints like this (for live game data): GET https://127.0.0.1:2999/liveclientdata/allgamedata
I get the error
"Cannot connect to destination host"
Here is sample code I've been trying:
private IEnumerator Test()
{
string url = "https://127.0.0.1:2999/liveclientdata/activeplayername";
using (UnityWebRequest webRequest = UnityWebRequest.Get(url))
{
yield return webRequest.SendWebRequest();
string error = webRequest.error;
if (error != null)
{
Debug.LogError("[LoLAPI] - " + error);
}
else
{
Debug.Log(webRequest.downloadHandler.text);
}
}
}
Am I missing something?
Thanks
The implementation of UnityWebRequest will not accept self-signed SSL certificates by default. Try adding this:
public class UncheckedCertificateHandler: CertificateHandler
{
protected override bool ValidateCertificate(byte[] certData)
{
// certificate validation always returns true
return true;
}
}
Then when you create the web request:
using (UnityWebRequest webRequest = UnityWebRequest.Get(url))
{
www.certificateHandler = new UncheckedCertificateHandler();
yield return webRequest.SendWebRequest();
Or alternatively, just use http:// if it is available.
Hello legendary coders.
Flowing by my previous question I tried to use user32.dll in windows universal application (UWP) in C# language but I encountered an error while trying to use the method I imported from that .dll
here is my code:
[DllImport("user32.dll")]
public static extern bool LockWorkStation();
private async void btnLock_Click(object sender, RoutedEventArgs e)
{
string path;
if (Images.TryGetValue(selectedRadioButton.Name, out path))
{
StorageFile file = await StorageFile.GetFileFromPathAsync(path);
await LockScreen.SetImageFileAsync(file);
if (!LockWorkStation())
throw new Exception(Marshal.GetLastWin32Error().ToString());
}
}
as you can see I imported LockWorkStation() mthod from user32.dll and I used it in the event listener of a button. the Images is a Dictionary<string,string> and every thing is Fine unless the call to method LockWorkStation() it always return false and so the thrown error is 1008 I mentioned it in the Title The question is Why? and how can I assign a token?
Note: any way,any way to lock the screen is admirable.
So after searching a lot and being hopeless from directly lock the screen from the universal windows application platform I send a web request to a local web server and I made that web server to use the user32.dll and lock the screen.
here is the code in the UWP app:
try
{
HttpClient httpClient = new HttpClient();
Uri uri = new Uri("http://localhost:8080/lock/");
HttpStringContent content = new HttpStringContent(
"{ \"pass\": \"theMorteza#1378App\" }",
UnicodeEncoding.Utf8,
"application/json");
HttpResponseMessage httpResponseMessage = await httpClient.PostAsync(
uri,
content);
httpResponseMessage.EnsureSuccessStatusCode();
}
catch (Exception ex)
{
throw ex;
}
and there is the code in the web server:
[DllImport("user32.dll")]
public static extern bool LockWorkStation();
private static string LockTheScreen(HttpListenerRequest request)
{
var inputStream = request.InputStream;
try
{
using (StreamReader sr = new StreamReader(inputStream))
{
JToken pass = JToken.Parse(sr.ReadToEnd());
if (pass.Value<string>("pass") == "theMorteza#1378App")
{
LockWorkStation();
}
}
}
catch (Exception)
{
return "fail";
}
return "fail";
}
Note: you can find how to make a simple web server here
But: you must install the web server and grant it's access for users.
I am trying to invoke External APIs from AWS lambda function written in c#. The Lamda function is deployed in No VPC mode. I am calling this function from Alexa skill. The code works fine for an http request, but its not working for https.
The below code works when I use http://www.google.com.
But, if I replace http with https, then I get the error in the cloud watch saying:
"Process exited before completing request."
Even the log written in catch is not getting logged in cloud watch.
public class Function
{
public const string INVOCATION_NAME = "bingo";
public async Task<SkillResponse> FunctionHandler(SkillRequest input, ILambdaContext context)
{
var requestType = input.GetRequestType();
if (requestType == typeof(IntentRequest))
{
string response = "";
IntentRequest request = input.Request as IntentRequest;
response += $"About {request.Intent.Slots["carmodel"].Value}";
try
{
using (var httpClient = new HttpClient())
{
Console.WriteLine("Trying to access internet");
//var resp=httpClient.GetAsync("http://www.google.com").Result // this works perfect!
var resp = httpClient.GetAsync("https://www.google.com").Result; // this throws error
Console.WriteLine("Call was successful");
}
}
catch (Exception ex)
{
Console.WriteLine("Exception from main function " + ex.Message);
Console.WriteLine(ex.InnerException.Message);
Console.WriteLine(ex.StackTrace);
}
return MakeSkillResponse(response, true);
}
else
{
return MakeSkillResponse(
$"I don't know how to handle this intent. Please say something like Alexa, ask {INVOCATION_NAME} about Tesla.",
true);
}
}
private SkillResponse MakeSkillResponse(string outputSpeech, bool shouldEndSession,
string repromptText = "Just say, tell me about car models to learn more. To exit, say, exit.")
{
var response = new ResponseBody
{
ShouldEndSession = shouldEndSession,
OutputSpeech = new PlainTextOutputSpeech { Text = outputSpeech }
};
if (repromptText != null)
{
response.Reprompt = new Reprompt() { OutputSpeech = new PlainTextOutputSpeech() { Text = repromptText } };
}
var skillResponse = new SkillResponse
{
Response = response,
Version = "1.0"
};
return skillResponse;
}
}
The issue was resolved by updating the library version.
System.Net.Http v4.3.4 was not completely compatible with dotnet core v1.
So outbound http calls were working but not https calls. Changing the version of System.net.http resolved the issue.
I am writing an App server application in C# that needs to access Firebase Database. It uses REST protocol. To authentication i want to use an service account.
Unfortunately there is no library written in C#, so i am trying to put the bellow http Request to work.
I follow this steps:
To get the accesstoken i follow the https://github.com/google/google-api-dotnet-client-samples. The code prints the token so should be ok to that point.
Invoke GET web request passing the token in the access_token query parameter as documented at https://firebase.google.com/docs/reference/rest/database/user-auth.
I tried all variations i could remember, in headers, with apostrophe, APN request style, but always got 401 error or 403. Error code 403 should mean that the API recognize the user but denys access to the resource, but i am not sure if this works this way in this case.
The account is defined in the API console and it has project edit and owner profile, for the Firebase app.
The rules are set like this:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Can't figure out were i went wrong. I don't think i need to go written an JWT token if i use google API library. Rules should not apply to this account so i guess i am not passing the token correctly. By inspecting the token retrieved i can see that it is of type Bear, so i tried to pass it on header with no success too.
Test code:
using System;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Auth.OAuth2;
using System.Threading.Tasks;
using System.Net;
using System.IO;
namespace FirebaseAppServer
{
/// </summary>
public class Program
{
public static void Main(string[] args)
{
accessFirebase();
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
public async static Task accessFirebase()
{
String serviceAccountEmail = "serviceaccount1#myapp.iam.gserviceaccount.com";
var certificate = new X509Certificate2(#"App.p12", "notasecret", X509KeyStorageFlags.Exportable); //App2 is the certificate i downloaded from API console
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { "https://www.googleapis.com/auth/firebase.database" //from https://developers.google.com/identity/protocols/googlescopes
,"https://www.googleapis.com/auth/firebase"
,"https://www.googleapis.com/auth/cloud-platform"}
}.FromCertificate(certificate));
var task = await credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None);
Console.WriteLine("AccessToken " + credential.Token.AccessToken); //accessToken has a value, so guess is all good so far.
var request = (HttpWebRequest)WebRequest.Create("https://<Myapp>.firebaseio.com/.json?access_token=" + credential.Token.AccessToken);
request.Method = "GET";
request.ContentType = "application/json";
using (var response = (HttpWebResponse)request.GetResponse()) //Throw error 403 - forbidden
{
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.WriteLine("responseString " + responseString);
}
}