Get function key (name) used when calling Azure Function - azure

I need to be able to identify the key (ideally key name) provided in the header (x-functions-key) for the POST to the Azure Function in the Run method, e.g.
Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log, ClaimsPrincipal principal)
It is great to be able to protect access to the Azure Function adding Function Keys in the Azure Portal panel, but I must be able to tell which function key was used. Ideally it would be possible to associate claims on each function key, but as long as I can at least figure out which key was used I will be happy.

Simply get the claim "http://schemas.microsoft.com/2017/07/functions/claims/keyid" from the req.HttpContext.User.Claims object. It contains the key id in case a Function key was used.
Works like a charm, and does not require external lookups.
const string KEY_CLAIM = "http://schemas.microsoft.com/2017/07/functions/claims/keyid";
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
var claim = req.HttpContext.User.Claims.FirstOrDefault(c => c.Type == KEY_CLAIM);
if (claim == null)
{
log.LogError("Something went SUPER wrong");
throw new UnauthorizedAccessException();
}
else
{
log.LogInformation( "Processing call from {callSource}", claim.Value);
}

Sajeetharan answered how you can get the Keys using REST API.
About the ability to use RBAC, you need to use Managed Identities and you can find more information about how to set it up: https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=dotnet

In Azure Functions v1:
[FunctionName("MyAuthenticatedFunction")]
public static async Task<HttpResponseMessage> MyAuthenticatedFunction([HttpTrigger(AuthorizationLevel.Function)] System.Net.Http.HttpRequestMessage reqMsg, ILogger log)
{
if (reqMsg.Properties.TryGetValue("MS_AzureFunctionsKeyId", out object val))
log.LogInformation($"MS_AzureFunctionsKeyId: {val}");
}
Code reference: WebJobs.Script.WebHost/Filters/AuthorizationLevelAttribute.cs#L77

Related

Azure Function App documentation using API Management

I have created a Azure Function App. The function app connects to a SQL DB and has the following features
Return all the records in a table
Returns the records based on the column name using the below code
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
string loan_id = req.Query["loanid"];
string loan_amount = req.Query["loanamount"];
if (string.IsNullOrEmpty(loan_id)) {
//Do something when dont give loan id.
} else if (string.IsNullOrEmpty(loan_amount)) {
//DO something when dont give loan amount.
}
return new OkObjectResult("This is a test.");
}
I would like to document the function app using API Management/Swagger. Can you please let me know how this can be achieved?
Thanks in advance
You just need to create an API management service instance from the portal and add the function endpoint using the open api.
You can follow this documentation on how to do the same.

Azure Function URL missing Function key

I have deployed .Net core function app in Azure. Have successfully created a Build and release pipeline. When I go the the specific function in Azure and click the button Get Function URL, I dont see function key appended to the url
All i see is the following error
https://srlcustomermanagerapp.azurewebsites.net/api/customers-details
When I try to run this url , I get 500 internal error. I have run the function app locally and it runs perfectly fine.
Am I missing some configuration in the Azure portal as when I click the Get Url button I should be getting an URL with the function key to it
I tried running the function from code + Test shown below as well as using postman and get 500 error
Screenshot
Get Function URL
Function
public class GetCustomersOrders
{
private readonly ICustomerOrdersRepository _repo;
private readonly IMapper _mapper;
private readonly TelemetryClient _telemetryClient;
public GetCustomersOrders(ICustomerOrdersRepository repo, IMapper mapper, TelemetryConfiguration configuration)
{
_repo = repo;
_mapper = mapper;
_telemetryClient = new TelemetryClient(configuration);
}
[FunctionName("GetCustomersOrders")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "customer-orders")] HttpRequest req,
ILogger log)
{
this._telemetryClient.TrackTrace("C# HTTP trigger function processed a request.");
var customersOrders = _repo.GetCustomerOrders();
return new OkObjectResult(_mapper.Map<List<CustomerOrdersViewModel>>(customersOrders));
}
}
The configuration setting "authLevel": "anonymous" may be to blame. As per the documentation:
Functions lets you use keys to make it harder to access your HTTP function endpoints during development. Unless the HTTP access level on an HTTP triggered function is set to anonymous, requests must include an API access key in the request.
So my guess is that the function isn't expecting a function key because of this setting, and the fact you're getting a 500 back is a red herring and nothing to do with a missing function key.

Hooks for inspecting claims Azure functions?

