def findAffectedUsers(appInstanceId): """ Finds 'affected users': when subdomain part of UPN and linked domain are different. """ api = openapi.OpenAPI() aps_api = apsapi.API(getApsApiUrl()) appInstanceToken = getAppInstanceToken(appInstanceId, api) instanceUsersCount = countInstanceResources(appInstanceId, O365_APS_TYPE_USER) affectedUsers = [] path = "aps/2/resources/?implementing(%s)" \ ",and(eq(aps.status,aps:ready)" \ ",select(aps.id,login,domain.domain_name,tenant.aps.id)" \ ",sort(+aps.id)" \ ",limit(0,%d))" \ % (O365_APS_TYPE_USER, instanceUsersCount) allInstanceUsers = aps_api.GET(path, appInstanceToken) for user in allInstanceUsers: # VBE: strange condition user['domain']['domain_name']!=0 ----- a glupost of mine, it should be len(user['domain']['domain_name'])!=0 if (user['domain']['domain_name'].lower() in user['login'].lower() and len(user['login']) != 0 and user['domain']['domain_name'] != 0): # It is not necessary to log users which are OK ------ there was an idea to show good\bad users ratio. log( "Processing user " + user['login'] + ". He is OK: linked domain matches login.", logging.INFO, True) else: log( "Processing user " + user['login'] + ". He is NOT OK: linked to domain with name: " + user['domain']['domain_name'], logging.INFO, True) affectedUsers.append(user) return affectedUsers
def fixIncorrectDomainLink(userUIDToFix, correctDomainUIDToLink, appInstanceId): """ Links an Office365/User resource to a given Office365/Domain. """ api = openapi.OpenAPI() aps_api = apsapi.API(getApsApiUrl()) appInstanceToken = getAppInstanceToken(appInstanceId, api) path = "aps/2/resources/%s/domain/" % userUIDToFix body = { "aps": { "id": correctDomainUIDToLink }, } try: aps_api.POST(path, appInstanceToken, body) except Exception as ex: # VBE: it would be useful to log the error as well ------ yes, I need to add smthg like log(str(ex),logging.INFO, True) log("Failed to update domain link of user: " + userUIDToFix, logging.INFO, True)
def createOffice365DomainResource(appInstanceId, domainName, coreDomainUID, tenantAPSUID): """ Creates new Office365/Domain resource in scope of certain OA subscription. Core domain UID should be specified to link with. """ api = openapi.OpenAPI() aps_api = apsapi.API(getApsApiUrl()) appInstanceToken = getAppInstanceToken(appInstanceId, api) # VBE: Unfortunately it doesn't work -------- it does work in terms of poaupdater module: helps to add additioanl request headers. Yes, it doesn't work in scope of this task ( appInstanceToken[ "APS-Resource-ID"] = tenantAPSUID # <-- add additional header with Office365/Tenant APS resource UID. Need for proper linking. path2 = "aps/2/applications/" allApplications = aps_api.GET( path2, appInstanceToken ) # <-- try to find Application UID by package name. RQL doesn't work on /applications/ node. for application in allApplications: if application.aps.package.name == 'Office 365': applicationUID = str(application.aps.id) # VBE: break -------- a glupost of mine, forgot to add it # VBE: Need to validate the value of applicationUID path = "aps/2/applications/%s/office365domains/" % applicationUID # VBE: the body should be constructed from using the existing domain resource (including service_name, dns_records etc.) body = { "aps": { "type": O365_APS_TYPE_DOMAIN }, "domain_name": domainName, "cloud_status": "Ready", "service_name": "rapidAuth,mobileDevice", "domain": { "aps": { "id": coreDomainUID } } } try: aps_api.POST(path, appInstanceToken, body) except Exception as ex: log("Failed to create new domain with name: " + domainName, logging.INFO, True)
def main(): parser = OptionParser( version=VERSION, usage= "\nFind users whose UPN differs from domain name they are linked with. Fix by linking them to a correct domain in scope of the same subscription.\n\n Usage: %prog --app-instance-id ID [--dry-run]" ) parser.add_option("--app-instance-id", dest="app_instance_id", type="int", help="Office 365 APS 2.0 Application Instance ID") parser.add_option( "--mode", dest="mode", type="string", default=None, help= "Script mode. Possible values: \n fixByDomainName - fix User <-> Domain links when login subdomain part does not match linked domain name; \n fixByTenantUID - fix User <-> Domain links when user and his domain are linked to different Tenant resources;" ) parser.add_option( "--dry-run", dest="dry_run", action="store_true", help="Dry-run mode: count affected users and create a report only") (options, args) = parser.parse_args() if not options.app_instance_id: parser.print_help() raise Exception( "The required parameter 'app-instance-id' is not specified.") elif not options.mode: parser.print_help() raise Exception("Required parameter 'mode' is not specified.") else: # init globals date_for_file_name = time.strftime("%Y%m%d-%H%M%S") logfile_name = "./fixUserAndDomains_" + date_for_file_name + "_O365_instance_" + str( options.app_instance_id) + ".log" format_str = "%(asctime)s %(levelname)s %(message)s" logging.basicConfig(filename=logfile_name, level=logging.DEBUG, format=format_str) initEnv() api = openapi.OpenAPI() aps_api = apsapi.API(getApsApiUrl()) appInstanceToken = getAppInstanceToken(options.app_instance_id, api) dtStart = datetime.datetime.now() instanceUsersCount = countInstanceResources( api, aps_api, appInstanceToken, options.app_instance_id, O365_APS_TYPE_USER ) # <-- count instance users, using the response headers print "Instance users total: ", instanceUsersCount # If we need to fix users by Office365/Tenant APS resource consistence: if options.mode == 'fixByTenantUID': affectedUsers = findAffectedUsersWrongDomainTenant( api, aps_api, appInstanceToken, options.app_instance_id) print affectedUsers # allDomainMap1 = findAffectedUsersWrongDomainTenant(api, aps_api, appInstanceToken, options.app_instance_id) # print allDomainMap1 #findAffectedUsersWrongDomainTenant(api, aps_api, appInstanceToken, options.app_instance_id) # print affectedUsersMap1 if options.mode == 'fixByDomainName' and (instanceUsersCount >= 0): affectedUsers = findAffectedUsers( options.app_instance_id ) #<-- find all affected users, where UPN does not match domain linked
def main(): parser = OptionParser( version=VERSION, usage= "\nFind users whose UPN differs from domain name they are linked with. Fix by linking them to a correct domain in scope of the same subscription.\n\n Usage: %prog --app-instance-id ID [--dry-run]" ) parser.add_option("--app-instance-id", dest="app_instance_id", type="int", help="Office 365 APS 2.0 Application Instance ID") #parser.add_option("--mode", dest="mode", type="string", default=None, # help="Script mode. Possible values: \n fixByDomainName - fix User <-> Domain links when login subdomain part does not match linked domain name; \n fixByTenantUID - fix User <-> Domain links when user and his domain are linked to different Tenant resources;") parser.add_option( "--dry-run", dest="dry_run", action="store_true", help="Dry-run mode: count affected users and create a report only") (options, args) = parser.parse_args() if not options.app_instance_id: parser.print_help() raise Exception( "The required parameter 'app-instance-id' is not specified.") else: # init globals date_for_file_name = time.strftime("%Y%m%d-%H%M%S") logfile_name = "./fixUserDomainLinks_" + date_for_file_name + "_O365_instance_" + str( options.app_instance_id) + ".log" format_str = "%(asctime)s %(levelname)s %(message)s" logging.basicConfig(filename=logfile_name, level=logging.DEBUG, format=format_str) initEnv() api = openapi.OpenAPI() aps_api = apsapi.API(getApsApiUrl()) appInstanceToken = getAppInstanceToken(options.app_instance_id, api) dtStart = datetime.datetime.now() instanceUsersCount = countInstanceResources( api, aps_api, appInstanceToken, options.app_instance_id, O365_APS_TYPE_USER ) # <-- count instance users, using the response headers log( " --- Processing application instance " + str(options.app_instance_id) + "---\n", logging.INFO, True) affectedUsers = findAllAffectedUsers(api, aps_api, appInstanceToken, options.app_instance_id) log(" \n", logging.INFO, True) log( " --- SUMMARY about application instance " + str(options.app_instance_id) + "---\n", logging.INFO, True) log(" Total instance users: " + str(instanceUsersCount), logging.INFO, True) log(" Total affected users: " + str(len(affectedUsers)), logging.INFO, True) log(" \n", logging.INFO, True) log( " Affected users are (User APS UID \ Correct Domain APS UID, if any): ", logging.INFO, True) for user in affectedUsers.items(): log(user, logging.INFO, True) log(" \n", logging.INFO, True) if not options.dry_run: # <----- dry_run option log(" --- Fixing affected users. ", logging.INFO, True) for key, value in affectedUsers.items(): if "NO such" not in value: #log("Trying to fix user: "******"Dry-run mode, links were not fixed actually. ", logging.INFO, True) totalExecutionTime = TimeProfiler.convertTimedelta2Milliseconds( datetime.datetime.now() - dtStart) log(" \n", logging.INFO, True) log( " Total execution time: " + str(totalExecutionTime) + " milliseconds.\n", logging.INFO, True)