We are trying to implement an authentication system using JWT Security Tokens on HoloLens 2.
We are using:
Unity 2020.3.28
OpenXR
NuGet Packages:
Microsoft.IdentityModel.JsonWebTokens, v. 6.15.1
Microsoft.IdentityModel.Logging, v. 6.15.1
Microsoft.IdentityModel.Tokens, v. 6.15.1
System.IdentityModel.Tokens.Jwt, v. 6.15.1
Newtonsoft.Json, v. 11.0.2
When receiving the answer from the server we parse it into a JwtSecurityToken using this code snippet:
Debug.Log($"signInResul: {signInResult.IdentityToken}");
var stream = signInResult.IdentityToken;
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(stream);
Debug.Log($"jsonToken: {jsonToken}");
var tokenS = jsonToken as JwtSecurityToken;
Where the signInResult is the Server answer, and we can also output that the response comes in the correct way.
Now within Unity the parsing happens without any problems, once switching to the HoloLens it doesn't work anymore.
We receive the same answer as within the Unity environment, but the code stops on the line with var handler = new JwtSecurityTokenHandler(); or var jsonToken = handler.ReadToken(stream);, since we never get to Debug.Log($"jsonToken: {jsonToken}");.
Does anybody have experience with Jwt on HoloLens and might know where the issue could lies?
Thanks for the help
Related
I have written a plugin wherein I am trying to get an XML response.
This is my code :
// Set the Method property of the request to POST.
string strXMLServer = "xxx";
var request = (HttpWebRequest)WebRequest.Create(strXMLServer);
request.Method = "POST";
// Set the ContentType property of the WebRequest.
request.ContentType = "xyz";
// Assuming XML is stored in strXML
byte[] byteArray = Encoding.UTF8.GetBytes(strXML);
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
//(LINE 5) Get the request stream
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
This code works fine when its written in a console application. But when I copy the same code to a class library(plugin) and tries to debug it using plugin profiler, the application gets stopped abruptly when it reaches (LINE 5)
i.e. At Stream dataStream = request.GetRequestStream();
request.GetRequestStream() function is not working with plugin, but works fine within a console.
Any help would be appreciated :)
Thanks in advance
Note: I am using Dynamics 365 online trial version
There are a couple of things to take into consideration when building a plugin with web requests. Firstly, you need to use WebClient as it's widely supported by Microsoft products.
Secondly, your URL needs to be a DNS name and not an IP address, as this is a hosted plugin in sandbox mode.
Example from Microsoft's website: https://msdn.microsoft.com/en-us/library/gg509030.aspx
Reading material: https://crmbusiness.wordpress.com/2015/02/05/understanding-plugin-sandbox-mode/
For the past 3 years we have used HTML/Js only with Firebase but now we are using Unity as well.
The current Unity/Firebase only works on Android/iOS when deployed and 99% of our work is on the windows store.
I've actually got a pretty decent Unity/Firebase codebase going but it requires me to use a full App Secret.
All the other libraries expose a method to login with Email/Password but the REST API only allows the use of a token or your app secret that it then states is ill advised to put into your client; I guess the thinking is if you're using a different library that you'll have your own auth/user method which we don't...
Now, I've pulled apart the web version and got this:
https://auth.firebase.com/v2/<myfirebase>/auth/password?&email=dennis%40<mysite>&password=<mypassword>v=js-2.2.9&transport=json&suppress_status_codes=true
So there IS an endpoint that I can send stuff to and I've tested it inside unity with good results.
Obviously the URL isn't guaranteed to stay working but I'm wondering if there is any reason NOT to use this?
Also, Why not just expose this endpoint in the official REST API?
As I understand it, that URL will continue to work for your Legacy Firebase project. You will have to do the same sort of reverse engineering if you want to update to the new Firebase 3.0 API. However, if you are still using a legacy Firebase project -- I encourage you to take a look at this. It has not been updated to work with Firebase 3.0 -- so I needed to do something similar to what you did to allow login to the new API.
I was able to do this with the new API using C# as follows (where FirebaseManager is a Singleton I wrote for Global variables and functions to write and read from/to the DB :
Hashtable loginData = new Hashtable();
loginData.Add ("email", <EMAIL-GOES-HERE>);
loginData.Add ("password", <PASSWORD-GOES-HERE>);
loginData.Add ("returnSecureToken", true);
UnityHTTP.Request loginRequest = new UnityHTTP.Request ("post",
"https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key="
+ <YOUR-PROJECT-API-KEY-GOES-HERE>, loginData);
loginRequest.Send ((request) => {
Hashtable jsonResponse = (Hashtable)JSON.JsonDecode(request.response.Text);
if (jsonResponse == null) {
DisplayErrorMessage("Error logging in. Server returned null or malformed response");
}
FirebaseManager.Instance.idToken = (string)jsonResponse["idToken"]; // This is your auth token
FirebaseManager.Instance.uid = (string)jsonResponse["localId"]; // this is your "uid"
});
// I have a list of users in my db keyed by the "uid" -- I access them like this
UnityHTTP.Request fullnameRequest = new UnityHTTP.Request ("get",
<YOUR-DATABASE-ROOT-URL-HERE>
+ "/users/" + FirebaseManager.Instance.uid + ".json?auth=" + FirebaseManager.Instance.idToken);
fullnameRequest.Send ((request) => {
Debug.Log(request.response.Text);
Hashtable jsonResponse = (Hashtable)JSON.JsonDecode(request.response.Text);
if (jsonResponse == null) {
DisplayErrorMessage("Error getting user info. Server returned null or malformed response");
}
FirebaseManager.Instance.fullname = (string)jsonResponse["fullname"];
FirebaseManager.Instance.groupId = (string)jsonResponse["group"]; // just storing this in memory
});
So I don't think there is any harm in using the URL, just make sure you budget time for more work when things change.
I use the following implementation for PlayReady on Samsung Smart TV SDK 3.5 & 4.x.
Now, in my network traces I see a plain GET Request to the license server URL being executed, but no data passed.
What could be the cause for this?
This is my code:
var VideoURL = '.........bution_deu_20_9000K.ism/Manifest';
var serverLicense = '...LicenseAcquisition.asmx';
var customData = '.....';
player.InitPlayer(VideoURL+"|COMPONENT=WMDRM");// + "|COMPONENT=WMDRM"
player.SetPlayerProperty(4, serverLicense, serverLicense.length);
player.SetPlayerProperty(3, customData, customData.length);
player.StartPlayback();
Thanks
I'm attempting to create a Facebook Registration process for our website that will create an account for the user in our CRM - to this end I require the use of a few custom fields in the registration form.
I have the registration form appearing properly on the site, however, when I process the signed_request the JSON only returns the decoded standard items and not my custom fields:
{
"algorithm": "HMAC-SHA256",
"code": "2.AQDp0sgWRw3TWrII.3600.1330650000.1100001862544007|LwjvMjADtPxaIzxizYuIivNdi7w",
"issued_at": 1330644064,
"user_id": "<my user id>"
}
This is a .NET implementation but I am not using the Facebook C# SDK as none of the documentation seems to be available anymore on their site and I'm just not clever enough to figure it out. I tried using the new 6.x beta of the Facebook C# SDK and the Facebook.Client() parse method but didn't have any luck determining what to do with it once the thing was parsed.
So - this stolen code is what I used to get the results posted above:
//client_payload = the signed_request from Facebook
string[] sB64String = client_payload.Split('.');
string payload = client_payload.Replace((sB64String[0] + "."), string.Empty);
var encoding = new UTF8Encoding();
var decodedJson = payload.Replace("=", string.Empty).Replace('-', '+').Replace('_', '/');
var base64JsonArray = Convert.FromBase64String(decodedJson.PadRight(decodedJson.Length + (4 - decodedJson.Length % 4) % 4, '='));
var json = encoding.GetString(base64JsonArray);
var jObject = JObject.Parse(json);
response.write(Convert.ToString(jObject)); // rw for debugging
Maybe I'm missing something?
I've resolved this on my own by modifying the way I was going about it.
I ended up using the tag and client side cookie as found here:
https://developers.facebook.com/docs/plugins/registration/advanced/
All of my custom fields end up in the cookie that I can then parse and send to my .NET webservice. Kind of a round-about way of doing it but it's getting the job done now.
ADFS 2.0, WIF (WS-Federation), ASP.NET: There is no http modules or any IdentityFoundation configuration defined in a web.config (like most WIF SDK samples show), instead everything is done via program code manually using WSFederationAuthenticationModule, ServiceConfiguration and SignInRequestMessage classes. I do http redirect to ADFS in a code and it seems to work fine, returning claims and redirecting user back to my web site with serialized claims in http request. So the question is how to parse this request using WIF classes, properties and methods and extract claims values from there? Thanks
Just in case want to share my experience, it might help somebody in the future. Well, solution I finally came to looks like this:
var message = SignInResponseMessage.CreateFromFormPost(Request) as SignInResponseMessage;
var rstr = new WSFederationSerializer().CreateResponse(message, new WSTrustSerializationContext(SecurityTokenHandlerCollectionManager.CreateDefaultSecurityTokenHandlerCollectionManager()));
var issuers = new ConfigurationBasedIssuerNameRegistry();
issuers.AddTrustedIssuer("630AF999EA69AF4917362D30C9EEA00C22D9A343", #"http://MyADFSServer/adfs/services/trust");
var tokenHandler = new Saml11SecurityTokenHandler {CertificateValidator = X509CertificateValidator.None};
var config = new SecurityTokenHandlerConfiguration{
CertificateValidator = X509CertificateValidator.None,
IssuerNameRegistry = issuers};
config.AudienceRestriction.AllowedAudienceUris.Add(new Uri("MyUri"));
tokenHandler.Configuration = config;
using(var reader=XmlReader.Create(new StringReader(rstr.RequestedSecurityToken.SecurityTokenXml.OuterXml)))
{
token = tokenHandler.ReadToken(reader);
}
ClaimsIdentityCollection claimsIdentity = tokenHandler.ValidateToken(token);
I found few similar code that uses SecurityTokenServiceConfiguration (it contains token handlers) instead of Saml11SecurityTokenHandler to read and parse token, however it did not work for me because of certificate validation failure. Setting SecurityTokenServiceConfiguration.CertificateValidator to X509CertificateValidator.None did not help coz Security Token Handler classes uses their own handler configuration and ignores STS configuration values, at least if you specify configuration parameters through the code like I did, however it works fine in case configuration is defined in web.config.