Cannot access child value on JValue in Azure Mobile App - c#

I recently implemented custom authentication with Azure Mobile App - All the server side works fine and also my web application which is using that mobile app service is working fine. I tested the server-side in details with POSTMAN and with different scenarios, everything works fine until I try to LoginAsync on Xamarin.
When I pass email and password in POSTMAN, I get the following response as a clear indication that it is working
but when I send a request from my app using LoginAsync I get the following error.
Cannot access child value on Newtonsoft.Json.Linq.JValue
My code to send request is fairly simple as following
public async Task<bool> Authenticate()
{
string username = "todo#gmail.com";
string password = "todo";
string message = string.Empty;
var success = false;
var credentials = new JObject
{
["email"] = username,
["password"] = password
};
try
{
MobileServiceUser user = await client.LoginAsync("CustomAuth", credentials);
if (user != null)
{
success = true;
CreateAndShowDialog("OK", "Auth");
}
}
catch (Exception ex)
{
CreateAndShowDialog(ex, "Auth Error");
}
return success;
}
where I am calling it as follows
private MobileServiceClient client;
client = new MobileServiceClient(applicationURL);
await Authenticate();
Any idea why I am getting Cannot access child value on Newtonsoft.Json.Linq.JValue error?
Cheers
EDIT POST
As a workaround, I am temporarily using InvokeApiAsync with JObject.FromObject instead of LoginAsync
await client.InvokeApiAsync("/.auth/login/CustomAuth", JObject.FromObject(credentials), HttpMethod.Post, null);
I am still not sure why LoginAsync does not work - Until I find a solution I will keep using InvokdeApiAsync as a workaround

AFAIK, your initialization for credentials is correct. For the below error:
Cannot access child value on Newtonsoft.Json.Linq.JValue
I checked your testing result via POSTMAN and found that you did not return userId to your client. The essential properties returned to your client would look like as follows:
{
"authenticationToken":"***",
"user":{
"userId":"***"
}
}
When using MobileServiceClient.LoginAsync, the client SDK would internally invoke LoginAsync() method under MobileServiceAuthentication.cs as follows:
JToken authToken = JToken.Parse(response);
// Get the Mobile Services auth token and user data
this.Client.CurrentUser = new MobileServiceUser((string)authToken["user"]["userId"]);
this.Client.CurrentUser.MobileServiceAuthenticationToken = (string)authToken[LoginAsyncAuthenticationTokenKey];
You would find that it would try to extract the userId property under user to construct the MobileServiceUser instance and assign to MobileServiceClient.CurrentUser.

Related

NetSuite OAUTH1 POST request works in Postman but fails using Restsharp

