How to dynamically pass an argument to a function being called by a logic app with ethereum connector in Azure? - azure

I am using Azure blockchain Service and I made a logic app to call a function inside a smart contract whenever a particular trigger occurs.
While creating the logic app it asks me the argument with which I want to call the function.
Now, I do not want to hard code the argument.
It is something like on my website, there are multiple products available, and whichever product the user chooses, the function should be called with the name of the product as the argument.

You have two options here
HTTP triggered function and pass parameters using POST request
Queue triggered function and pass parameters using Azure Storage Queue
In first case you simply create HTTP trigger
Body configured as
{
"type": "object",
"properties": {
"product": {
"type": "string"
}
}
}
This means logic app request expects JSON like this
{
"product" : "abc"
}
This way you can use product from trigger
And use it as parameter for function call using either HTTP action
or Azure Function action
If you want to learn more about logic apps feel free to check my video intro on it https://youtu.be/ZvsOzji_8ow
If you are worried about publicly accessible webhooks for logic apps use Azure Storage Queue with Azure AD authentication or cover logic app with API management like described here https://marczak.io/posts/2019/08/secure-logic-app-with-api-management/

Related

How to use serverless Azure SignalR (REST API / Upstream) with ReactJS?

On high level I want to achieve real time communication between two ReactJS apps. I need to be able to create specific groups to separate the end users, that group will belong to another group with one or more manager users. The manager should be able to send messages (can a be string or object) to the whole end user group or just for one user within that group, which upon I can act in the end user app. The end users should be able to send a message for the specific group of managers.
Since Azure Cloud is given, a sensible choice would be to use the Azure SignalR, especially because it has a serverless plan.
I have created the SignalR service, set it to serverless mode.
Installed #microsoft/signalr package to the React apps.
Created a Nodejs negotiate HTTP triggered function with signalR binding.
At this point I'm connected to signalR. But I'm confused how to proceed.
On one hand I should be able to use SignalR REST API, on the other hand I could use SignalR Upstream. Upstream seems more suitable, since users can invoke hub methods (in my case Nodejs SignalR bindings in the Function App) and users gets notified when client connections are connected or disconnected. That is important for the manager users to see who is connected and if the connection is still alive. As next steps:
defined Upstream URL
created connected/disconnected bindings in the Function app
function.json:
{
"bindings": [
{
"type": "signalRTrigger",
"name": "invocation",
"hubName": "default",
"category": "connections",
"event": "connected",
"direction": "in"
},
{
"type": "signalR",
"name": "signalRMessages",
"hubName": "default",
"connectionStringSetting": "AzureSignalRConnectionString",
"direction": "out"
}
]
}
index.js:
module.exports = function (context, invocation) {
context.bindings.signalRMessages = [
{
target: "connected", // name of the client method to invoke
arguments: [invocation.ConnectionId],
},
];
context.done();
};
In similar manner sending a broad cast message:
{
"bindings": [
{
"type": "signalRTrigger",
"name": "invocation",
"hubName": "default",
"category": "messages",
"event": "broadcastMessage",
"parameterNames": ["message"],
"direction": "in"
},
{
"type": "signalR",
"name": "signalRMessages",
"hubName": "default",
"connectionStringSetting": "AzureSignalRConnectionString",
"direction": "out"
}
]
}
module.exports = function (context, invocation) {
context.bindings.signalRMessages = [
{
target: "broadcastMessage", // name of the client method to invoke
arguments: [
context.bindingData.message, // arguments to pass to client method. binding with parameterNames
],
},
];
context.done();
};
After connection from the React app, the connected method is fired automatically and I could invoke other methods like: siglarConnection.invoke("broadcast", 'Hi')
But this is as far as I got. No private message, no user groups and still need to manage the active connections somewhere.
Also there is a suggestion, that I could use userId to send messages directly, no need to bother with the connectionId. Since other functions are using App Service Authentication and the users are stored in AD B2C:
enabled the App Service Authentication for the Function app
Now for the React apps to connect I need to pass an access token with to the connection builder else I get a 401. Now I can apps connect again but now using the authenticated users access token, which is a good thing, but because of this my invokations does not work anymore. Most likely because I cannot supply access token with these and I get back 401.
Security is a must, so I decided to take a look at the REST API way.
Looks fairly straight forward, I need to call the specified endpoints, but calling them actually gives 401 response www-authenticate: Bearer error="invalid_token", error_description="The signature key was not found". Figures since I call the signalR service directly, providing AD B2C access token does not help. I probably need the access token from the negotiate, but I don't know how to get it. Sure enough it's in the negotiate response, but I was not able to intercept that.
Sorry for the lengthy description, but I believe it was necessary to understand my scenario. I may have a major overlook somewhere or someone with similar experience can clear up the confusion. There are tons of examples using C#, but I cannot use that.
Any help is appreciated.

