Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #4
0
    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)
Beispiel #5
0
    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)