Skip to content

Commit f74b289

Browse files
author
jhamilton
committed
Fixed Azure token revoker
1 parent 4d51d2f commit f74b289

File tree

3 files changed

+86
-43
lines changed

3 files changed

+86
-43
lines changed

responders/AzureTokenRevoker/AzureTokenRevoker.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
{
22
"name": "AzureTokenRevoker",
33
"version": "1.0",
4-
"author": "Daniel Weiner @dmweiner",
4+
"author": "Daniel Weiner @dmweiner, revised by @jahamilto",
55
"url": "https://github.com/TheHive-Project/Cortex-Analyzers",
66
"license": "AGPL-V3",
77
"description": "Revoke all Microsoft Azure authentication session tokens for a list of User Principal Names",
8-
"dataTypeList": ["thehive:case"],
9-
"command": "AzureTokenRevoker.py",
8+
"dataTypeList": ["thehive:case_artifact"],
9+
"command": "AzureTokenRevoker/AzureTokenRevoker.py",
1010
"baseConfig": "AzureTokenRevoker",
1111
"configurationItems": [
12-
{"name": "redirect_uri",
13-
"description": "Azure AD Application URI (Example: https://login.microsoftonline.com/TENANTIDHERE/oauth2/token)",
12+
{"name": "tenant_id",
13+
"description": "Azure Directory/Tenant ID",
1414
"type": "string",
1515
"multi": false,
1616
"required": true

responders/AzureTokenRevoker/AzureTokenRevoker.py

+44-38
Original file line numberDiff line numberDiff line change
@@ -10,55 +10,61 @@
1010
class AzureTokenRevoker(Responder):
1111
def __init__(self):
1212
Responder.__init__(self)
13-
self.client_id = self.get_params('config.client_id', None, 'Azure AD Application ID/Client ID Missing')
14-
self.client_secret = self.get_params('config.client_secret', None, 'Azure AD Registered Application Client Secret Missing')
15-
self.redirect_uri = self.get_params('config.redirect_uri', None, 'Set a redirect URI in Azure AD Registered Application. (ex. https://logon.microsoftonline.<tenant id>/oauth2/token)')
13+
self.client_id = self.get_param('config.client_id', None, 'Azure AD Application ID/Client ID Missing')
14+
self.client_secret = self.get_param('config.client_secret', None, 'Azure AD Registered Application Client Secret Missing')
15+
self.tenant_id = self.get_param('config.tenant_id', None, 'Azure AD Tenant ID Mising')
1616
self.time = ''
1717
def run(self):
18-
try:
19-
self.user = self.get_params('data.data', None, 'No UPN supplied to revoke credentials for')
20-
if not self.user:
21-
self.error("No user supplied")
22-
base_resource = "https://graph.microsoft.com"
18+
Responder.run(self)
2319

24-
token_data = {
25-
"grant_type": "client_credentials",
26-
'client_id': self.client_id,
27-
'client_secret': self.client_secret,
28-
'resource': 'https://graph.microsoft.com',
29-
'scope': 'https://graph.microsoft.com'
30-
}
20+
if self.get_param('data.dataType') == 'mail':
21+
try:
22+
self.user = self.get_param('data.data', None, 'No UPN supplied to revoke credentials for')
23+
if not self.user:
24+
self.error("No user supplied")
25+
base_resource = "https://graph.microsoft.com"
3126

27+
token_data = {
28+
"grant_type": "client_credentials",
29+
'client_id': self.client_id,
30+
'client_secret': self.client_secret,
31+
'resource': 'https://graph.microsoft.com',
32+
'scope': 'https://graph.microsoft.com'
33+
}
3234

33-
#Authenticate to the graph api
3435

35-
token_r = requests.post(self.redirect_uri, data=token_data)
36-
token = token_r.json().get('access_token')
36+
#Authenticate to the graph api
3737

38-
if token_r.status_code != 200:
39-
self.error('Failure to obtain azure access token: {}'.format(token_r.content))
38+
redirect_uri = "https://login.microsoftonline.com/{}/oauth2/token".format(self.tenant_id)
39+
token_r = requests.post(redirect_uri, data=token_data)
40+
token = token_r.json().get('access_token')
4041

41-
# Set headers for future requests
42-
headers = {
43-
'Authorization': 'Bearer {}'.format(token)
44-
}
42+
if token_r.status_code != 200:
43+
self.error('Failure to obtain azure access token: {}'.format(token_r.content))
4544

46-
base_url = 'https://graph.microsoft.com/v1.0/'
47-
48-
r = requests.post(base_url + 'users/{}/revokeSignInSessions'.format(self.user), headers=headers)
45+
# Set headers for future requests
46+
headers = {
47+
'Authorization': 'Bearer {}'.format(token)
48+
}
49+
50+
base_url = 'https://graph.microsoft.com/v1.0/'
51+
52+
r = requests.post(base_url + 'users/{}/revokeSignInSessions'.format(self.user), headers=headers)
4953

50-
if r.status_code != 200:
51-
self.error('Failure to revoke access tokens of user {}: {}'.format(self.user, r.content))
54+
if r.status_code != 200:
55+
self.error('Failure to revoke access tokens of user {}: {}'.format(self.user, r.content))
56+
57+
else:
58+
#record time of successful auth token revokation
59+
self.time = datetime.datetime.utcnow()
5260

53-
else:
54-
#record time of successful auth token revokation
55-
self.time = datetime.datetime.utcnow()
56-
57-
except Exception as ex:
58-
self.error(traceback.format_exc())
59-
# Build report to return to Cortex
60-
full_report = {"message": "User {} authentication tokens successfully revoked at {}".format(self.user, self.time)}
61-
self.report(full_report)
61+
except Exception as ex:
62+
self.error(traceback.format_exc())
63+
# Build report to return to Cortex
64+
full_report = {"message": "User {} authentication tokens successfully revoked at {}".format(self.user, self.time)}
65+
self.report(full_report)
66+
else:
67+
self.error('Incorrect dataType. "mail" expected.')
6268

6369

6470
if __name__ == '__main__':
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
## Azure Sign In Token Revoker Responder
2+
3+
This responder allows you to revoke the session tokens for an Azure AD user. Requires the UPN of the account in question, which should be entered as a "mail" oberservable in TheHive.
4+
5+
### Config
6+
7+
To enable the responder, you need three values:
8+
1. Azure Tenant ID
9+
2. Application ID
10+
3. Application Secret
11+
12+
The first two values can be found at any time in the application's Overview page in the Azure portal. The secret must be generated and then stored in a safe place, as it is only fully visible when you first make it.
13+
14+
## Setup
15+
16+
### Prereqs
17+
User account with the Cloud Application Administrator role.
18+
User account with the Global Administrator Role (most of the steps can be done with only the Cloud App Administrator role, but the final authorization for its API permissions requires GA).
19+
20+
### Steps
21+
22+
#### Creation
23+
1. Navigate to the [Azure Portal](https://portal.azure.com) and sign in with the relevant administrator account.
24+
2. Navigate to App Registrations, and create a new registration.
25+
3. Provide a display name (this can be anything, and can be changed later). Click Register.
26+
27+
#### Secret
28+
4. Navigate to Certificates and Secrets.
29+
5. Create a new client secret. Enter a relevant description and set a security-conscious expiration date.
30+
6. Copy the Value. **This will only be fully visible for a short time, so you should immediately copy it and store it in a safe place**.
31+
32+
#### API Permissions
33+
7. Navigate to API permissions.
34+
8. Add the Directory.ReadWrite.All and User.ReadWrite.All permissions (Microsoft Graph API, application permissions).
35+
9. Using a GA account, select the "Grant admin consent for *TENANTNAME*" button.
36+
37+
10. Place the relevant values into the config within Cortex.

0 commit comments

Comments
 (0)