azure data factory BlobEventsTrigger : set "advanced filter" programatically

I am trying to set "advanced filter" of BlobEventsTrigger programmatically.
They are reset at each deployment. I need only 3 and having 7 of them are causing the job to start twice. It is super annoying to delete them manually after each deployment.
I have tried to add a field "advancedFilters" or "blobType" to the trigger json file without success.
"typeProperties": {
"blobPathBeginsWith": "/bingofile/blobs/",
"blobPathEndsWith": "/_SUCCESS",
"ignoreEmptyBlobs": false,
"scope": "/subscriptions/bingofilesup/resourceGroups/bingofilesup/providers/Microsoft.Storage/storageAccounts/bingofilesup",
"events": [
"Microsoft.Storage.BlobCreated"
]
I've also tried az eventgrid system-topic event-subscription update but this library does not work when it comes to updating advanced filter. It asks an endpoint (which is normally a facultative argument) , and when provided the existing data factory endpoint, it fails reaching it.
I have checked the documentation about this endpoint and it is said to be the webhook endpoint .
Endpoint where EventGrid should deliver events matching this event
subscription. For webhook endpoint type, this should be the
corresponding webhook URL. For other endpoint types, this should be
the Azure resource identifier of the endpoint. It is expected that the
destination endpoint to be already created and available for use
before executing any Event Grid command.
But it does not work .
Deployment failed. Correlation ID:
95e4fab5-163e-48ab-8cb2-b23432516e53. Webhook validation handshake
failed for [webwook end point provided in the topic]. Http POST
request failed with response code Unknown. For troublehooting, visit
https://aka.ms/esvalidation.
Any observation or suggestion would be great, thanks in advance !
According to my test, the endpoint https://pmeastasia.svc.datafactory.azure.com:4443/triggerevent/BlobEventsTrigger/<> is juts a base URL. When the events are sent to data factory or update subscription, azure will generate an endpoint with the base URL to do auth. So if you want to update the subscription with other tools, I think you need to use fildder to catch the request to get the whole endpoint at first.

Is there a way to secure an Azure Function that will only be called from a specific Azure Logic App?

I understand that Azure Functions are potentially open endpoints on the internet if I read Microsoft’s documentation correctly and per conversations with a friend who has some experience working with web development paradigms that Azure Functions leverages. A cursory reading of security forums and stack overflow questions on the topic leads me to understand at least a couple options of securing them namely
Azure Active Directory
Shared Access Signatures (SAS) and
Azure Virtual Networks.
Context/ What does my Azure Function do? It manages a blob container related to an ETL of vendor data from a SFTP source to a SQL Endpoint which this ETL utilizes an intermediary blob container for file transfer and long term cold storage of source data. The Azure Function moves the blobs from one container to an archive container after they have been loaded to the SQL endpoint. Why Azure Function to manage the blob containers?
SSIS lacks ability to perform blob manipulation (i.e copy and delete)
Logic App lacks ability to perform a join (of files loaded to SQL endpoint and file names in blob container)
An example of one of the functions is shown here below:
using System.IO;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Net.Http;
using System.Net;
using Microsoft.WindowsAzure.Storage.Blob;
using System.Collections.Generic;
using System.Text;
namespace AFA_ArchiveBlob
{
public static class HttpTrigger_BlobInput
{
[FunctionName("HttpTrigger_BlobInput")]
public static async Task<HttpResponseMessage> Run(
//public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "{name}")] HttpRequest req,
string name,
ILogger log,
[Blob("{name}/blobname",FileAccess.ReadWrite,Connection = "AzureWebJobsStorage")] CloudBlobContainer myCloudBlobContainer
)
{
//Execution Logged.
log.LogInformation($"HttpTrigger_BlobInput - C# HTTP trigger function processed a request.");
//Run the query against the blob to list the contents.
BlobContinuationToken continuationToken = null;
List<IListBlobItem> results = new List<IListBlobItem>();
do
{
var response = await myCloudBlobContainer.ListBlobsSegmentedAsync(continuationToken);
continuationToken = response.ContinuationToken;
results.AddRange(response.Results);
}
while (continuationToken != null);
//Query the names of the blobs. Todo: can this be a single line linq query select instead?
List<string> listBlobNames = new List<string>();
foreach (CloudBlockBlob b in results)
{
listBlobNames.Add(b.Name);
}
//Serialize the list of blob names to json for passing to function caller via return statement
var jsonReturn = JsonConvert.SerializeObject(listBlobNames);
log.LogInformation("Returning the following JSON");
log.LogInformation(jsonReturn);
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(jsonReturn, Encoding.UTF8, "application/json")
};
}
}
}
Firstly, even though using keys might be convenient, I see that official documentation advises against using keys to secure function endpoint in production scenarios.
I suggest it would be a better choice to go with Azure Active Directory for security.. as explained here Secure an HTTP endpoint in production
How to Implement
I see two possible approaches:
1. Simple Approach: Check that calling application is your Azure logic app specifically
Enable Azure Active Directory Authentication for your Azure Function App. You can simply use Express settings (with create a new Azure AD app)
Enable Managed Service Identity for your Logic App.
Find out appid for Managed Service Identity associated with your logic app.. go to Azure Portal > Azure Active Directory > Enterprise Applications > All Applications > Relevant Service Principal (Explained in more detail with screenshots in another SO post here)
Authenticate your logic app to Azure function using Managed Service Identity as explained here.. Authenticate with managed identity in logic app.. note that resource being accessed will be your Azure function.
In your function code, now you can check that appid claim in access token should exactly match the appid for logic app (i.e. logic app is the one calling your function).. otherwise you can reject the call with Unauthorized exception.
2. A more declarative Approach: Have an application permission defined for Azure function app and check for this permission/role being present in auth token from client calling your function
This approach is a little more declarative, as you define an application permission that needs to be assigned to any application that can call your Azure function.
Enable Azure Active Directory Authentication for your Azure Function App. You can simply use Express settings (with create a new Azure AD app)
Now go to Azure Active Directory > App Registrations > App registration for your function app > Manifest
Add a new application role.. using json like this:
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"displayName": "Can invoke my function",
"id": "fc803414-3c61-4ebc-a5e5-cd1675c14bbb",
"isEnabled": true,
"description": "Apps that have this role have the ability to invoke my Azure function",
"value": "MyFunctionValidClient"
}]
Enable Managed Service Identity for your Logic App.
Find out appid for Managed Service Identity associated with your logic app.. as already explained in approach 1 above
Assign the app permission to this managed service identity..
New-AzureADServiceAppRoleAssignment -ObjectId <logicappmsi.ObjectId> -PrincipalId <logicappmsi.ObjectId> -Id "fc803414-3c61-4ebc-a5e5-cd1675c14bbb" -ResourceId <yourfunctionaadapp.ObjectId>
Authenticate your logic app to Azure function using Managed Service Identity.. as already explained in approach 1 above
Now, in the auth token received by your function, you can check that the role claims collection must contain a role named "MyFunctionValidClient" otherwise you can reject the call with Unauthorized exception.
In addition to the above steps explained by #Rohit Below step is important:
Go to Host.json of the function.
Default authLevel : "function" should be changed to "authLevel": "anonymous".
This does not mean anyone can access the function as with Log on AD sign-in authentication required sign user however with managed identity in logic app function authenticate with service principle.

