I have a Flutter client app that authorises the user using Google Provider. I want to use the dotnet core C# Google Cloud function to read the authorisation token and read the FireStore using Firebase Admin SDK. The documentation for this is scant and/or written for other languages.
Anyone have any examples or links to dotnet core documentation to do this as I've spent all day trying to figure this out?
I've got a simple function as per: https://cloud.google.com/functions/docs/quickstart-dotnet#whats-next
and I see some tests that give a clue to how some of the SDK works: https://github.com/firebase/firebase-admin-dotnet/blob/f6babbd4e59655f01be4a43230b5be198fc4f8cd/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAuthSnippets.cs#L608-L629
using Google.Cloud.Functions.Framework;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using FirebaseAdmin;
using FirebaseAdmin.Auth;
using Microsoft.Extensions.Logging;
using Google.Apis.Auth.OAuth2;
namespace HelloHttpFunction
{
public class Function : IHttpFunction
{
private readonly ILogger _logger;
public Function(ILogger<Function> logger) =>
_logger = logger;
//how to use firebase auth to check token and get uid from calling client
//how to read a set of docs from firestore
//already setup the Google environment variables
public async Task HandleAsync(HttpContext context)
{
HttpRequest request = context.Request;
// this my all guesswork below:
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.GetApplicationDefault(),
});
FirebaseToken decodedToken = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(idToken);
string uid = decodedToken.Uid;
var user = FirebaseAuth.DefaultInstance.GetUserAsync(uid);
await context.Response.WriteAsync("Hello, Functions Framework. ");
}
}
}
Related
We want to create an azure function in c# that retrieve the list of azure web app contained in the subscription (basically we want to call dynamically, for each webapp, the same API endpoint changing the subdomain of the api).
It's possible with c# retrieve the list of the web app contained in the same azure function subscriptions?
Usually we connect to the master database, we query the sys.databases to collect the dbname and understand the webapp names. But we are searching for a smartest way.
If you're in C# land, I'd look at using the ArmClient class to retrieve what you're looking for.
Install these (I've got a few others installed but start with that and see how you go, there may be a couple of others needed) Nuget packages ...
Azure.Identity;
Azure.ResourceManager;
Azure.ResourceManager.AppService
... and from there, using the DefaultCredential approach (if you've never used it, read up on it here -> https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/README.md) you can query your subscriptions webApps ...
using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.AppService;
using System;
using System.Threading.Tasks;
namespace AzureManagement
{
internal class Program
{
static void Main(string[] args)
{
GetAzureResources().Wait();
}
static async Task GetAzureResources()
{
var credential = new DefaultAzureCredential();
var armClient = new ArmClient(credential);
var subscription = await armClient.GetDefaultSubscriptionAsync();
var webSitesEnumerator = subscription.GetWebSitesAsync().GetAsyncEnumerator();
try
{
while (await webSitesEnumerator.MoveNextAsync())
{
var webSite = webSitesEnumerator.Current;
Console.WriteLine($"Web App Name ........ {webSite.Data.Name}");
Console.WriteLine($"Default Host Name ... {webSite.Data.DefaultHostName}\n");
}
}
finally
{
await webSitesEnumerator.DisposeAsync();
}
Console.ReadLine();
}
}
}
The above is obviously not a function app but the core code will still work for you and can be ported as need be.
Note: I could be telling you how to suck eggs, but, once deployed to Azure, you'll need to do the necessary work to ensure that the function app has the required access to retrieve all of the resource information you're looking for.
If you're unfamiliar with that, read up on the managed identity concept. It's very easy to setup -> https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity
Yes, one easy way is to use HttpClient and send a request to Azure Rest API:
GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Web/sites?api-version=2022-03-01
https://learn.microsoft.com/en-us/rest/api/appservice/web-apps/list
PS: you first need to acquire an authentication token.
https://www.youtube.com/watch?v=6b1J03fDnOg&t=329s
I am trying to get application insights to pick up on custom ActivitySource in a library, however the documentation is unclear on how to achieve this.
Currently I have the following:
...
public static readonly ActivitySource Source = new ActivitySource("MyCompany.Library");
...
In the library it is used like this:
using(var activity = Source.StartActivity("Action"))
{
...
}
And in my startup I've added the following:
services.ConfigureTelemetryModule<DependencyTrackingTelemetryModule>(
(m, o) => m.IncludeDiagnosticSourceActivities.Add("MyCompany.Library")
);
services.AddApplicationInsightsTelemetryWorkerService();
However, these activities are not being picked up by application insights.
Is there something else required to make application insights aware of these activities ?
I'd rather not 'pollute' these libraries with application insights code
ApplicationInsights SDKs does not support reporting telemetry from custom ActivitySource.
There is a preview version which supports ActivitySource based telemetry. (Its called OpenTelemetry AzureMonitorExporter)
https://learn.microsoft.com/azure/azure-monitor/app/opentelemetry-enable?tabs=net
Follow the below steps to operate:
Add the OpenTelemetry.Exporter.Console NuGet package.
dotnet add package OpenTelemetry.Exporter.Console
Update Program.cs with additional OpenTelemetry using directives
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
Update Main() to create the OpenTelemetry TracerProvider:
public static async Task Main()
{
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample"))
.AddSource("Sample.DistributedTracing")
.AddConsoleExporter()
.Build();
await DoSomeWork();
Console.WriteLine("Example work done");
}
Now the app collects distributed trace information and displays it to the console:
> dotnet run
You will get the result required.
Follow the below link for further reference:
https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-collection-walkthroughs
With reference to this article Authorization Request.
If my application user is already logged in, how can I request to get my profile using SDK or this API reference: https://graph.microsoft.com/v1.0/me/
SDK code I wrote:
public async Task<string> GetFullNameAsync()
{
try
{
var user = await _client.Me
.Request()
.Select(data => data.DisplayName)
.GetAsync();
return user.DisplayName;
}
catch (Exception ex)
{
return "404 Not Found";
}
}
For that, how can I get a bearer token string using delegated authentication for Web Application and single tenant in .NET Core as mentioned in the above article?
To get bearer token using delegated authentication, please check the below if helpful:
Make use of Microsoft.Identity.Web.MicrosoftGraph nuget package to implement Graph API from an ASP. NET Core web application.
The application authentication and the authorization are setup in the Startup class.
For delegated user access token make use of AddMicrosoftIdentityWebApiAuthentication method as below sample code:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
services.AddScoped<GraphApiClientDirect>();
services.AddMicrosoftIdentityWebApiAuthentication(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
services.AddControllers(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
}
Use GetAccessTokenForUserAsync method, to get new delegated access token for required scopes.
The Graph API client service can then be used in the API which is protected using the Microsoft.Identity .Web packages.
[Authorize]
[ApiController]
[Route("[controller]")]
public class GraphCallsController : ControllerBase
{
private readonly GraphApiClientDirect _graphApiClientDirect;
public GraphCallsController(GraphApiClientDirect graphApiClientDirect)
{
_graphApiClientDirect = graphApiClientDirect;
}
[HttpGet]
public async Task<string> Get()
{
var user = await _graphApiClientDirect.GetGraphApiUser()
.ConfigureAwait(false);
return user.DisplayName;
}
}
The correct initialization must be used while using Graph API client in ASP.NET Core applications for delegated access user access tokens.
Use the IHttpClientFactory to create the HttpClient instance to create instance.
Use ITokenAcquisition and the IHttpClientFactory interfaces to create the GraphApiClient requests for different scopes.
Please find below references to know more in detail:
Using Microsoft Graph API in ASP.NET Core | Software Engineering (damienbod.com)
Secure a .NET Core API using Bearer Authentication - Dotnet Playbook
I have a Blazor server-side application that uses .NET core 3.1. It uses Microsoft.AspNetCore.Authentication.Negotiate to authenticate user through Windows Credentials/Active Directory.
The issue I have is how to sign out user. After various research I found out that certain external authentication methods do not support sign out. For example Windows/AD does not need to be explicitly signed out. The only thing you need to do is clean identity and Claims principles locally in application. That is what I am having trouble with. The user also signs out automatically when you close browser.
I am using this middle ware to authenticate using Negotiate and am trying to clean claims of user during sign out. But it doesn't work.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Authentication;
namespace Test.Middleware
{
internal class ValidateAuthentication : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
if (context.User.Identity.IsAuthenticated)
{
await next(context);
}
else
{
await context.ChallengeAsync("Negotiate");
}
}
catch(InvalidOperationException) // this is for Windows/Negotiate sign out
{
context.User = new System.Security.Claims.ClaimsPrincipal();
}
}
}
}
Here is my configuration of services
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddElasticsearch(Configuration);
services.AddHttpContextAccessor();
services.AddScoped<ValidateAuthentication>();
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
}
Expected result is for user to be signed out. But the actual result is user remains signed in.
I am using Azure Mobile Services to provide data to a Windows Universal app and Azure API Management as a proxy for API usage and analytics purposes. This is working great.
Now I was asked to provide offline functionality to the application so I started using Azure Mobile Services Synchronization Context in order to implement this using SQLite as the local store.
Azure API Management requires me to send my subscription key as part of my query string. I have been doing this using the 'parameters' dictionary provided by the IMobileServiceTable.InsertAsync method and this was working fine as well.
Now the offline implementation requires me to use IMobileServiceSyncTable.InsertAsync method instead, which doesn't provide an overload with the 'parameters' dictionary. The MobileServiceSyncContextExtensions.PushAsync method does not seem to provide a way to add custom parameters to the query string either.
Does anyone know of a way to include custom parameters when using the Mobile Services Synchronization Context in order to send the subscription key of the Azure API Management service?
I've found the way to do this.
I implemented the following HTTP Message Handler:
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
class AzureApiManagementHandler : DelegatingHandler
{
string _subscriptionKey;
public AzureApiManagementHandler(string subscriptionKey)
{
_subscriptionKey = subscriptionKey;
}
protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
var baseUri = new UriBuilder(request.RequestUri);
string queryToAppend = string.Format("subscription-key={0}", _subscriptionKey);
if (baseUri.Query != null && baseUri.Query.Length > 1)
baseUri.Query = baseUri.Query.Substring(1) + "&" + queryToAppend;
else
baseUri.Query = queryToAppend;
request.RequestUri = baseUri.Uri;
return base.SendAsync(request, cancellationToken);
}
}
And then I passed it to the Mobile Services client in the constructor:
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://yoursubdomainhere.azure-api.net",
"yourapikeyhere",
new AzureApiManagementHandler("yoursubscriptionkeyhere")
);
I hope this is useful for anyone facing the same problem.