Unitywebrequest Embedding User + Password Data for Http Basic Authentication Not Working on Android

UnityWebRequest Embedding User + Password data for HTTP Basic Authentication not working on Android

Embedding username and password(http://username:password@example.com) in a url is no longer supported in some Applications and OS for security reasons.That's because this is not the standard way to perform HTTP Authentication. It very likely that Unity or Android did not implement this on the their side.

I tested this on the built-in Android Browser with http://Administrator:ZZh7y6dn@*IP Address*:8080/Thingworx/Things/SimulationData/Properties/OvenTemperature/ and it failed to function. So, I guess this problem is from Android.

I tested again without username and password http://*IP Address**:8080/Thingworx/Things/SimulationData/Properties/OvenTemperature/ then the login window appeared. When I entered the username and password, it worked.

You can still use UnityWebRequest to solve this problem by providing the AUTHORIZATION header to the UnityWebRequest with the SetRequestHeader function. This will only work if the authorization type is Basic instead of Digest. In your case, it is HTTP Basic.

For general solution:

string authenticate(string username, string password)
{
string auth = username + ":" + password;
auth = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(auth));
auth = "Basic " + auth;
return auth;
}

IEnumerator makeRequest()
{
string authorization = authenticate("YourUserName", "YourPassWord");
string url = "yourUrlWithoutUsernameAndPassword";

UnityWebRequest www = UnityWebRequest.Get(url);
www.SetRequestHeader("AUTHORIZATION", authorization);

yield return www.Send();
.......
}

For solution in your question:

public GameObject TempText;
static string TempValue;

void Start()
{
StartCoroutine(GetText());
}

string authenticate(string username, string password)
{
string auth = username + ":" + password;
auth = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(auth));
auth = "Basic " + auth;
return auth;
}

IEnumerator GetText()
{
WaitForSeconds waitTime = new WaitForSeconds(2f); //Do the memory allocation once

string authorization = authenticate("Administrator", "ZZh7y6dn");
while (true)
{
yield return waitTime;
string url = "http://*IP Address*:8080/Thingworx/Things/SimulationData/Properties/OvenTemperature/";

UnityWebRequest www = UnityWebRequest.Get(url);
www.SetRequestHeader("AUTHORIZATION", authorization);
yield return www.Send();

if (www.isError)
{
Debug.Log("Error while Receiving: " + www.error);
}
else
{
string result = www.downloadHandler.text;
Char delimiter = '>';

String[] substrings = result.Split(delimiter);
foreach (var substring in substrings)
{
if (substring.Contains("</TD"))
{
String[] Substrings1 = substring.Split('<');
Debug.Log(Substrings1[0].ToString() + "Temp Value");
TempValue = Substrings1[0].ToString();
TempText.GetComponent<TextMesh>().text = TempValue + "'C";
}
}
}
}
}

How to Retrieve file from URL which Requires Authentication?

This is what I ended up going with after looking at the comments above. Let me know if I'm doing anything terribly inefficient!

    String username = "Superman"; // Obviously handled secretly
String pw = "ILoveLex4evar!"; // Obviously handled secretly
String url = "https://www.SuperSecretServer.com/123&stuff=?uhh";
String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + pw));
CookieContainer myContainer = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add("Authorization", "Basic " + encoded);
try
{
using (WebResponse response = request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (FileStream xml = File.Create("filepath/filename.xml"))
{
byte[] buffer = new byte[BufferSize];
int read;
while ((read = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
xml.Write(buffer, 0, read);
}
}
}
}
}

Unity WWWForm unauthorized for azure

In the docu they actually didn't show any example for using the Prediction-Key but I guess it works similar to the examples with Training-Key e.g.:

curl -X POST "https://southcentralus.api.cognitive.microsoft.com/customvision/v2.0/Training/projects/{projectId}/tags?name=cat" -H "Training-Key: $TRAININGKEY" --data-ascii ""

The header after -H is a header added to the http-request itself not as a header field within the form.

I'm pretty sure you have to use a base64 encoded string similar to when adding authorization headers (Source)

string Base64String(string key)
{
return System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(key));
}

and than use it req.SetRequestHeader in order to authorize the http-request itself not as header in the form:

WWWForm form = new WWWForm();
form.AddBinaryData("fileUpload", texture.EncodeToPNG());

UnityWebRequest req = UnityWebRequest.Post(link,form);
req.SetRequestHeader("Prediction-Key", Base64String("xxxxxxxxxxxxxxxxxxxxxxxx");

yield return req.SendWebRequest();

Unity - WWW.text returning null on android device

I ran a quick test with your modified code that is still not working and got this run-time exception:

java.net.MalformedURLException: Protocol not found

It's always good to use Android Monitor when having such problems like this.

The problem is that you did not prefix the url with http:// or https://. Android does not support that so that's why it worked on the Editor but not on Android.

The-same thing happens also happens when you try to embed user name and password in a url. For example, http://username:password@example.com.

This will work on Windows and the Editor but will not work on Android but there is a fix for it.

This should work:

IEnumerator testConnection()
{
Dictionary<string, string> header = new Dictionary<string, string>();
string userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36";
header.Add("User-Agent", userAgent);
WWW www = new WWW("http://www.google.com", null, header);
yield return www;
// check for errors
if (www.error == null)
{
util.debug("works");
}
else
{
// www.error and www.text both are empty
util.debug("testing: WWW Error: " + www.error + www.text);
}
}

Hint:

When making a web request from Unity app to a server that does not belong to you (http://www.google.com), it is always a good idea to add user-agent header or expect the request to fail on some devices when your app is released.

Unity WebGL UnityWebRequest Bad Body Data

This particular issue was caused by antivirus software. We found the affected users were using Kaspersky antivirus, and specifically a feature called 'Integrate script for interaction with websites into traffic', under the 'Traffic Processing' tab. I have no clue why Kaspersky thinks this is a reasonable thing to do, and I imagine it must break more than just our game, but there it is. The user can simply disable that option in Kaspersky and the UnityWebRequest will run as normal.



Related Topics



Leave a reply



Submit