Dynamically calling several back-end endpoints from within Azure APIM policy

I'm calling a back-end API from Azure API Management (APIM) and I need to provide the JSON schema for my custom connector in Logic Apps/Flow.
Depending on the content of the response I'm getting, I need to perform additional calls in order to provide an enumeration/drop down.
Consider a response from the back-end API, like this:
{
"member1": {
"prop": "content"
},
"member2": {
"prop": "content",
"datasource": "http://someurl.com/api/member2/content"
},
"member3": {
"prop": "content"
},
"member4": {
"prop": "content"
"datasource": "http://someurl.com/api/memberfour/content"
}
}
I need to perform additional calls to the URLs in the "datasource" members in order to provide additional data, but these are obviously dynamic, depending on the call I'm performing. I'm a bit stuck since I can't seem to perform a send-request policy for a dynamic number of calls and URLs. How would I best approach this?
If I understand the scenario correctly, I don't think you want to use APIM to make the calls to the datasource URLs because then you wouldn't be able to get those results back to logic apps. I think what you are looking for is the x-ms-dynamic-values which is documented here
You can use this extension to describe both the primary operation which will provide your content and some secondary operations that will return the lists used to fill the drop downs for the Logic Apps UI. You will probably need to create additional APIM operations to surface those lists.

Building SOAP Listener with Azure Functions

