### RUN pip install -r requirements.txt /Python3

## This script will create a AAD native app from a SP that has permissions for the Graph API. Access will be delegated to the AAD native app and permissions granted. Used by kubectl
## users to authenticate via AAD for RBAC integration with AAD and AKS

## Now we need to create an app, see here https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal
## To automate an app run bash script CreateSP.sh and populate the two variables returned: SERVER_APP_ID and SERVER_SECRET
## Ensure you populate the remainder of the Global Variables

# Ensure you have pressed Grant Permissions in the portal for the SP created in CreateSP.sh

import json
import requests

### Global Variables - Change these

SERVER_APP_NAME='' # Must be populated manually - The name of your Server App
SERVER_APP_ID='' # Must be populated manually - The AppId or ClientId of your server app - generated by CreateSP.sh
SERVER_SECRET='' # Must be populated manually - The password or ClientSecret of your server app - manually set in CreateSP.sh

TENANT_ID='' # Must be populated manually - Your AD tenant id
CLIENT_APP_NAME='' # Must be populated manually - The name of your AAD native app

CLIENT_APP_ID='' # Populated automatically
CLIENT_APP_SPN='' # Populated automatically

TOKEN=''

ssn=''

def getToken():

    # Get Token parameters

    access_token=''

    headers = dict()
    headers['Content-Type'] = 'application/x-www-form-urlencoded'

    payload= {'grant_type': 'client_credentials', 'client_id': SERVER_APP_ID, 'resource': 'https://graph.windows.net', 'client_secret': SERVER_SECRET}

    # Use the requests library to make the POST call
    response = requests.request('post',
                                'https://login.microsoftonline.com/'+TENANT_ID+'/oauth2/token',
                                data=payload)

    if response.status_code != 200 and response.status_code != 201:
        print("Error code: %d" % (response.status_code))
        print("Message: %s" % (response.json()))

    print(response.status_code, response.reason, " Got Token")

    jbody = response.json()

    access_token= jbody['access_token']
    return access_token

def createApp(isNative, AppName):

    app_id = ''

    headers = {
        "Authorization": TOKEN,
        "Content-Type": "application/json"
        }

    if isNative == 'true':

        payload = {
            "odata.type": "Microsoft.DirectoryServices.Application",
            "objectType": "Application",
            "availableToOtherTenants": "false",
            "displayName": AppName,
            "publicClient": isNative,
            "replyUrls": [
                "http://" + AppName + "/"
            ],
            "requiredResourceAccess": [
            {
              "resourceAppId": SERVER_APP_ID, # AppId of serverApp
              "resourceAccess": [
                {
                  "id": SERVER_OAUTH_ID, #id of OAuthPermission
                  "type": "Scope"
                }
              ]
            },
            {
              "resourceAppId": "00000002-0000-0000-c000-000000000000", # AD Graph
              "resourceAccess": [
                {
                  "id": "311a71cc-e848-46a1-bdf8-97ff7156d8e6", # Static role id
                  "type": "Scope"
                }
              ]
            }
          ]
        }

    data_json = json.dumps(payload)

    response = requests.request('post',
                                'https://graph.windows.net/myorganization/applications?api-version=1.6', headers=headers, data=data_json)

    if response.status_code != 200 and response.status_code != 201:
        print("Error code: %d" % (response.status_code))
        print("Message: %s" % (response.json()))

    print(response.status_code, response.reason, ' Created Application ', CLIENT_APP_NAME)

    jbody = response.json()

    app_id = jbody['appId']

    return app_id

def createSPN(clientId):

    spn = ''

    headers = {
        "Authorization": TOKEN,
        "Content-Type": "application/json"
    }

    payload = {
        "odata.type": "Microsoft.DirectoryServices.ServicePrincipal",
        "objectType": "ServicePrincipal",
        "appId": clientId,
        "displayName": CLIENT_APP_NAME,
        "servicePrincipalNames": [
            clientId
        ],
        "servicePrincipalType": "Application",
        "tags": [
            "WindowsAzureActiveDirectoryIntegratedApp"
        ]

    }

    data_json = json.dumps(payload)
    # Use the requests library to make the POST call
    response = requests.request('post',
                                'https://graph.windows.net/myorganization/servicePrincipals?api-version=1.6',
                                headers=headers, data=data_json)

    if response.status_code != 200 and response.status_code != 201:
        print("Error code: %d" % (response.status_code))
        print("Message: %s" % (response.json()))

    print(response.status_code, response.reason, 'Created Service Principal')

    jbody = response.json()

    spn = jbody['objectId']

    return spn

def grantOAuth2Permissions():

    headers = {
        "Authorization": TOKEN,
        "Content-Type": "application/json"
    }

    appids = ['00000002-0000-0000-c000-000000000000', SERVER_APP_ID]

    for _, val in enumerate(appids):
        # Get the SPN ObjectId

        # Use the requests library to make the POST call
        response = requests.request('get',
                                    'https://graph.windows.net/myorganization/servicePrincipals?api-version=1.6&$filter=appId+eq' + "'" + val + "'",
                                    headers=headers)

        if response.status_code != 200 and response.status_code != 201:
            print("Error code: %d" % (response.status_code))
            print("Message: %s" % (response.json()))

        print(response.status_code, response.reason, ' Queried Service Principals')

        jbody = response.json()
        spn = jbody['value'][0]['objectId']

# Now we grant the permissions

        if val == '00000002-0000-0000-c000-000000000000': # This is AD Read
            scope = 'User.Read'
        else:
            scope = "user_impersonation"

        payload = {
        "odata.type": "Microsoft.DirectoryServices.OAuth2PermissionGrant",
        "clientId": CLIENT_APP_SPN,
        "consentType": "AllPrincipals",
        #"principalId": "",
        "resourceId": spn,
        "scope": scope,
        "startTime": "0001-01-01T00:00:00",
        "expiryTime": "9000-01-01T00:00:00"
        }

        data_json = json.dumps(payload)

        response = requests.request('post',
                                    'https://graph.windows.net/myorganization/oauth2PermissionGrants?api-version=1.6',
                                    headers=headers, data=data_json)

        if response.status_code != 200 and response.status_code != 201:
            print("Error code: %d" % (response.status_code))
            print("Message: %s" % (response.json()))

        print(response.status_code, response.reason, ' Granted permissions ')

def getServerOAuthID(appId):

    oauthId = ''

    headers = {
        "Authorization": TOKEN,
        "Content-Type": "application/json"
    }

    # Use the requests library to make the POST call
    response = requests.request('get',
                                'https://graph.windows.net/myorganization/servicePrincipals?api-version=1.6&$filter=appId+eq' + "'" + appId + "'",
                                headers=headers)

    if response.status_code != 200 and response.status_code != 201:
        print("Error code: %d" % (response.status_code))
        print("Message: %s" % (response.json()))

    print(response.status_code, response.reason, ' Queried Service Principals')

    jbody = response.json()
    oauthId = jbody['value'][0]['oauth2Permissions'][0]['id']

    return oauthId

# Let's go and get a token
TOKEN = 'Bearer ' + getToken()

# We now need to get the OAuth2 Permissions for the Server App
SERVER_OAUTH_ID = getServerOAuthID(SERVER_APP_ID)

# Let's go and create a native app
CLIENT_APP_ID = createApp('true', CLIENT_APP_NAME)

# Now we need to create a Service Principal for the native app
CLIENT_APP_SPN = createSPN(CLIENT_APP_ID)

# Now we need to get the Service Principal ObjectIds so that we can grant OAuth2 permissions
grantOAuth2Permissions()
print("All Done")

### Tests

#if __name__ == '__main__':

