🔍 Code Extractor

class ServicePrincipal

Maturity: 48

Represents an instance of an application in a directory, providing methods to manage service principal credentials, permissions, and role assignments in Azure Active Directory.

File:
/tf/active/vicechatdev/SPFCsync/venv/lib64/python3.11/site-packages/office365/directory/serviceprincipals/service_principal.py
Lines:
28 - 384
Complexity:
complex

Purpose

ServicePrincipal is a core class for managing Azure AD service principals, which are the local representation of an application object in a specific tenant. It provides comprehensive functionality for credential management (keys, passwords, certificates), permission grants/revocations, role assignments, and synchronization. Service principals are used to define what an application can do in a specific tenant, who can access it, and what resources it can access.

Source Code

class ServicePrincipal(DirectoryObject):
    """Represents an instance of an application in a directory."""

    def __str__(self):
        return self.display_name

    def add_key(self, key_credential, password_credential, proof):
        """
        Adds a key credential to a servicePrincipal. This method along with removeKey can be used by a servicePrincipal
        to automate rolling its expiring keys.

        :param KeyCredential key_credential: The new application key credential to add.
            The type, usage and key are required properties for this usage. Supported key types are:
                AsymmetricX509Cert: The usage must be Verify.
                X509CertAndPassword: The usage must be Sign
        :param PasswordCredential password_credential: Only secretText is required to be set which should contain
            the password for the key. This property is required only for keys of type X509CertAndPassword.
            Set it to null otherwise.
        :param str proof: A self-signed JWT token used as a proof of possession of the existing keys
        """
        payload = {
            "keyCredential": key_credential,
            "passwordCredential": password_credential,
            "proof": proof,
        }
        return_type = ClientResult(self.context, KeyCredential())
        qry = ServiceOperationQuery(self, "addKey", None, payload, None, return_type)
        self.context.add_query(qry)
        return return_type

    def add_password(self, display_name=None):
        """Adds a strong password to an application.

        :param str display_name: App display name
        """
        params = PasswordCredential(display_name=display_name)
        return_type = ClientResult(self.context, params)
        qry = ServiceOperationQuery(
            self, "addPassword", None, params, None, return_type
        )
        self.context.add_query(qry)
        return return_type

    def add_token_signing_certificate(self, display_name, end_datetime=None):
        """
        Create a self-signed signing certificate and return a selfSignedCertificate object, which is the public part
        of the generated certificate.

        The self-signed signing certificate is composed of the following objects,
        which are added to the servicePrincipal:

          The keyCredentials object with the following objects:
              A private key object with usage set to Sign.
              A public key object with usage set to Verify.
              The passwordCredentials object.
        All the objects have the same value of customKeyIdentifier.

        The passwordCredential is used to open the PFX file (private key). It and the associated private key object
        have the same value of keyId. When set during creation through the displayName property, the subject of the
        certificate cannot be updated. The startDateTime is set to the same time the certificate is created using
        the action. The endDateTime can be up to three years after the certificate is created.

        :param str display_name: Friendly name for the key. It must start with CN=.
        :param str end_datetime: The date and time when the credential expires. It can be up to 3 years from the date
            the certificate is created. If not supplied, the default is three years from the time of creation.
            The timestamp type represents date and time information using ISO 8601 format and is always in UTC time.
            For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z.
        """
        payload = {"displayName": display_name, "endDateTime": end_datetime}
        return_type = ClientResult(self.context, SelfSignedCertificate())
        qry = ServiceOperationQuery(
            self, "addTokenSigningCertificate", None, payload, None, return_type
        )
        self.context.add_query(qry)
        return return_type

    def grant(self, app, app_role):
        # type: (Application|str, AppRole|str) -> Self
        """
        Revokes an app role assignment to a client service principal
        :param Application or str app: Application object or app identifier
        :param AppRole or str app_role: AppRole object or name
        """

        def _grant(principal):
            # type: ("ServicePrincipal") -> None
            app_role_id = repr(app_role)
            principal_id = principal.id
            self.app_role_assigned_to.add(
                principalId=principal_id, resourceId=self.id, appRoleId=app_role_id
            )

        def _ensure_principal():
            self.context.service_principals.get_by_app(app).get().after_execute(_grant)

        self.ensure_property("id", _ensure_principal)
        return self

    def revoke(self, app, app_role):
        # type: (Application|str, AppRole|str) -> Self
        """Revokes an app role assignment from a client service principal"""

        def _revoke(principal):
            # type ("ServicePrincipal") -> None
            principal_id = principal.id
            app_role_id = repr(app_role)
            app_role_assigned_to_ids = [
                item.id
                for item in self.app_role_assigned_to
                if item.principal_id == principal_id and item.app_role_id == app_role_id
            ]
            if len(app_role_assigned_to_ids) > 0:
                self.app_role_assigned_to[app_role_assigned_to_ids[0]].delete_object()

        def _ensure_resource(principal):
            self.ensure_properties(["id", "appRoleAssignedTo"], _revoke, principal)
            # self.app_role_assigned_to.get_all(page_loaded=_revoke)

        def _ensure_principal():
            self.context.service_principals.get_by_app(app).get().after_execute(
                _ensure_resource
            )

        self.ensure_property("id", _ensure_principal)
        return self

    def remove_password(self, key_id):
        """
        Remove a password from a servicePrincipal object.
        :param str key_id: The unique identifier for the password.
        """
        qry = ServiceOperationQuery(self, "removePassword", None, {"keyId": key_id})
        self.context.add_query(qry)
        return self

    @property
    def account_enabled(self):
        # type: () -> Optional[bool]
        """
        true if the service principal account is enabled; otherwise, false. If set to false, then no users will be
        able to sign in to this app, even if they are assigned to it. Supports $filter (eq, ne, not, in).
        """
        return self.properties.get("accountEnabled", None)

    @property
    def alternative_names(self):
        """
        Used to retrieve service principals by subscription, identify resource group and full resource ids for
        managed identities. Supports $filter (eq, not, ge, le, startsWith).
        """
        return self.properties.get("alternativeNames", StringCollection())

    @property
    def app_description(self):
        # type: () -> Optional[str]
        """
        The description exposed by the associated application.
        """
        return self.properties.get("appDescription", None)

    @property
    def app_display_name(self):
        # type: () -> Optional[str]
        """The display name exposed by the associated application."""
        return self.properties.get("appDisplayName", None)

    @property
    def app_role_assigned_to(self):
        """
        App role assignments for this app or service, granted to users, groups, and other service principals.
        Supports $expand."""
        return self.properties.get(
            "appRoleAssignedTo",
            AppRoleAssignmentCollection(
                self.context, ResourcePath("appRoleAssignedTo", self.resource_path)
            ),
        )

    @property
    def app_roles(self):
        """
        The roles exposed by the application which this service principal represents.
        """
        return self.properties.get("appRoles", AppRoleCollection())

    @property
    def display_name(self):
        # type: () -> Optional[str]
        """The display name."""
        return self.properties.get("displayName", None)

    @property
    def homepage(self):
        # type: () -> Optional[str]
        """Home page or landing page of the application"""
        return self.properties.get("homepage", None)

    @property
    def key_credentials(self):
        """
        The collection of key credentials associated with the service principal. Not nullable.
        Supports $filter (eq, not, ge, le).
        """
        return self.properties.setdefault(
            "keyCredentials", ClientValueCollection(KeyCredential)
        )

    @property
    def login_url(self):
        # type: () -> Optional[str]
        """
        Specifies the URL where the service provider redirects the user to Azure AD to authenticate.
        Azure AD uses the URL to launch the application from Microsoft 365 or the Azure AD My Apps. When blank,
        Azure AD performs IdP-initiated sign-on for applications configured with SAML-based single sign-on.
        The user launches the application from Microsoft 365, the Azure AD My Apps, or the Azure AD SSO URL.
        """
        return self.properties.get("loginUrl", None)

    @property
    def logout_url(self):
        # type: () -> Optional[str]
        """
        Specifies the URL that will be used by Microsoft's authorization service to logout an user using
        OpenId Connect front-channel, back-channel or SAML logout protocols.
        """
        return self.properties.get("logoutUrl", None)

    @property
    def notification_email_addresses(self):
        """
        Specifies the list of email addresses where Azure AD sends a notification when the active certificate is near
        the expiration date. This is only for the certificates used to sign the SAML token issued for Azure
        AD Gallery applications.
        """
        return self.properties.get("notificationEmailAddresses", StringCollection())

    @property
    def service_principal_type(self):
        # type: () -> Optional[str]
        """
        Identifies whether the service principal represents an application, a managed identity, or a legacy application.
        This is set by Azure AD internally. The servicePrincipalType property can be set to three different values:
            Application - A service principal that represents an application or service.
            The appId property identifies the associated app registration, and matches the appId of an application,
            possibly from a different tenant. If the associated app registration is missing, tokens are not issued
            for the service principal.

            ManagedIdentity - A service principal that represents a managed identity. Service principals
            representing managed identities can be granted access and permissions, but cannot be updated
            or modified directly.

            Legacy - A service principal that represents an app created before app registrations,
            or through legacy experiences. Legacy service principal can have credentials, service principal names,
            reply URLs, and other properties which are editable by an authorized user,
            but does not have an associated app registration. The appId value does not associate
            the service principal with an app registration.
            The service principal can only be used in the tenant where it was created.
        """
        return self.properties.get("servicePrincipalType", None)

    @property
    def owners(self):
        """Directory objects that are owners of this servicePrincipal.
        The owners are a set of non-admin users or servicePrincipals who are allowed to modify this object.
        """
        return self.properties.get(
            "owners",
            DirectoryObjectCollection(
                self.context, ResourcePath("owners", self.resource_path)
            ),
        )

    @property
    def oauth2_permission_scopes(self):
        """
        The delegated permissions exposed by the application. For more information see the oauth2PermissionScopes
        property on the application entity's api property.
        """
        return self.properties.get(
            "oauth2PermissionScopes", ClientValueCollection(PermissionScope)
        )

    @property
    def oauth2_permission_grants(self):
        # type: () -> DeltaCollection[OAuth2PermissionGrant]
        """"""
        return self.properties.get(
            "oauth2PermissionGrants",
            DeltaCollection(
                self.context,
                OAuth2PermissionGrant,
                ResourcePath("oauth2PermissionGrants", self.resource_path),
            ),
        )

    @property
    def created_objects(self):
        """Directory objects created by this service principal."""
        return self.properties.get(
            "createdObjects",
            DirectoryObjectCollection(
                self.context, ResourcePath("createdObjects", self.resource_path)
            ),
        )

    @property
    def owned_objects(self):
        """Directory objects that are owned by this service principal."""
        return self.properties.get(
            "ownedObjects",
            DirectoryObjectCollection(
                self.context, ResourcePath("ownedObjects", self.resource_path)
            ),
        )

    @property
    def synchronization(self):
        """
        Represents the capability for Azure Active Directory (Azure AD) identity synchronization through
        the Microsoft Graph API.
        """
        return self.properties.get(
            "synchronization",
            Synchronization(
                self.context, ResourcePath("synchronization", self.resource_path)
            ),
        )

    @property
    def token_encryption_key_id(self):
        # type: () -> Optional[str]
        """
        Specifies the keyId of a public key from the keyCredentials collection. When configured, Azure AD issues tokens
        for this application encrypted using the key specified by this property. The application code that receives
        the encrypted token must use the matching private key to decrypt the token before it can be used
        for the signed-in user.
        """
        return self.properties.get("tokenEncryptionKeyId", None)

    def get_property(self, name, default_value=None):
        if default_value is None:
            property_mapping = {
                "appRoles": self.app_roles,
                "appRoleAssignedTo": self.app_role_assigned_to,
                "created_objects": self.created_objects,
                "keyCredentials": self.key_credentials,
                "oauth2PermissionScopes": self.oauth2_permission_scopes,
                "ownedObjects": self.owned_objects,
                "oauth2PermissionGrants": self.oauth2_permission_grants,
            }
            default_value = property_mapping.get(name, None)
        return super(ServicePrincipal, self).get_property(name, default_value)

    def set_property(self, name, value, persist_changes=True):
        if self._resource_path is None and name == "appId":
            self._resource_path = AppIdPath(value, self.parent_collection.resource_path)
        return super(ServicePrincipal, self).set_property(name, value, persist_changes)