I am using Azure Functions to build some integrations between various systems. I new requirement is to respond to record updates in Salesforce. Some quick research yielded what seems like a good solution from the Salesforce side. Use Outbound messaging which can send SOAP requests on record modifications.
How to create Salesforce application that will send record to external web service when record created/changed(https://salesforce.stackexchange.com/questions/73425/how-to-create-salesforce-application-that-will-send-record-to-external-web-servi)
The challenge now is to be able create a SOAP listener in Azure Function. I have created basic HTTP Triggers for my other listeners. Is there anything "built-in" to Azure Functions that would allow me to easily consume the incoming SOAP request?
Salesforce has the basics for a solution based on a more traditional web service and an ASMX file but I am not sure if or how that can be applied in Azure Functions. (https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_om_outboundmessaging_listener.htm)
That notification is just a SOAP request that is made over HTTP, so really not too different than a regular HTTP trigger request.
Although you could just treat that as a plain request and parse the contents yourself, Azure Functions does expose the great WebHook support we get from ASP.NET WebHooks, and luckily, there is a Salesforce receiver that significantly simplifies this task.
DISCLAIMER: It's worth noting that although the receiver is technically enabled in Azure Functions, there's no official support for it yet, so you won't find a lot of documentation and help will be limited to what you get on SO and Forums. Official support to this and other receivers will hopefully be coming soon, which means documentation, templates and UI support will become available.
To get started, you need the following:
Create a new function, selecting the GenericWebHook - CSharp template (this works for node as well, but I'll focus on C# here.
Follow the steps outlined on the ASP.NET WebHooks integration with Salesforce post in order to create the outbound message. Here you want to use the Function Url given to you by the portal WITHOUT THE CODE QUERY STRING (having the code there wouldn't hurt, but the receiver does not use that information).
IMPORTANT: Get your Salesforce Organization ID, which will be used for authentication and is located under Administer > Company Profile > Company Information > Salesforce.com Organization ID and back in the Azure Functions portal, open the Keys panel, delete your default function key (not host key) and create a new key, named default (this name is important) using the Organization ID value you got from Salesforce.
Go to Integrate
On the integration page, select Advanced Editor on the upper right (as mentioned, there's no official support, so the UI does not expose this. We're putting our explorer hats on and venturing into a more advanced workflow here :) )
Change the webHookType property value to sfsoap and save the configuration. Your function.json config should look like the following:
function.json:
{
"bindings": [
{
"type": "httpTrigger",
"direction": "in",
"webHookType": "sfsoap",
"name": "req"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
],
"disabled": false
}
Switch to the Develop tab. We're ready to write our code.
This is where the ASP.NET WebHooks receiver shines! It will parse the notification for you, exposing strong typed objects you can work with. All you need to do is modify the method/function signature you get withe template to use the SalesforceNotifications type, making sure you're referencing the required assembly (Microsoft.AspNet.WebHooks.Receivers.Salesforce, which is made available to you, so no need for package reference) and namespace reference (Microsoft.AspNet.WebHooks).
Here is a full sample of a function that will receive the request and log the Organization ID, Action ID, grab the first notification and log all of its properties:
#r "Microsoft.AspNet.WebHooks.Receivers.Salesforce"
using Microsoft.AspNet.WebHooks;
public static void Run(SalesforceNotifications req, TraceWriter log)
{
log.Info($"Salesforce webhook was triggered!");
log.Info(req.OrganizationId);
log.Info(req.ActionId);
var notification = req.Notifications.First();
foreach (var p in notification.Keys)
{
log.Info($"{p} = {notification[p]}");
}
}
This process will be a lot smoother when the receiver is officially supported, but even with the added steps, this still beats having to parse the SOAP messages yourself :)
I hope this helps!

Resources