Enhancements: Updates to API Paging Limitations

cc @kenilelk1 @rrivera1109 @RArroyo

I don’t use a public git repo so just gonna post it here for now - don’t see myself updating it much anyway. Also - hope it’s readable and if you have any feedback, feel free to shoot. Not a python expert in any capacity so always happy to improve.

import csv
import re
import requests as r
import json
import os

# Update the below values to match your installation
sp_api_url = "https://<tenant>.api.identitynow.com"
clientid = "" 
secret = ""


# Get a bearer token
def get_sp_api_token():
    body = {
        "grant_type": "client_credentials",
        "client_id": clientid,
        "client_secret": secret
    }
    response = r.post(sp_api_url + "/oauth/token", body)
    if response.ok:
        print("API access token obtained")
        return response.json()['access_token']
    else:
        print(response.json())
        print("Error while obtaining access token")


# get all controlled applications, store name, ID & description
def get_all_apps():
    apps = []
    response = r.get(sp_api_url + "/cc/api/app/list?filter=org", headers=apiCallHeaders)
    if response.ok:
        print("Applications found")
        for item in response.json():
            if item['controlType'] != "PERSONAL":
                print(item['name'])
                apps.append({"appid": item['id'], "appName": item['name'], "appDescription": item['description']})
    else:
        print("Error fetching applications: ")
        print(response)
    return apps


# get all access profiles assigned to each application. Store access profiel name, description and approvalSchemes
def get_app_access_profiles():
    apps = applications
    for app in applications:
        response = r.get(sp_api_url + "/cc/api/app/getAccessProfiles/" + app['appid'], headers=apiCallHeaders2)
        if response.ok:
            if response.json()['count'] != 0:
                print("Found " + str(response.json()['count']) + " access profiles for " + app['appName'])
                accessprofiles = []
                for item in response.json()['items']:
                    accessprofiles.append({"accessprofile": item['name'], "description": item['description'],
                                           "approvals": item['approvalSchemes']})
                app["accessprofiles"] = accessprofiles
            else:
                print("No access profiles assigned to " + app['appName'])
        else:
            print("Error fetching access profiles for " + app['appName'])
            print(response)
    return apps


# get membership of each governance group per access profile - you could optimise this and fetch all governance groups separately and store in a variable to iterate over later. At the moment this fetches all approvers and also updates the apps list
def get_workgroup_membership():
    apps = access_profiles
    for app in apps:
        if "accessprofiles" in app:
            for ap in app['accessprofiles']:
                if ap['approvals'] is not None:
                    if "," in str(ap['approvals']):
                        ap.update({"approvals": ap['approvals'].split(",")})
                        workgroups = []
                        for approver in ap['approvals']:
                            if "workgroup" in approver:
                                members = []
                                workgroup = r.get(sp_api_url + "/v2/workgroups/" + (approver.split(":")[1]).strip(), headers=apiCallHeaders2)
                                membership = r.get(sp_api_url + "/v2/workgroups/" + (approver.split(":")[1]).strip() + "/members", headers=apiCallHeaders2)
                                for member in membership.json():
                                    members.append(member['email'])
                                workgroups.append({workgroup.json()['name']: members})
                            else:
                                workgroups.append(approver)
                        ap['approvals'] = workgroups
                    else:
                        if "workgroup" in ap['approvals']:
                            members = []
                            workgroup = r.get(sp_api_url + "/v2/workgroups/" + (ap['approvals'].split(":")[1]).strip(), headers=apiCallHeaders2)
                            membership = r.get(sp_api_url + "/v2/workgroups/" + (ap['approvals'].split(":")[1]).strip() + "/members", headers=apiCallHeaders2)
                            for member in membership.json():
                                members.append(member['email'])
                            ap['approvals'] = {workgroup.json()['name']: members}
    print("Approval values updated with governance group names and membership")
    appson = apps
    return appson


# save to file
def save_file():
    with open('data.json', 'w') as file:
        json.dump(alldata, file, indent=4)
    return


token = get_sp_api_token()
apiCallHeaders = {'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json'}
apiCallHeaders2 = {'Authorization': 'Bearer ' + token}
applications = get_all_apps()
access_profiles = get_app_access_profiles()
alldata = get_workgroup_membership()
save_file()