Parameters

Name Type Default Kind
bases DirectoryObject -

Parameter Details

inherits_from_DirectoryObject: This class inherits from DirectoryObject, which provides base functionality for Azure AD directory objects. The constructor parameters are inherited from the parent class and typically include context (API client context) and resource_path (the API endpoint path for this resource).

Return Value

Instantiation returns a ServicePrincipal object that represents an application instance in the directory. Methods return various types: add_key/add_password/add_token_signing_certificate return ClientResult objects containing the created credentials; grant/revoke return Self for method chaining; remove_password returns self; properties return typed values (strings, booleans, collections) representing service principal attributes.

Class Interface

Methods

__str__(self) -> str

Purpose: Returns string representation of the service principal

Returns: The display_name property value

add_key(self, key_credential: KeyCredential, password_credential: PasswordCredential, proof: str) -> ClientResult

Purpose: Adds a key credential to the service principal for automated key rolling

Parameters:

  • key_credential: KeyCredential object with type, usage, and key properties. Supported types: AsymmetricX509Cert (usage: Verify) or X509CertAndPassword (usage: Sign)
  • password_credential: PasswordCredential with secretText for X509CertAndPassword keys, null otherwise
  • proof: Self-signed JWT token proving possession of existing keys

Returns: ClientResult containing the created KeyCredential object

