Subscribing to Notifications in MS Graph

Subscribing to Notifications in MS Graph

Responding to security alerts and notifications can be time critical.  Fortunately, advanced tools like Splunk, Microsoft Graph, GSuite, SumoLogic, Jira and more allow notifications or alerts to be sent to webhooks. Using a webhook agent in the Tines Security Automation platform, it is simple to receive and process these alerts instantly. Subscribing to Notifications in MS Graph can save you time and allow your team respond to a threat or notification the instant it is generated.  

For many tools, subscribing to notifications can be done through the UI.  However other tools like Microsoft Graph require you to validate the subscription using OAuth, and renew the subscription periodically. In this tutorial we'll demonstrate how top subscribe to notifications in Microsoft Graph.

What notifications are available?

Microsoft Graph Subscriptions are available on over a dozen tools including the below resources:

  • Security Alerts
  • Azure Security Center
  • Microsoft ATP
  • Microsoft Cloud App Security
  • Office 365
  • Azure Sentinel
  • New Emails sent to an Inbox
  • Group Changes
  • File uploads or modifications in OneDrive for Business
  • Active Directory Updates e.g. changes to a user profile
  • Sharepoint Lists
  • Contacts

In an earlier blog, we configured an O365 application to interact with the Graph API to process phishing emails. To do this, Tines polls the API and checks for new mails in a mailbox, every 5 minutes for example. Instead of waiting 5 minutes between calls, however, we can implement the Subscription Change Notification function to receive email notifications from O365 in real time via a Tines webhook.

Note, for this tutorial, you’ll need a preconfigured Azure Application with Delegated Mail.Read, offline_access permissions, and an o365 OAuth Credential in your Tines tenant. The steps to setting up this application and credential are outlined in this blog.

Step 1: Create a Webhook

The first step to receiving alerts is to create a valid webhook. During the subscription creation process, o365 will send a Validation Token to this webhook. For a webhook to be valid for subscriptions it will require a response that fulfills three requirements:

  1. A HTTP Status 200 response code
  2. A Content-Type of `text/plain`
  3. A body containing the validationToken provided by the initial Graph request

To do this in Tines first create a new story, then drag a Webhook Agent onto the Storyboard. This agent will receive new email notifications directly from o365.  We then add a dynamic response of the Validation Token. The below Webhook Agent configuration will satisfy each of the above requirements:

{
 "secret": "e95ad9f65e17208e9a02b93066ece17f",
 "verbs": "get,post",
 "response_code": "200",
 "response": "{{.validationToken}}"
 }

Step 2: Create a Subscription

To create a subscription, we need to make a post request to the subscriptions endpoint, with the resource we are subscribing to and our webhook url. In curl the request would look like this:

curl --request POST --url https://graph.microsoft.com/v1.0/subscriptions -H 'authorization: Bearer $password' -H 'content-type: application/json' --data '{"changeType":"created","notificationUrl":"https://your-webhook-url.com","resource":"/me/mailfolders('\''inbox'\'')/messages","expirationDateTime":"2020-05-05T00:00:00","clientState": "SecretClientState"}'

In Tines, we can use a HTTP Request Agent to create the subscription. This agent configuration will submit a request to the Microsoft Graph API. Using the resource '/me/mailfolders('inbox')/messages' we are registering a subscription to all new emails in the inbox of the Azure Application owner.

{
"url": "https://graph.microsoft.com/v1.0/subscriptions",
"content_type": "json",
"method": "post",
"payload":
	{ "changeType": "created",
  	"notificationUrl": "https://spring-wildflower-6327.tines.io/webhook/9bcde94f6d3d0194b6c396b29dc59b61/e95ad9f65e17208e9a02b93066ece17f",
    "resource": "/me/mailfolders('inbox')/messages",
    "expirationDateTime": "{{ "now" | date: "%s" | plus: 240000 | date: "%Y-%m-%dT%H:%M:%S.%H%M%d0Z" }}",
    "clientState": "SecretClientState"
    },
"headers": {
	"Authorization": "Bearer {% credential msgraph %}"
  } 
}

Microsoft Graph Subscriptions for new email notifications are only valid for a maximum of 4,230 minutes (slightly less than 3 days), and the expiration date and time is needed as part of the request. To calculate expirationDateTime, we are using a Liquid Tag to get the current time and parse it to seconds. Next 240000 seconds is added to the time, before it is parsed into the timestamp format required by Graph. This timestamp will be in UTC.

Testing the Subscription

