First commit
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
"""
|
||||
Microsoft Graph Authentication Module
|
||||
|
||||
Handles authentication to Microsoft Graph API for app registration management.
|
||||
"""
|
||||
|
||||
from azure.identity import InteractiveBrowserCredential
|
||||
from msgraph import GraphServiceClient
|
||||
from typing import Optional
|
||||
import config
|
||||
|
||||
|
||||
class GraphAuthenticator:
|
||||
"""Handles Microsoft Graph authentication and client creation."""
|
||||
|
||||
def __init__(self, client_id: str = None):
|
||||
"""
|
||||
Initialize the Graph authenticator.
|
||||
|
||||
Args:
|
||||
client_id: Application Client ID (defaults to config.CLIENT_ID)
|
||||
"""
|
||||
self.client_id = client_id or config.CLIENT_ID
|
||||
self.credential: Optional[InteractiveBrowserCredential] = None
|
||||
self.client: Optional[GraphServiceClient] = None
|
||||
|
||||
async def authenticate(self) -> bool:
|
||||
"""
|
||||
Authenticate to Microsoft Graph using interactive browser login.
|
||||
|
||||
Returns:
|
||||
bool: True if authentication succeeded, False otherwise
|
||||
|
||||
Raises:
|
||||
Exception: If authentication fails
|
||||
"""
|
||||
try:
|
||||
# Create interactive browser credential
|
||||
# Using "organizations" allows login with any organizational account
|
||||
# additionally_allowed_tenants="*" allows acquiring tokens for any tenant (needed for Key Vault access)
|
||||
self.credential = InteractiveBrowserCredential(
|
||||
tenant_id="organizations",
|
||||
client_id=self.client_id,
|
||||
additionally_allowed_tenants=["*"]
|
||||
)
|
||||
|
||||
# Define scopes for Microsoft Graph
|
||||
scopes = ['https://graph.microsoft.com/.default']
|
||||
|
||||
# Create Graph service client
|
||||
self.client = GraphServiceClient(
|
||||
credentials=self.credential,
|
||||
scopes=scopes
|
||||
)
|
||||
|
||||
# Authenticate to Graph API FIRST
|
||||
# This triggers the initial browser auth for Graph scope
|
||||
# Then Management API will use SSO (single sign-on) from this auth
|
||||
me = await self.client.me.get()
|
||||
|
||||
if me:
|
||||
print(f"Successfully authenticated as: {me.display_name} ({me.user_principal_name})")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"Graph authentication failed: {str(e)}")
|
||||
|
||||
def get_client(self) -> GraphServiceClient:
|
||||
"""
|
||||
Get the authenticated Graph service client.
|
||||
|
||||
Returns:
|
||||
GraphServiceClient: The authenticated client
|
||||
|
||||
Raises:
|
||||
Exception: If not authenticated
|
||||
"""
|
||||
if not self.client:
|
||||
raise Exception("Not authenticated. Call authenticate() first.")
|
||||
return self.client
|
||||
|
||||
def get_credential(self) -> InteractiveBrowserCredential:
|
||||
"""
|
||||
Get the credential object for reuse in other Azure services.
|
||||
|
||||
Returns:
|
||||
InteractiveBrowserCredential: The credential object
|
||||
|
||||
Raises:
|
||||
Exception: If not authenticated
|
||||
"""
|
||||
if not self.credential:
|
||||
raise Exception("Not authenticated. Call authenticate() first.")
|
||||
return self.credential
|
||||
|
||||
def is_authenticated(self) -> bool:
|
||||
"""
|
||||
Check if currently authenticated.
|
||||
|
||||
Returns:
|
||||
bool: True if authenticated, False otherwise
|
||||
"""
|
||||
return self.client is not None and self.credential is not None
|
||||
Reference in New Issue
Block a user