generate a unique token for each user account on login xamarin.forms - xamarin.forms

i am trying to create a messaging app using xamarin.forms and fcm. i am trying to create a token for each user upon login. i am using the same device to login to each user. the thing is that same token is being genberated. this is my code:
in xamarin.android project in MainActivity.cs:
public static FirebaseApp app ;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
string userid = Preferences.Get("userid", "");
FirebaseOptions options = new FirebaseOptions.Builder().SetApplicationId("my_app_id").SetApiKey("my_api_key").SetProjectId("my_project_id").Build();
app = FirebaseApp.InitializeApp(this, options, "User" + userid);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
and this is my getToken class
using Android.App;
using Android.Content;
using Android.Gms.Extensions;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Firebase.Iid;
using LearningWithCassidy;
using LearningWithCassidy.Droid;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
[assembly: Xamarin.Forms.Dependency(typeof(GetTokenAndroid))]
namespace LearningWithCassidy.Droid
{
internal class GetTokenAndroid:GetToken
{
public async Task<string> get_token()
{
FirebaseInstanceId firebaseInstanceId = FirebaseInstanceId.GetInstance(MainActivity.app);
var instanceIdResult = await firebaseInstanceId.GetInstanceId().AsAsync<IInstanceIdResult>();
var token = instanceIdResult.Token;
return token;
}
}
}
and this is how i get the token in my MainPage.xaml.cs
string token="";
token = await DependencyService.Get<GetToken>().get_token();
System.Diagnostics.Debug.WriteLine($"Token: {token}");
what am i doing wrong? why do i keep getting the same token?
thanks in advance

You have to delete the current token using deleteToken() whenever a user logs out. This will invalidate the token of the old user. Then, generate a new one after a new user logs in.

Related

unable to store json in single line inside azure blob storage using azure function

I have a requirement to store json in a single line(without any formatting) inside a blob storage file. I am using azure function with Newtonsoft.JSon properties for some manipulation purpose and then writing to a blob . But when I try to using JToken.Parse I am getting exception or internal server error.Below is the code I am using:
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public static async Task<IActionResult> Run(HttpRequest req,TextWriter outputBlob,ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
log.LogInformation($"Response is {requestBody}");
dynamic jObject = JsonConvert.DeserializeObject(requestBody);
JToken jCategory = jObject;
var clus = jCategory["clusters"];
foreach(JObject item in clus)
{
var custom_tag=item["custom_tags"];
var app_logical_name = item.SelectToken("custom_tags.app_name");
item.SelectToken("init_scripts_safe_mode").Parent.AddAfterSelf(new JProperty("app_logical_name",app_logical_name));
}
var clus2 = JsonConvert.SerializeObject(jCategory,Formatting.None);
//var clus_new=JArray.Parse(clus).toString(Newtonsoft.Json.Formatting.None);
outputBlob.Write(clus2);
// outputBlob.Write(clus_new);
return new OkObjectResult(requestBody);
}
I have tried both ways but both are giving runtime errors. I just need to put the json in a single line(without any formatting) and write to blob.Can you please help me in this ?
This is the structure on my side:
{
"clusters":[
{
"custom_tags":{
"app_name": "appname1"
},
"init_scripts_safe_mode":{
"xxx": "yyy"
}
},
{
"custom_tags":{
"app_name": "appname2"
},
"init_scripts_safe_mode":{
"xxx2": "yyy2"
}
}
],
"test":"333"
}
And this is my code:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace FunctionApp3
{
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
log.LogInformation($"Response is {requestBody}");
dynamic jObject = JsonConvert.DeserializeObject(requestBody);
JToken jCategory = jObject;
var clus = jCategory["clusters"];s2 = JsonConvert.SerializeObject(jCategory, Formatting.None);
foreach (JObject item in clus)
{
var custom_tag = item["custom_tags"];
var app_logical_name = item.SelectToken("custom_tags.app_name");
var xxx = item.SelectToken("init_scripts_safe_mode");
xxx.Parent.AddAfterSelf(new JProperty("app_logical_name", app_logical_name));
log.LogInformation(JsonConvert.SerializeObject(custom_tag, Formatting.None));
log.LogInformation(JsonConvert.SerializeObject(app_logical_name, Formatting.None));
}
return new OkObjectResult(clus);
}
}
}
It seems no problem:
If you get the server side error, please check the details log to get where is the error comes from.
The 500 error is not helpful to solve this problem, you need to check the specific error of the azure function. You can use application insights to get the details error. The function must configure the corresponding application insights before you can view the log on the portal.
So you need to configure an application insights to your function app like this:
Then your function app will restart.
Of course, you can also go to kudu to view:
First, go to advanced tools, then click 'GO',
Then After you go to kudu, click Debug Console -> CMD -> LogFiles -> Application -> Functions -> yourtriggername. You will find log file there.
If you are based on linux OS, after go to kudu, just click 'log stream'(this is not supportted to consumption plan for linux.).

How to fix error: "Google.Apis.Auth: At least one client secrets (Installed or Web) should be set " for YouTubeAPI