add_password(self, display_name: str = None) -> ClientResult

Purpose: Adds a strong password credential to the application

Parameters:

  • display_name: Optional friendly name for the password credential

Returns: ClientResult containing PasswordCredential with the generated password in secret_text property

add_token_signing_certificate(self, display_name: str, end_datetime: str = None) -> ClientResult

Purpose: Creates a self-signed signing certificate for SAML token signing

Parameters:

  • display_name: Friendly name for the certificate, must start with 'CN='
  • end_datetime: Optional expiration date in ISO 8601 format (UTC), max 3 years from creation, defaults to 3 years

Returns: ClientResult containing SelfSignedCertificate object with public certificate data

grant(self, app: Application | str, app_role: AppRole | str) -> Self

Purpose: Grants an app role assignment to a client service principal

Parameters:

  • app: Application object or application identifier string
  • app_role: AppRole object or role name string

Returns: Self for method chaining

revoke(self, app: Application | str, app_role: AppRole | str) -> Self

Purpose: Revokes an app role assignment from a client service principal

Parameters:

  • app: Application object or application identifier string
  • app_role: AppRole object or role name string

Returns: Self for method chaining

remove_password(self, key_id: str) -> Self

Purpose: Removes a password credential from the service principal

Parameters:

  • key_id: The unique identifier (GUID) of the password credential to remove