Lets say I have two Azure functions:
public static class MyFunctions
[FunctionName("DoIt")]
public static async Task<HttpResponseMessage> DoIt(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req,
TraceWriter log)
{}
[FunctionName("DoSOmethingElse")]
public static async Task<HttpResponseMessage> DoOther(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req,
TraceWriter log)
{}
}
And then I configure the Function AppService to require AzureAD authentication. Lets say I wanted particular permissions like Role membership or other claims. I could do the following in a function I call at the top of each method:
inspect the req parameter for the bearer token, parse the JWT
look at the claims
Use AuthenticationContext or another JWT library to get Microsoft Graph tokens to get additional data
My question is are there options to do any of the following?
Create "before hook" function so every http function I write in that class or deploy to the service container goes through this inspection
Performa any of these authorization via attributes?
Access a claimsIdentity directly?
I've found some code sample related to what you are looking for:
stuartleeks/AzureFunctionsEasyAuth (Github)
So the interesting part is here (will give you the main idea):
[FunctionName("GetClaims")]
public static HttpResponseMessage GetClaims(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)]
HttpRequestMessage request,
TraceWriter log)
{
if (Thread.CurrentPrincipal.Identity.IsAuthenticated)
{
var claimsPrincipal = (ClaimsPrincipal)Thread.CurrentPrincipal;
var claims = claimsPrincipal.Claims.ToDictionary(c => c.Type, c => c.Value);
// Could use the claims here. For this sample, just return it!
return request.CreateResponse(HttpStatusCode.OK, claims, "application/json");
}
else
{
return request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Not Authorized");
}
}
The simplistic solution would be to create a function that get the claims and you can call this function in every others functions.
Azure functions has Function Filters (As per the documentation it is still in preview.)
Function Filters provide a way to customize the WebJobs execution pipeline with your own logic. Filters are very similar in to ASP.NET Filters. They can be implemented as declarative attributes that can be applied to your job functions/classes.
Filters allow you to encapsulate common logic to be shared across many different functions. They also allow you to centralize logic for cross cutting concerns (e.g. validation, logging, error handling, etc.).
So you should be able to create a custom authorization filter with these information.

Error creating HttpTrigger Azure Function with CosmosDB document output

I want to make an Azure Function that takes a JSON body passed to it and inserts this document in to an Azure COSMOSDB instance.
To do so, I created this function in the Azure Functions Portal:
And implement the function like so:
#r "Newtonsoft.Json"
using Newtonsoft.Json.Linq;
using System.Net;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, object outputDocument)
{
var requestContent = await req.Content.ReadAsStringAsync();
log.Verbose($#"Received request:\n{requestContent}");
var newDoc = JObject.Parse(requestContent);
newDoc["Id"] = Guid.NewGuid().ToString();
newDoc["shardKey"] = newDoc.Value<string>(#"Id").Substring(8);
outputDocument = newDoc;
return req.CreateResponse(System.Net.HttpStatusCode.Created);
}
In the portal, I put in an easy sample doc:
{
"prop1": 2,
"prop2": "2017-02-20",
}
and click 'Run'
I'm immediately met with
as an overlay in the portal IDE along with
{
"id": "145ee924-f824-4064-8364-f96dc12ab138",
"requestId": "5a27c287-2c91-40f5-be52-6a79c7c86bc2",
"statusCode": 500,
"errorCode": 0,
"message": "'UploadDocumentToCosmos' can't be invoked from Azure WebJobs SDK. Is it missing Azure WebJobs SDK attributes?"
}
in the log area.
There seems to be nothing I can do to fix the issue, yet I sure feel like I'm doing everything right.
What do I need to do to simply take a JSON object as an HTTP Request to an Azure Function, and insert/upsert said object in to an Azure Cosmos DB instance??
For async functions you should use IAsyncCollector:
public static async Task<HttpResponseMessage> Run(
HttpRequestMessage req, TraceWriter log,
IAsyncCollector<object> outputDocuments)
{
...
await outputDocuments.AddAsync(newDoc);
}
Can you try adding out to dynamic outputDocument?
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, out dynamic outputDocument)

Azure function CRUD on Table Storage

How can we do CRUD with table storage in Azure functions:
I have insert working, but would like to know how to return entities and do updates and deletes too.
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, IAsyncCollector<User> outputTable)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
var user = new User();
user.PartitionKey = "Users";
user.RowKey = DateTime.Now.Ticks.ToString();
user.UserId = "aaaa";
user.Country = "uk";
await outputTable.AddAsync(user);
....
You can bind your function to an instance of CloudTable class, and then you get all its API at your hands.
I think you should be able to just replace IAsyncCollector<User> with CloudTable in your function definition and adjust the usage (provided you have a valid output binding).
See "Output usage" under Azure Functions Storage table bindings.

Resources