I have created an HTTP trigger azure function, which holds the code (below) to upload a video to YouTube automatically. Source: (https://developers.google.com/youtube/v3/docs/videos/insert).
When I try to run the app locally using visual studio, I am getting the following error:
Executed 'Function1' (Failed, Id=d601d64a-2f2c-4f8a-8053-a2f33ca21dbc)
System.Private.CoreLib: Exception while executing function: Function1.
Google.Apis.Auth: At least one client secrets (Installed or Web)
should be set
It looks like a Google Authentication error, but I am unsure as to how to get this fixed and I see that YouTube API does not support Service account? How can this issue be fixed, is there a get around to this? Thanks in advance.
C# Code:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Upload;
using Google.Apis.YouTube.v3.Data;
using System.Reflection;
using Google.Apis.YouTube.v3;
using Google.Apis.Services;
using System.Threading;
namespace UploadVideo
{
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
log.LogInformation("YouTube Data API: Upload Video");
log.LogInformation("==============================");
try
{
await Run();
}
catch (AggregateException ex)
{
foreach (var e in ex.InnerExceptions)
{
log.LogInformation("Error: " + e.Message);
}
}
return new OkObjectResult($"Video Processed..");
}
private static async Task Run()
{
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
// This OAuth 2.0 access scope allows an application to upload files to the
// authenticated user's YouTube channel, but doesn't allow other types of access.
new[] { YouTubeService.Scope.YoutubeUpload },
"user",
CancellationToken.None
);
}
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = Assembly.GetExecutingAssembly().GetName().Name
});
var video = new Video();
video.Snippet = new VideoSnippet();
video.Snippet.Title = "Default Video Title";
video.Snippet.Description = "Default Video Description";
video.Snippet.Tags = new string[] { "tag1", "tag2" };
video.Snippet.CategoryId = "22"; // See https://developers.google.com/youtube/v3/docs/videoCategories/list
video.Status = new VideoStatus();
video.Status.PrivacyStatus = "unlisted"; // or "private" or "public"
var filePath = #"C:\Users\Peter\Desktop\audio\test.mp4"; // Replace with path to actual movie file.
using (var fileStream = new FileStream(filePath, FileMode.Open))
{
var videosInsertRequest = youtubeService.Videos.Insert(video, "snippet,status", fileStream, "video/*");
videosInsertRequest.ProgressChanged += videosInsertRequest_ProgressChanged;
videosInsertRequest.ResponseReceived += videosInsertRequest_ResponseReceived;
await videosInsertRequest.UploadAsync();
}
}
private static void videosInsertRequest_ProgressChanged(Google.Apis.Upload.IUploadProgress progress)
{
switch (progress.Status)
{
case UploadStatus.Uploading:
Console.WriteLine("{0} bytes sent.", progress.BytesSent);
break;
case UploadStatus.Failed:
Console.WriteLine("An error prevented the upload from completing.\n{0}", progress.Exception);
break;
}
}
private static void videosInsertRequest_ResponseReceived(Video video)
{
Console.WriteLine("Video id '{0}' was successfully uploaded.", video.Id);
}
}
}
It looks like you were trying to use the service account to do the OAuth2 web server flow, which wont work. The correct code form creating a service account credential is as follows.
GoogleCredential credential;
using (var stream = new FileStream(serviceAccountCredentialFilePath, FileMode.Open, FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream)
.CreateScoped(scopes);
}
Note
as i have mentioned in your other questions the YouTube API does NOT support service account authentication. You must use Oauth2 and i am not convinced this can be done inside of azure functions. As there is no way to spawn the web browser window to request authorization of the user.

deliver token manually (in addition to the owin configuration way)