The notificationUrl in this agent configuration is the destination of the Webhook Agent we created earlier. This url can be found in the “Summary” tab of the webhook agent.

Now that the initial configuration is complete, we can Run the HTTP Request Agent. This sends our subscription request to the Graph API. The Graph API will send a request to the “notificationUrl“ webhook, and the webhook will respond with the required validationToken. If it is valid, it will authenticate the subscription to Graph and respond with 'changeType':'created'.

Step 3: Auto-Renew the Subscription

The subscription we’ve just created will be valid for less than 3 days, after which it will expire unless renewed. Renewing is straight forward, though. In curl the request would look like:

curl --request PATCH --url https://graph.microsoft.com/v1.0/subscriptions/7664135e-c1dd-4fc0-8794-0936264529d9 -H 'authorization: Bearer $password' -H 'content-type: application/json' --data '{"expirationDateTime":"2020-05-08T00:00:00"}'

In Tines, we’re going to use a HTTP Request Agent and the HTTP ‘patch’ method to update the expirationDateTime of the subscription.

Using the same Liquid Filter used earlier, we generate a new expiration date.

 {
"url": "https://graph.microsoft.com/v1.0/subscriptions/7664136e-c1dd-4fc0-8294-0936264529d9",
"content_type": "json",
"method": "patch",
"payload": {
	"expirationDateTime": "{{ "now" | date: "%s" | plus: 240000 | date: "%Y-%m-%dT%H:%M:%S.%H%M%d0Z" }}"
	},
"headers": { 
	"Authorization": "Bearer {% credential msgraph %}"
}
}

Graph will respond with a HTTP Status 200 and a body confirming the details of the subscription.

To ensure the mail alerts keep coming in to the webhook we should schedule this HTTP Request Agent to run every day to renew the subscription. If you're in Tines, congratulations, you've now subscribed to new emails! You can use this process to subscribe to other notifications like security alerts, calendar invites, File Uploads, Active Directory Changes and more. Subscribing to Notifications in MS Graph is just one part of the automation process, however. We are not quite finished building our story!

Step 4: Process mails coming in to the webhook

The next time a mail arrives in our chosen inbox, Microsoft will send a notification to the Webhook Agent. The notification will look like this: 

It doesn’t look like an email just yet, but we’re nearly there! The important value in this event is the "id" field, which is a direct pointer to the mail that just arrived. First, we’re going to explode the "value" array into its individual elements. In the above example there is only one element in the array, however it is possible two mails may arrive at the same time, and be dispatched in the same notification. This is especially important if you’re interested in changes as well as creations - like creating and updating a calendar event, or processing security alerts, for example.

An Event Transformation Agent in “Explode” mode will take each element in an array, and emit each one as a new event.

 {
"mode": "explode",
"path": "{{.webhook_agent.value}}",
"to": "individual_notification"
}


Retrieving Individual Events

The last step to getting a basic story up and running is to use the ID from the earlier event and get the content of the message. In curl we would take the ID from the subscription and make the following request:

curl --request GET --url https://graph.microsoft.com/v1.0/me/messages/$ID -H 'authorization: Bearer $password' -H 'content-type: application/json'

In Tines will need another HTTP Request Agent using the below configuration to get the content.

{
"url": "https://graph.microsoft.com/v1.0/me/messages/{{.explode_graph_notification_array.individual_notification.resourceData.id}}",
"content_type": "json",
"method": "get",
"headers": {
"Authorization": "Bearer {% credential msgraph %}"
}
}


When that agent receives an event from the previous explode agent, it will use the message ID field to download a JSON formatted email.

At the end of this, we have a short Tines Story to receive new email notifications, get the email content, and renew the subscription every day. We do not need the Create Subscription agent now that everything is set up and working, so we can deleted this agent.

From this point we could go on to create a case in a case management system, send a notification to Slack, extract and scan URLs from the mail, or automate the other manual steps Security Analysts will carry out when investigating an email. You can download this story here.

Reference

https://docs.microsoft.com/en-us/graph/webhooks#notification-endpoint-validation

Summary

Subscribing to Notifications in MS Graph API allows us to build on existing foundations to improve efficiency and simplicity. These are just the first couple of steps towards automating an entire process and reclaiming analyst time to allow them to focus on the high priority incidents.


💡  What now ? If you’re unsure what’s next on your automation journey, grab a quick demo or ask us how we'd automate your use case ? Either way you can experiment with a free, no strings, fully-functional trial to see what's possible...

Thomas Kinsella
Thomas Kinsella
Co-founder & Chief Operating Officer, Tines