Returns: Self for method chaining

get_property(self, name: str, default_value=None) -> Any

Purpose: Retrieves a property value with lazy loading support for complex properties

Parameters:

  • name: Property name to retrieve
  • default_value: Default value if property not found

Returns: Property value or default_value

set_property(self, name: str, value: Any, persist_changes: bool = True) -> Self

Purpose: Sets a property value and optionally persists changes

Parameters:

  • name: Property name to set
  • value: Value to assign
  • persist_changes: Whether to mark property for persistence

Returns: Self for method chaining

Attributes

Name Type Description Scope
account_enabled Optional[bool] Whether the service principal account is enabled. If false, no users can sign in instance
alternative_names StringCollection Used to retrieve service principals by subscription, resource group, and managed identity IDs instance
app_description Optional[str] The description exposed by the associated application instance
app_display_name Optional[str] The display name exposed by the associated application instance
app_role_assigned_to AppRoleAssignmentCollection App role assignments for this service principal, granted to users, groups, and other service principals instance
app_roles AppRoleCollection The roles exposed by the application which this service principal represents instance
display_name Optional[str] The display name of the service principal instance
homepage Optional[str] Home page or landing page URL of the application instance
key_credentials ClientValueCollection[KeyCredential] Collection of key credentials (certificates) associated with the service principal instance
login_url Optional[str] URL where the service provider redirects users to Azure AD for authentication instance
logout_url Optional[str] URL used by Microsoft's authorization service for logout operations instance
notification_email_addresses StringCollection Email addresses for certificate expiration notifications instance
service_principal_type Optional[str] Type of service principal: Application, ManagedIdentity, or Legacy instance
owners DirectoryObjectCollection Directory objects that are owners of this service principal instance
oauth2_permission_scopes ClientValueCollection[PermissionScope] Delegated permissions exposed by the application instance
oauth2_permission_grants DeltaCollection[OAuth2PermissionGrant] OAuth2 permission grants for this service principal instance
created_objects DirectoryObjectCollection Directory objects created by this service principal instance
owned_objects DirectoryObjectCollection Directory objects owned by this service principal instance
synchronization Synchronization Azure AD identity synchronization capability through Microsoft Graph API instance
token_encryption_key_id Optional[str] KeyId of public key used for token encryption instance