I have actually an asp.net website application, that can deliver token to an user with the following way :
the user logs into the application, go to a specific page and obtains a clientid and a clientsecret.
then, he calls the following api "....api/token" by giving clientid and clientsecret (client credentials grant type) to get the token.
This is the associated code :
using Microsoft.Owin;
using Owin;
using System;
using Microsoft.Owin.Security.OAuth;
[assembly: OwinStartup(typeof(MyApp.Web.App_Start.OwinStartup))]
namespace MyApp.Web.App_Start
{
public class OwinStartup
{
public void Configuration(IAppBuilder app)
{
OwinWebApiStartup.Configuration(app);
}
}
}
public static class OwinWebApiStartup
{
public static void Configuration(IAppBuilder app)
{
var provider = //my provider implementation;
var oauthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(20),
Provider = provider,
};
app.UseOAuthAuthorizationServer(oauthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
AccessTokenProvider = //my provider implementation,
});
}
}
This is working nicely. But I would like to add a new feature, where a javascript client code, not an user anymore, would like to call my apis, and so it will need to have a token, but do not have a clientid and clientsecret.
This is my idea :
Create a new api endpoint, (only this one will be reachable by my javascript client code without token, and there, the code will generate a token (thanks to the username of the current user connected) and return this one (that will
be the same that an user could have obtained with the existing method) to be used by the javascript client code
I faced this problem in the past. I solved this via querystring, cause owin could only provide one token ressource. In fact it makes sense to rely on owin and on not implementing your own code.
My pseudo solution:
KeyValuePair<string, string[]> typePair = ctx.Request.Query.FirstOrDefault(x => x.Key == "type");
LoginType? loginType = GetLoginType(typePair);
[...]
switch (loginType)
{
case LoginType.User:
[...]
////within this routine you could set your claims depending on your needs
If you get another solution, I'd be grateful for sharing

WSFederation Sign-in - Asp.net 4.6.1

So I'm trying to sort out web-based authentication using the WSFederation protocal. We've sorted out the setup, and my web app can reach the login page, after some headache:
(Asp.net on-premises authentication - The remote certificate is invalid according to the validation procedure)
Now I'm getting a 'IDX10201: None of the the SecurityTokenHandlers could read the 'securityToken' error. From what I understand, we'll need middleware to deal with the security tokens. So I'm trying to get started with this:
https://www.scottbrady91.com/Katana/WS-Federation-Token-Encryption-using-Microsoft-Katana
So I've set the TokenValidationParameters option in the WsFederationAuthenticationOptions, but I'm getting an error from VisualStudio saying that 'Cert' does not exist in the current context. I'm confused as to why, as my code is nearly identical to the guides.
I'm also wondering if our certificate has simply been improperly configured. I came across some SSL guidelines for ADFS, and I know our IT guy hasn't gone down that road (yet). I'd like to rule that out as a possible cause, but if someone knows that it is, or is not, the cause, it'd save me time and be greatly appreciated.
EDIT: After some reading, there are some things that are unclear to me? We're using an ADFS server to handle the credentials, but as I understand it, ADFS should also handle our tokens without any additional work. Am I wrong? Should I be using middleware? Or is there a problem with the ADFS server configuration?
using System;
using System.Collections.Generic;
using System.Configuration;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.WsFederation;
using Owin;
using System.Security.Cryptography.X509Certificates;
using System.Security;
using System.Net.Security;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.IdentityModel.Tokens;
using Microsoft.Owin;
using RCHHRATool;
using System.Net;
using System.IdentityModel.Selectors;
namespace RCHHRATool
{
public partial class Startup
{
private static string realm = ConfigurationManager.AppSettings["ida:Wtrealm"];
private static string adfsMetadata = ConfigurationManager.AppSettings["ida:ADFSMetadata"];
private X509Certificate2 certificate;
public void ConfigureAuth(IAppBuilder app)
{
Debug.WriteLine("Configure Auth Started");
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType =
WsFederationAuthenticationDefaults.AuthenticationType });
//System.Net.ServicePointManager.ServerCertificateValidationCallback.
//ServicePointManager.ServerCertificateValidationCallback = RemoteCertificateValidationCB;
var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
foreach(X509Certificate2 cert in store.Certificates)
{
Debug.WriteLine(cert.Issuer);
if (cert.Issuer.Equals("CN=xxxxx.xxxxx.com"))
{
this.certificate = new X509Certificate2(cert);
}
}
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
SignInAsAuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType,
Wtrealm = "https://localhost:44340",
Wreply = "http://localhost:56879",
MetadataAddress = adfsMetadata,
AuthenticationType = "adfs",
SecurityTokenHandlers = new SecurityTokenHandlerCollection
{
new X509SecurityTokenHandler
{
Configuration = new SecurityTokenHandlerConfiguration
{
IssuerTokenResolver = new X509CertificateStoreTokenResolver(StoreName.Root,
StoreLocation.LocalMachine)
}
}
}
//},
//TokenValidationParameters = new TokenValidationParameters
//{
// ValidAudience = "https://localhost:44340/",
// ValidIssuer = "xxxxx.xxxxx.com",
// IssuerSigningToken = new X509SecurityToken(this.certificate)
//}
});
}
Turns out that asp.net (framework 4.6.1) & ws-federation doesn't handle encrypted security tokens out of the box. I followed a great guide to resolve the token error. After some tuning (watch your certificate footprint, and make sure your certificates are in trusted root), I managed to get the authentication working.

Consume ProjectData from Project Server 2013 Workflow - Forbidden

I need to consume data from http://project/pwa/_api/ProjectData Project OData service from Project Server 2013 Workflow.
But I got "Forbidden" Response Code.
User have all rights (Administrator, Site Collection Administrator).
Consuming other endpoints (ProjectServer, Web, Lists) successfull, even from other site collections and farms.
When I need configure a security to successfully consume ProjectData?
Thank you!
Have you tried to provide credentials
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.ProjectServer.Client;
static void Main(string[] args)
{
const string pwaPath = "http://ServerName/pwa/";
const string password = "pwa_password";
const string userName = "user_name#your_company.onmicrosoft.com";
var projContext = new ProjectContext(pwaPath);
var secureString = new SecureString();
password.ToCharArray().ToList().ForEach(x => secureString.AppendChar(x));
projContext.Credentials = new SharePointOnlineCredentials(userName, secureString);
// Get the list of published projects in Project Web App.
projContext.Load(projContext.Projects);
projContext.ExecuteQuery();
Console.WriteLine("\nThere are {0} projects", projContext.Projects);
}

Resources