def create_application(client, display_name, homepage, years, password, identifier_uris, available_to_other_tenants=False, reply_urls=None): password_credential = _build_password_credential(password, years) app_create_param = ApplicationCreateParameters( available_to_other_tenants=available_to_other_tenants, display_name=display_name, identifier_uris=identifier_uris, homepage=homepage, reply_urls=reply_urls, password_credentials=[password_credential]) try: return client.create(app_create_param) except GraphErrorException as ex: if 'insufficient privileges' in str(ex).lower(): link = ( 'https://docs.microsoft.com/en-us/azure/azure-resource-manager/' + 'resource-group-create-service-principal-portal') raise CLIError( "Directory permission is needed for the current user to register the application. " "For how to configure, please refer '{}'. Original error: {}". format(link, ex)) raise
def create_application(self, display_name): password = uuid.uuid4() start_date = datetime.datetime.utcnow() end_date = datetime.datetime(2299, 12, 31, tzinfo=datetime.timezone.utc) app = self.client.applications.create( ApplicationCreateParameters( display_name=display_name, identifier_uris=[ self.MANAGED_APP_PREFIX + str(uuid.uuid4()), ], password_credentials=[ PasswordCredential( custom_key_identifier=str(start_date).encode(), start_date=start_date, end_date=end_date, value=password, ), ], )) return app, password
def create_application(self, display_name): password = uuid.uuid4() try: end_date = datetime.datetime(2299, 12, 31, tzinfo=datetime.timezone.utc) except AttributeError: end_date = datetime.datetime(2299, 12, 31) app = self.client.applications.create( ApplicationCreateParameters( display_name=display_name, identifier_uris=[ self.MANAGED_APP_PREFIX + str(uuid.uuid4()), ], password_credentials=[ PasswordCredential( end_date=end_date, value=password, ), ], )) return app, password
def create_application( client, display_name, homepage, identifier_uris, # pylint: disable=too-many-arguments available_to_other_tenants=False, password=None, reply_urls=None, key_value=None, key_type=None, key_usage=None, start_date=None, end_date=None): password_creds, key_creds = _build_application_creds( password, key_value, key_type, key_usage, start_date, end_date) app_create_param = ApplicationCreateParameters( available_to_other_tenants, display_name, identifier_uris, homepage=homepage, reply_urls=reply_urls, key_credentials=key_creds, password_credentials=password_creds) return client.create(app_create_param)
def create_application(client, display_name, homepage, identifier_uris, available_to_other_tenants=False, password=None, reply_urls=None, key_value=None, key_type=None, key_usage=None, start_date=None, end_date=None): password_creds, key_creds = _build_application_creds( password, key_value, key_type, key_usage, start_date, end_date) app_create_param = ApplicationCreateParameters( available_to_other_tenants, display_name, identifier_uris, homepage=homepage, reply_urls=reply_urls, key_credentials=key_creds, password_credentials=password_creds) try: return client.create(app_create_param) except GraphErrorException as ex: if 'insufficient privileges' in str(ex).lower(): link = 'https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal' # pylint: disable=line-too-long raise CLIError( "Directory permission is needed for the current user to register the application. " "For how to configure, please refer '{}'. Original error: {}". format(link, ex)) raise
def create_service_principal(name=None, secret=None, years=1): '''create a service principal you can use with login command :param str name: an unique uri. If missing, the command will generate one. :param str secret: the secret used to login. If missing, command will generate one. :param str years: Years the secret will be valid. ''' start_date = datetime.datetime.now() app_display_name = 'azure-cli-' + start_date.strftime('%Y-%m-%d-%H-%M-%S') if name is None: name = 'http://' + app_display_name key_id = str(uuid.uuid4()) end_date = start_date + relativedelta(years=years) secret = secret or str(uuid.uuid4()) app_cred = PasswordCredential(start_date, end_date, key_id, secret) app_create_param = ApplicationCreateParameters( False, app_display_name, 'http://' + app_display_name, [name], password_credentials=[app_cred]) profile = Profile() cred, _, tenant = profile.get_login_credentials(for_graph_client=True) client = GraphRbacManagementClient(cred, tenant) #pylint: disable=no-member aad_application = client.applications.create(app_create_param) aad_sp = client.service_principals.create(aad_application.app_id, True) _build_output_content(name, aad_sp.object_id, secret, tenant)
def create_application_registration(onefuzz_instance_name: str, name: str, approle: OnefuzzAppRole) -> Application: """ Create an application registration """ client = get_client_from_cli_profile(GraphRbacManagementClient) apps: List[Application] = list( client.applications.list(filter="displayName eq '%s'" % onefuzz_instance_name)) app = apps[0] resource_access = [ ResourceAccess(id=role.id, type="Role") for role in app.app_roles if role.value == approle.value ] params = ApplicationCreateParameters( is_device_only_auth_supported=True, display_name=name, identifier_uris=[], password_credentials=[], required_resource_access=([ RequiredResourceAccess( resource_access=resource_access, resource_app_id=app.app_id, ) ] if len(resource_access) > 0 else []), ) registered_app: Application = client.applications.create(params) atttempts = 5 while True: if atttempts < 0: raise Exception( "Unable to create application registration, Please try again") atttempts = atttempts - 1 try: time.sleep(5) query_microsoft_graph( method="PATCH", resource="applications/%s" % registered_app.object_id, body={ "publicClient": { "redirectUris": [ "https://%s.azurewebsites.net" % onefuzz_instance_name ] }, "isFallbackPublicClient": True, }, ) break except GraphQueryError as err: if err.status_code == 404: continue authorize_application(UUID(registered_app.app_id), UUID(app.app_id)) return registered_app
def create_application_registration( onefuzz_instance_name: str, name: str, approle: OnefuzzAppRole ) -> Application: """ Create an application registration """ client = get_graph_client() apps: List[Application] = list( client.applications.list(filter="displayName eq '%s'" % onefuzz_instance_name) ) app = apps[0] resource_access = [ ResourceAccess(id=role.id, type="Role") for role in app.app_roles if role.value == approle.value ] params = ApplicationCreateParameters( is_device_only_auth_supported=True, display_name=name, identifier_uris=[], password_credentials=[], required_resource_access=( [ RequiredResourceAccess( resource_access=resource_access, resource_app_id=app.app_id, ) ] if len(resource_access) > 0 else [] ), ) registered_app: Application = client.applications.create(params) atttempts = 5 while True: if atttempts < 0: raise Exception( "Unable to create application registration, Please try again" ) atttempts = atttempts - 1 try: time.sleep(5) client = get_graph_client() update_param = ApplicationUpdateParameters( reply_urls=["https://%s.azurewebsites.net" % onefuzz_instance_name] ) client.applications.patch(registered_app.object_id, update_param) break except Exception: continue authorize_application(UUID(registered_app.app_id), UUID(app.app_id)) return registered_app
def create_application_registration( onefuzz_instance_name: str, name: str ) -> Application: """ Create an application registration """ client = get_client_from_cli_profile(GraphRbacManagementClient) apps: List[Application] = list( client.applications.list(filter="displayName eq '%s'" % onefuzz_instance_name) ) app = apps[0] resource_access = [ ResourceAccess(id=role.id, type="Role") for role in app.app_roles ] params = ApplicationCreateParameters( is_device_only_auth_supported=True, display_name=name, identifier_uris=[], password_credentials=[], required_resource_access=( [ RequiredResourceAccess( resource_access=resource_access, resource_app_id=app.app_id, ) ] if len(resource_access) > 0 else [] ), ) registered_app: Application = client.applications.create(params) body = { "publicClient": { "redirectUris": ["https://%s.azurewebsites.net" % onefuzz_instance_name] }, "isFallbackPublicClient": True, } az_cli( [ "rest", "-m", "PATCH", "-u", "https://graph.microsoft.com/v1.0/applications/%s" % registered_app.object_id, "--headers", "Content-Type=application/json", "-b", json.dumps(body), ] ) authorize_application(UUID(registered_app.app_id), UUID(app.app_id)) return registered_app
def create_aad_user(credentials, tenant_id, **kwargs): """ Create an AAD application and service principal :param credentials: msrestazure.azure_active_directory.AdalAuthentication :param tenant_id: str :param **application_name: str """ graph_rbac_client = GraphRbacManagementClient( credentials, tenant_id, base_url=AZURE_PUBLIC_CLOUD.endpoints.active_directory_graph_resource_id) application_credential = uuid.uuid4() try: display_name = kwargs.get("application_name", DefaultSettings.application_name) application = graph_rbac_client.applications.create( parameters=ApplicationCreateParameters( available_to_other_tenants=False, identifier_uris=["http://{}.com".format(display_name)], display_name=display_name, password_credentials=[ PasswordCredential( start_date=datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=timezone.utc), end_date=datetime(2299, 12, 31, 0, 0, 0, 0, tzinfo=timezone.utc), value=application_credential, key_id=uuid.uuid4()) ])) service_principal = graph_rbac_client.service_principals.create( ServicePrincipalCreateParameters(app_id=application.app_id, account_enabled=True)) except GraphErrorException as e: if e.inner_exception.code == "Request_BadRequest": application = next( graph_rbac_client.applications.list( filter="identifierUris/any(c:c eq 'http://{}.com')".format(display_name))) confirmation_prompt = "Previously created application with name {} found. "\ "Would you like to use it? (y/n): ".format(application.display_name) prompt_for_confirmation(confirmation_prompt, e, ValueError("Response not recognized. Please try again.")) password_credentials = list( graph_rbac_client.applications.list_password_credentials(application_object_id=application.object_id)) password_credentials.append( PasswordCredential( start_date=datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=timezone.utc), end_date=datetime(2299, 12, 31, 0, 0, 0, 0, tzinfo=timezone.utc), value=application_credential, key_id=uuid.uuid4())) graph_rbac_client.applications.patch( application_object_id=application.object_id, parameters=ApplicationUpdateParameters(password_credentials=password_credentials)) service_principal = next( graph_rbac_client.service_principals.list(filter="appId eq '{}'".format(application.app_id))) else: raise e return application.app_id, service_principal.object_id, str(application_credential)
def createApp(self, key, appName): passwordCredential = PasswordCredential(start_date=datetime.datetime.now(), end_date="2299-12-31T06:08:04.0863895Z", value=key ) resourceAccess = self.__getResourceAccessJson(); if len(resourceAccess) == 0: raise Exception("No resource accesses found") parameters = ApplicationCreateParameters(available_to_other_tenants=False, display_name=appName, homepage=self.__identifierUrl, identifier_uris=[self.__identifierUrl], required_resource_access=resourceAccess, password_credentials=[passwordCredential]) application = self.getGraphRbacClient().applications.create(parameters) logging.info("Created App with id: " + application.app_id) return application.app_id
def create_application( client, display_name, homepage, identifier_uris, available_to_other_tenants=False, password=None, reply_urls=None, key_value=None, key_type=None, key_usage=None, start_date=None, end_date=None, required_resource_accesses=None, ): password_creds, key_creds = _build_application_creds( password, key_value, key_type, key_usage, start_date, end_date) app_create_param = ApplicationCreateParameters( available_to_other_tenants=available_to_other_tenants, display_name=display_name, identifier_uris=identifier_uris, homepage=homepage, reply_urls=reply_urls, key_credentials=key_creds, password_credentials=password_creds, required_resource_access=required_resource_accesses, ) try: result = client.create(app_create_param, raw=True) return result.output, result.response.headers["ocp-aad-session-key"] except GraphErrorException as ex: if "insufficient privileges" in str(ex).lower(): link = "https://docs.microsoft.com/azure/azure-resource-manager/resource-group-create-service-principal-portal" # pylint: disable=line-too-long raise AzCLIError( "Directory permission is needed for the current user to register the application. " "For how to configure, please refer '{}'. Original error: {}". format(link, ex)) raise
def setup_rbac(self) -> None: """ Setup the client application for the OneFuzz instance. By default, Service Principals do not have access to create client applications in AAD. """ if self.results["client_id"] and self.results["client_secret"]: logger.info("using existing client application") return client = get_client_from_cli_profile( GraphRbacManagementClient, subscription_id=self.get_subscription_id()) logger.info("checking if RBAC already exists") try: existing = list( client.applications.list(filter="displayName eq '%s'" % self.application_name)) except GraphErrorException: logger.error( "unable to query RBAC. Provide client_id and client_secret") sys.exit(1) app_roles = [ AppRole( allowed_member_types=["Application"], display_name=OnefuzzAppRole.CliClient.value, id=str(uuid.uuid4()), is_enabled=True, description="Allows access from the CLI.", value=OnefuzzAppRole.CliClient.value, ), AppRole( allowed_member_types=["Application"], display_name=OnefuzzAppRole.ManagedNode.value, id=str(uuid.uuid4()), is_enabled=True, description="Allow access from a lab machine.", value=OnefuzzAppRole.ManagedNode.value, ), ] app: Optional[Application] = None if not existing: logger.info("creating Application registration") if self.multi_tenant_domain: url = "https://%s/%s" % ( self.multi_tenant_domain, self.application_name, ) else: url = "https://%s.azurewebsites.net" % self.application_name params = ApplicationCreateParameters( display_name=self.application_name, identifier_uris=[url], reply_urls=[url + "/.auth/login/aad/callback"], optional_claims=OptionalClaims(id_token=[], access_token=[]), required_resource_access=[ RequiredResourceAccess( resource_access=[ ResourceAccess(id=USER_IMPERSONATION, type="Scope") ], resource_app_id="00000002-0000-0000-c000-000000000000", ) ], app_roles=app_roles, ) app = client.applications.create(params) logger.info("creating service principal") service_principal_params = ServicePrincipalCreateParameters( account_enabled=True, app_role_assignment_required=False, service_principal_type="Application", app_id=app.app_id, ) def try_sp_create() -> None: error: Optional[Exception] = None for _ in range(10): try: client.service_principals.create( service_principal_params) return except GraphErrorException as err: # work around timing issue when creating service principal # https://github.com/Azure/azure-cli/issues/14767 if ("service principal being created must in the local tenant" not in str(err)): raise err logging.warning( "creating service principal failed with an error that occurs " "due to AAD race conditions") time.sleep(60) if error is None: raise Exception("service principal creation failed") else: raise error try_sp_create() else: app = existing[0] existing_role_values = [ app_role.value for app_role in app.app_roles ] has_missing_roles = any( [role.value not in existing_role_values for role in app_roles]) if has_missing_roles: # disabling the existing app role first to allow the update # this is a requirement to update the application roles for role in app.app_roles: role.is_enabled = False client.applications.patch( app.object_id, ApplicationUpdateParameters(app_roles=app.app_roles)) # overriding the list of app roles client.applications.patch( app.object_id, ApplicationUpdateParameters(app_roles=app_roles)) if self.multi_tenant_domain and app.sign_in_audience == "AzureADMyOrg": url = "https://%s/%s" % ( self.multi_tenant_domain, self.application_name, ) client.applications.patch( app.object_id, ApplicationUpdateParameters(identifier_uris=[url])) set_app_audience(app.object_id, "AzureADMultipleOrgs") elif (not self.multi_tenant_domain and app.sign_in_audience == "AzureADMultipleOrgs"): set_app_audience(app.object_id, "AzureADMyOrg") url = "https://%s.azurewebsites.net" % self.application_name client.applications.patch( app.object_id, ApplicationUpdateParameters(identifier_uris=[url])) else: logger.debug("No change to App Registration signInAudence setting") creds = list( client.applications.list_password_credentials(app.object_id)) client.applications.update_password_credentials( app.object_id, creds) (password_id, password) = self.create_password(app.object_id) cli_app = list( client.applications.list(filter="appId eq '%s'" % ONEFUZZ_CLI_APP)) if len(cli_app) == 0: logger.info( "Could not find the default CLI application under the current " "subscription, creating a new one") app_info = register_application( "onefuzz-cli", self.application_name, OnefuzzAppRole.CliClient, self.get_subscription_id(), ) if self.multi_tenant_domain: authority = COMMON_AUTHORITY else: authority = app_info.authority self.cli_config = { "client_id": app_info.client_id, "authority": authority, } else: authorize_application(uuid.UUID(ONEFUZZ_CLI_APP), app.app_id) self.results["client_id"] = app.app_id self.results["client_secret"] = password # Log `client_secret` for consumption by CI. if self.log_service_principal: logger.info("client_id: %s client_secret: %s", app.app_id, password) else: logger.debug("client_id: %s client_secret: %s", app.app_id, password)
def setup_rbac(self): """ Setup the client application for the OneFuzz instance. By default, Service Principals do not have access to create client applications in AAD. """ if self.results["client_id"] and self.results["client_secret"]: logger.info("using existing client application") return client = get_client_from_cli_profile(GraphRbacManagementClient) logger.info("checking if RBAC already exists") try: existing = list( client.applications.list( filter="displayName eq '%s'" % self.application_name ) ) except GraphErrorException: logger.error("unable to query RBAC. Provide client_id and client_secret") sys.exit(1) app_roles = [ AppRole( allowed_member_types=["Application"], display_name="CliClient", id=str(uuid.uuid4()), is_enabled=True, description="Allows access from the CLI.", value="CliClient", ), AppRole( allowed_member_types=["Application"], display_name="ManagedNode", id=str(uuid.uuid4()), is_enabled=True, description="Allow access from a lab machine.", value="ManagedNode", ), ] if not existing: logger.info("creating Application registration") url = "https://%s.azurewebsites.net" % self.application_name params = ApplicationCreateParameters( display_name=self.application_name, identifier_uris=[url], reply_urls=[url + "/.auth/login/aad/callback"], optional_claims=OptionalClaims(id_token=[], access_token=[]), required_resource_access=[ RequiredResourceAccess( resource_access=[ ResourceAccess(id=USER_IMPERSONATION, type="Scope") ], resource_app_id="00000002-0000-0000-c000-000000000000", ) ], app_roles=app_roles, ) app = client.applications.create(params) logger.info("creating service principal") service_principal_params = ServicePrincipalCreateParameters( account_enabled=True, app_role_assignment_required=False, service_principal_type="Application", app_id=app.app_id, ) client.service_principals.create(service_principal_params) else: app: Application = existing[0] existing_role_values = [app_role.value for app_role in app.app_roles] has_missing_roles = any( [role.value not in existing_role_values for role in app_roles] ) if has_missing_roles: # disabling the existing app role first to allow the update # this is a requirement to update the application roles for role in app.app_roles: role.is_enabled = False client.applications.patch( app.object_id, ApplicationUpdateParameters(app_roles=app.app_roles) ) # overriding the list of app roles client.applications.patch( app.object_id, ApplicationUpdateParameters(app_roles=app_roles) ) creds = list(client.applications.list_password_credentials(app.object_id)) client.applications.update_password_credentials(app.object_id, creds) (password_id, password) = self.create_password(app.object_id) onefuzz_cli_app_uuid = uuid.UUID(ONEFUZZ_CLI_APP) cli_app = get_application(onefuzz_cli_app_uuid) if cli_app is None: logger.info( "Could not find the default CLI application under the current " "subscription, creating a new one" ) app_info = register_application("onefuzz-cli", self.application_name) self.cli_config = { "client_id": app_info.client_id, "authority": app_info.authority, } else: authorize_application(onefuzz_cli_app_uuid, app.app_id) self.results["client_id"] = app.app_id self.results["client_secret"] = password # Log `client_secret` for consumption by CI. if self.log_service_principal: logger.info("client_id: %s client_secret: %s", app.app_id, password) else: logger.debug("client_id: %s client_secret: %s", app.app_id, password)