I have code to allow us to use the NetSuite REST API using OAuth 1.0. Everything works fine, except one call. When trying to do /salesorder/{id}/!transform/itemFulfillment It fails with 401. All other calls work fine. When I execute the same call from Postman it works fine too. What am I missing?
Here is my Code:
private static async Task CreateItemFulFillmentsAsync(NetSuiteJob job, int id, Item item)
{
RestRequest request = new RestRequest($"{job.RecordUrl}/salesorder/{id}/!transform/itemFulfillment", Method.Post);
request.AddBody(item);
RestHelper restHelper = new RestHelper();
RestResponse response = await restHelper.ExecuteRestRequest(request, job);
if (response == null || !response.IsSuccessful)
{
throw new Exception($"Failed to create the Item Fulfillment for the Sales Order: {id}.\r\n" + response.Content);
}
}
And the Helper Class:
public async Task<RestResponse> ExecuteRestRequest(RestRequest request, NetSuiteJob job)
{
RestClient client = new RestClient(job.BaseUrl) { Authenticator = GetOAuth1Authenticator(job) };
RestResponse response = await client.ExecuteAsync(request);
return response;
}
private OAuth1Authenticator GetOAuth1Authenticator(NetSuiteJob job)
{
OAuth1Authenticator oAuth1 = OAuth1Authenticator.ForAccessToken(
consumerKey: job.ConsumerKey,
consumerSecret: job.ConsumerSecret,
token: job.TokenId,
tokenSecret: job.TokenSecret,
OAuthSignatureMethod.HmacSha256);
oAuth1.Realm = job.Realm;
return oAuth1;
}
The results are:
{"type":"https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2",
"title":"Unauthorized","status":401,
"o:errorDetails":[{"detail":"Invalid login attempt.  For more details,
see the Login Audit Trail in the NetSuite UI at Setup > Users/Roles 
> User Management > View Login Audit Trail.","o:errorCode":"INVALID_LOGIN"}]}
In NetSuite's Login Audit Trail, this call is logged as a failure and Role is blank, but the other calls using different action shows the Role like it should. The working routines use the same helper class but are doing it with a different URL and Body. I've verified the content being passed matches what I did manually in Postman too.

Authentication in Dialogflow API V2 using C#

I have .NET Web API Project for the fulfillment API as our webhook in my Dialogflow agent. In our Post method of the controller, after getting the request from Dialogflow, I implement the explicit authentication as shown in the Google Cloud documentation for C#.
//jsonFileName is the name of the serviceAccountKey json generated from the Google Cloud Platform that's encrypted internally
public bool AuthExplicit(string projectId, string jsonFileName)
{
try
{
string JsonCredential = DecryptHelper.Decrypt(jsonFileName);
var credential = GoogleCredential.FromJson(JsonCredential).CreateScoped(LanguageServiceClient.DefaultScopes);
var channel = new Grpc.Core.Channel(
LanguageServiceClient.DefaultEndpoint.ToString(),
credential.ToChannelCredentials());
var client = LanguageServiceClient.Create(channel);
AnalyzeSentiment(client);
if (client != null)
{
return true;
}
else
{
return false;
}
}
internal void AnalyzeSentiment(LanguageServiceClient client)
{
var response = client.AnalyzeSentiment(new Document()
{
Content = "Authenticated.",
Type = Document.Types.Type.PlainText
});
var sentiment = response.DocumentSentiment;
string score = $"Score: {sentiment.Score}";
string magnitude = $"Magnitude: {sentiment.Magnitude}";
}
The difference with the code is that after getting the client, when we call the AnalyzeSentiment() method, it doesn't do anything, and the projectId parameter is never used to authenticate. GCP docs are quite confusing, since when there is an AuthExplicit() that uses projectId, it uses it as a parameter for the buckets and only prints this on the console.
It works fine, until we test the service account key with a different agent. Expected output is that authentication would fail, but somehow it still passes.
Once the Post method goes through the AuthExplicit() method, it would only return a boolean. Is this the right way to authenticate? Or is there something else needed to invoke?
The difference with the code is that after getting the client, when we call the AnalyzeSentiment() method, it doesn't do anything,
Does client.AnalyzeSentiment() return an empty response? Does the call hang forever?
It works fine, until we test the service account key with a different agent.
What is a different agent? A different User-Agent header?
Once the Post method goes through the AuthExplicit() method, it would only return a boolean. Is this the right way to authenticate? Or is there something else needed to invoke?
What does 'the Post method' refer to? What is the 'it' that would only return a boolean?

"BotAuthenticator failed to authenticate incoming request!" error in Teams when using Bot

I've created a Bot application in Visual Studio 2017, which I want to use in MS Teams. This application is part of a solution, which contains 2 components, the bot application itself and a windows application, which I have created that is used by the bot application to retrieve an authentication token from Microsoft (using similar code to what is on this website https://learn.microsoft.com/en-us/azure/active-directory/develop/guidedsetups/active-directory-uwp-v2).
When debugging the bot after hosting it locally, I'am able to use the bot successfully in Teams. There is no error. However, now that I have registered the bot with the Microsoft Bot Framework in Azure, I'm now having issues as Teams returns back the message "Sorry, my bot code is having an issue." In Azure I have a Bots Channels Registration entity, which in its settings points to a messaging endpoint that is https://.azurewebsites.net/api/messages. I also have a Apps Service. Now I have transferred the application id that I received when registering the bot with the Microsoft Bot Framework and have put this into the bot application in Visual Studio in the web.config file along with the app password.
After testing this in the Bot Framework Emulator I get "POST 401 directline.postActivity" and in the "Inspector-JSON" I get "BotAuthenticator failed to authenticate incoming request!". This is my first bot application so I'm lost as to what I have potentially missed out so does anyone have any idea what I could try?
So here's what I have in my RootDialog.cs file, which where the endpoint will hit when the bot is used.
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
string userInfo = "";
AuthTokenDeploy tokenDeploy = new AuthTokenDeploy();
userInfo = await tokenDeploy.MsGraphUserInfo();
if(!userInfo.Equals(""))
{
// send webhook to end user system
await SendToEndpoint(context, activity, activity.Text,
userInfo);
}
}
AuthTokenDeploy is an instance of another class, which is where the function to obtain the access token along with the user information from Microsoft is held. So I created a string "userInfo", which then takes the value given by MsGraphUserInfo().
public async Task<string> MsGraphUserInfo()
{
AuthenticationResult authResult = null;
string Text = null;
try
{
authResult = await App.PublicClientApp.AcquireTokenSilentAsync(_scopes, App.PublicClientApp.Users.FirstOrDefault());
}
catch (MsalUiRequiredException ex)
{
// A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token
System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");
try
{
authResult = await App.PublicClientApp.AcquireTokenAsync(_scopes);
}
catch (MsalException msalex)
{
}
}
catch (Exception ex)
{
}
if (authResult != null)
{
Text = await GetHttpContentWithToken(_graphAPIEndpoint, authResult.AccessToken);
}
return Text;
}
Calling MsGraphUserInfo() will open the "AuthToken.exe" as a popup Window and ask the user to log in with their credentials. You can see from the code above that it acquires the access token first, which is then passed into GetHttpContentWithToken(), which is where a HTTP GET request is run against "https://graph.microsoft.com/v1.0/me" and a JSON string is returned with the user information in it.
public async Task<string> GetHttpContentWithToken(string url, string token)
{
var httpClient = new System.Net.Http.HttpClient();
System.Net.Http.HttpResponseMessage response;
try
{
var request = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, url);
//Add the token in Authorization header
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
response = await httpClient.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
return content;
}
catch (Exception ex)
{
return ex.ToString();
}
}
Now I feel as if this method of using a Windows application to allow the user to log in might not be the best way forward, hence why I've been reading and following this guide https://learn.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-auth-aad. I would like to know whether it is possible to use what is on this page to allow my bot to retrieve an access token?

Mobile Service Client throws exception when response is not found

I am trying to port an application from an azure mobile service to an azure web app. (the mobile service was working). I have added microsoft account authentication to the web-app, and the web app api has a MobileAppController attribute. I have a Universal windows app front end that calls the api. The app first checks if a player is in the database, if not I get a not found response. If I call the method using the following code with the MobileServiceClient I get an exception.
private async Task<HttpResponseMessage> GetAZMAsyncP(string apiext, IDictionary<string,string> param )
{
string myuri = String.Format("{0}{1}", urlbase, apiext);
//client is the MobileServiceClient that is correctly logged in
//I do not get response which is 404 not found, I get an exception "The request could not be completed, Not Found"
var response = await client.InvokeApiAsync(myuri, System.Net.Http.HttpMethod.Get, param);
return response;
}
If I call the api from an httpclient and add my own headers, which the mobile client is supposed to do for me, then I get the response as requested. Here is the code:
private async static Task<HttpResponseMessage> GetAZAsync(string apiext)
{
string completeUrl = String.Format("{0}{1}", urlbase, apiext);
// Call out to AZ
using (var http = new HttpClient())
{
// http.BaseAddress = new Uri(completeUrl);
HttpRequestMessage rq = new HttpRequestMessage()
{
RequestUri = new Uri(completeUrl),
Method = HttpMethod.Get
};
addauthheader(rq);
var response = await http.SendAsync(rq);
return response;
}
}
private static void addauthheader(HttpRequestMessage rq)
{
MobileServiceUser user = App.client.CurrentUser;
rq.Headers.Add("X-ZUMO-FEATURES", "AT,QS");
rq.Headers.Add("X-ZUMO-INSTALLATION-ID",
"ff90f37e-0c03-4c52-a343-af711752e383");
rq.Headers.Add("X-ZUMO-AUTH", user.MobileServiceAuthenticationToken);
rq.Headers.Add("Accept", "application/json");
rq.Headers.Add("User-Agent", "ZUMO/2.1");
rq.Headers.Add("User-Agent",
"(lang = Managed; os = Windows Store; os_version = --; arch = X86; version = 2.1.40707.0)");
rq.Headers.Add("X-ZUMO-VERSION",
"ZUMO/2.1(lang = Managed; os = Windows Store; os_version = --; arch = X86; version = 2.1.40707.0)");
rq.Headers.Add("ZUMO-API-VERSION", "2.0.0");
}
You can try this out as it is live (and buggy).
https://gamenote2.azurewebsites.net/api/Players?displayname=Paul Goldschmidt&teamid=arizona-diamondbacks
Should give you a 404,
https://gamenote2.azurewebsites.net/api/Players?displayname=Chase Utley&teamid=los-angeles-dodgers
should give you a chase utley object. (YOu will be asked to log into a Microsoft Account).
So my questions: 1. Can I fix the mobileclient call to get a response instead of an execption
2. Is there any good reason for me to be spending so much time on this.
If you examine the exception, you will note that the status code is in there - it's just in a property that is not serialized. Just surround your InvokeApiAsync() call with a try/catch and test for the StatusCode. It should be a lot easier than writing your own HTTP Client code for the same purpose.
Specifically, MobileServiceInvalidOperationException contains the HttpResponse of the failed request, so you can check exception.Response.StatusCode value.

OneDrive client authentication (SDK)

I'm playing with OneDrive SDK 1.1.15.0:
try
{
AppConfig appConfig = new AppConfig
{
MicrosoftAccountAppId = oneDriveClientID, //something like 00000000123456AB
MicrosoftAccountClientSecret = oneDriveClientSecret, //something like 3vx[...]1sJ
MicrosoftAccountReturnUrl = "https://localhost/return",
MicrosoftAccountScopes = new string[] { "wl.signin", "wl.offline_access", "onedrive.readonly" }
};
OneDriveClient oneDriveClient = new OneDriveClient(appConfig);
AccountSession accountSession = await oneDriveClient.AuthenticateAsync();
//more code
await oneDriveClient.SignOutAsync();
}
catch (Exception ex)
{
throw ex;
}
My problem is in line:
AccountSession accountSession = await oneDriveClient.AuthenticateAsync();
that throws the following exception:
Microsoft.OneDrive.Sdk.OneDriveException, AuthenticationFailure: Failed to retrieve a valid authentication token for the user.
Any ideas?
Thank you in advance!
UPDATE
After reading comment from ginach (thank you!), I update my code. Some arguments to underline:
I want to access OneDrive from an Azure worker Role, so no authentication windows or something like that.
I upload the Microsoft.OneDrive SDK to 1.1.20 version.
I already registered my application to the OneDrive dev portal.
My actual code is:
try
{
MicrosoftAccountServiceInfo serviceInfo = new MicrosoftAccountServiceInfo();
serviceInfo.AppId = oneDriveClientID; //something like: 00000000ABCDEFGH
serviceInfo.ClientSecret = oneDriveClientSecret; //something like: 3vx[...]1sJ
serviceInfo.ReturnUrl = oneDriveReturnUrl; //something like: https://localhost/return
serviceInfo.Scopes = oneDriveAccountScopes; //something like new string[] { "wl.signin", "wl.offline_access", "onedrive.readonly" }
MicrosoftAccountAuthenticationProvider authenticationProvider = new MicrosoftAccountAuthenticationProvider(serviceInfo);
OneDriveClient oneDriveClient = await OneDriveClient.GetAuthenticatedMicrosoftAccountClient(oneDriveClientID, oneDriveReturnUrl, oneDriveAccountScopes, authenticationProvider);
//more code
await oneDriveClient.SignOutAsync();
}
catch (OneDriveException odex)
{
throw odex;
}
catch (Exception ex)
{
throw ex;
}
I obtain again and again (in OneDriveClient.GetAuthenticatedMicrosoftAccountClient method) a OneDriveException stating (Error property): AuthenticationFailure - Failed to retrieve a valid authentication token for the user.
Any suggestion?
Thank you.
UPDATE 2
OK, I'm trying a new approach. Using RestSharp I try to login to OneDrive with that code:
string clientId = "00[...]00";
string scopes = "wl.signin, wl.offline_access, onedrive.readonly";
string responseType = "code";
string redirectUri = "https://login.live.com/oauth20_desktop.srf";
RestClient client = new RestClient("https://login.live.com");
RestRequest request = new RestRequest();
request.Method = Method.GET;
request.Resource = "oauth20_authorize.srf";
request.AddQueryParameter("client_id", clientId);
request.AddQueryParameter("scope", scopes);
request.AddQueryParameter("response_type", responseType);
request.AddQueryParameter("redirect_uri", redirectUri);
IRestResponse response = client.Execute(request);
string content = response.Content;
I check the request with Fiddler and what I'm sending is:
https://login.live.com/oauth20_authorize.srf?client_id=00[...]00&scope=wl.signin%20wl.offline_access%20onedrive.readonly&response_type=code&redirect_uri=https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf
But OneDrive server answers my with:
Microsoft account requires JavaScript to sign in. This web browser either does not support JavaScript, or scripts are being blocked. To find out whether your browser supports JavaScript, or to allow scripts, see the browser's online help.
So I try the request in a browser and OneDrive server redirects me to the authorization page:
Now the question is: is there any workaround to skip the manual authorization?
Thank you,
Attilio
The client requires an authentication provider to be able to retrieve authentication tokens. There are a few ways to do this depending on your current platform.
Create your own IAuthenticationProvider implementation. The authentication provider is responsible for setting the Authentication header on requests. Here's how you would create a client instance with a custom authentication provider:
var client = new OneDriveClient(appConfig, serviceInfoProvider: new
ServiceInfoProvider(new CustomAuthenticationProvider()));
Use one of the various default authentication implementations. Take a look at the SDK authentication documentation for the available options and examples.
If you have a refresh token and only want to do the silent authentication flow you can use OneDriveClient.GetSilentlyAuthenticatedMicrosoftAccountClient. Here's an example:
var client = await OneDriveClient.GetSilentlyAuthenticatedMicrosoftAccountClient(clientId, returnUrl, scopes, refreshToken);

Categories

Resources