Dependencies

  • office365
  • typing
  • typing_extensions

Required Imports

from office365.directory.serviceprincipal import ServicePrincipal
from office365.directory.key_credential import KeyCredential
from office365.directory.password_credential import PasswordCredential
from office365.directory.certificates.self_signed import SelfSignedCertificate
from office365.directory.applications.application import Application
from office365.directory.applications.roles.role import AppRole

Usage Example

from office365.graph_client import GraphClient
from office365.directory.password_credential import PasswordCredential

# Initialize Graph client with credentials
client = GraphClient(credentials)

# Get a service principal by app ID
sp = client.service_principals.get_by_app('app-id-here').get().execute_query()

# Add a password credential
result = sp.add_password(display_name='MyAppPassword').execute_query()
password = result.value.secret_text

# Grant app role to another service principal
sp.grant(app='target-app-id', app_role='role-name').execute_query()

# Add token signing certificate
cert_result = sp.add_token_signing_certificate(
    display_name='CN=MyCert',
    end_datetime='2026-01-01T00:00:00Z'
).execute_query()

# Access properties
print(f'Display Name: {sp.display_name}')
print(f'Enabled: {sp.account_enabled}')
print(f'App Roles: {sp.app_roles}')

# Revoke app role
sp.revoke(app='target-app-id', app_role='role-name').execute_query()

Best Practices

  • Always call execute_query() after operations to commit changes to Azure AD
  • Use ensure_property() or ensure_properties() before accessing properties that may not be loaded
  • Store password credentials securely immediately after creation as they cannot be retrieved later
  • When using grant/revoke methods, ensure the service principal has necessary permissions
  • Use method chaining for multiple operations, but remember to call execute_query() at the end
  • For certificate operations, ensure display_name starts with 'CN=' prefix
  • When adding keys, provide appropriate proof JWT token for security validation
  • Check account_enabled property before attempting authentication operations
  • Use app_role_assigned_to collection to manage role assignments programmatically
  • Handle asynchronous operations properly using after_execute callbacks for dependent operations

Similar Components

AI-powered semantic similarity - components with related functionality:

  • class ApplicationServicePrincipal 83.6% similar

    Represents the concatenation of an Azure AD application and servicePrincipal object created when an application instance is added from the Azure AD application gallery.

    From: /tf/active/vicechatdev/SPFCsync/venv/lib64/python3.11/site-packages/office365/directory/applications/service_principal.py
  • class ProvisioningServicePrincipal 77.5% similar

    A class representing a service principal identity used for provisioning operations in Microsoft Office 365 directory services.

    From: /tf/active/vicechatdev/SPFCsync/venv/lib64/python3.11/site-packages/office365/directory/audit/provisioning/service_principal.py
  • class ServicePrincipalCollection 76.5% similar

    A collection class for managing Microsoft Graph Service Principal objects, providing methods to add, retrieve, and query service principals by various identifiers.

    From: /tf/active/vicechatdev/SPFCsync/venv/lib64/python3.11/site-packages/office365/directory/serviceprincipals/collection.py
  • class SPOWebAppServicePrincipal 68.5% similar

    Represents a SharePoint Online Web Application Service Principal for managing SPFx (SharePoint Framework) client secrets in the tenant administration context.

    From: /tf/active/vicechatdev/SPFCsync/venv/lib64/python3.11/site-packages/office365/sharepoint/tenant/administration/internal/web_appservice_principal.py
  • class Application 67.0% similar

    Represents an Azure Active Directory (Azure AD) application registration, providing methods to manage application credentials, certificates, passwords, and publisher verification.

    From: /tf/active/vicechatdev/SPFCsync/venv/lib64/python3.11/site-packages/office365/directory/applications/application.py
← Back to Browse