156 lines
5.1 KiB
Python
156 lines
5.1 KiB
Python
"""
|
|
Secret Service
|
|
|
|
Handles creation and removal of app registration secrets.
|
|
"""
|
|
|
|
from msgraph import GraphServiceClient
|
|
from msgraph.generated.models.password_credential import PasswordCredential
|
|
from msgraph.generated.applications.item.add_password.add_password_post_request_body import AddPasswordPostRequestBody
|
|
from msgraph.generated.applications.item.remove_password.remove_password_post_request_body import RemovePasswordPostRequestBody
|
|
from datetime import datetime, timedelta
|
|
from typing import Dict, List, Any
|
|
import config
|
|
|
|
|
|
class SecretService:
|
|
"""Service for managing app registration secrets."""
|
|
|
|
def __init__(self, graph_client: GraphServiceClient):
|
|
"""
|
|
Initialize the secret service.
|
|
|
|
Args:
|
|
graph_client: Authenticated Graph service client
|
|
"""
|
|
self.graph_client = graph_client
|
|
|
|
async def create_secret(
|
|
self,
|
|
app_object_id: str,
|
|
description: str,
|
|
years: int = None
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Create a new secret for an app registration.
|
|
|
|
Args:
|
|
app_object_id: The object ID of the app registration
|
|
description: Display name/description for the secret
|
|
years: Number of years until expiration (defaults to config.APP_SECRET_EXPIRATION_YEARS)
|
|
|
|
Returns:
|
|
Dict: Contains secret_text, key_id, and end_datetime
|
|
|
|
Raises:
|
|
Exception: If the API call fails
|
|
"""
|
|
try:
|
|
if years is None:
|
|
years = config.APP_SECRET_EXPIRATION_YEARS
|
|
|
|
# Calculate expiration date
|
|
end_date = datetime.now() + timedelta(days=365 * years)
|
|
|
|
# Create password credential
|
|
password_cred = PasswordCredential()
|
|
password_cred.display_name = description
|
|
password_cred.end_date_time = end_date
|
|
|
|
# Create request body
|
|
request_body = AddPasswordPostRequestBody()
|
|
request_body.password_credential = password_cred
|
|
|
|
# Call Graph API to add password
|
|
result = await self.graph_client.applications.by_application_id(
|
|
app_object_id
|
|
).add_password.post(request_body)
|
|
|
|
if result:
|
|
return {
|
|
'secret_text': result.secret_text,
|
|
'key_id': str(result.key_id),
|
|
'end_datetime': result.end_date_time,
|
|
'display_name': result.display_name
|
|
}
|
|
|
|
raise Exception("No result returned from add_password")
|
|
|
|
except Exception as e:
|
|
raise Exception(f"Failed to create secret: {str(e)}")
|
|
|
|
async def remove_old_secrets(
|
|
self,
|
|
app_object_id: str,
|
|
keep_key_id: str
|
|
) -> int:
|
|
"""
|
|
Remove all secrets except the specified one.
|
|
|
|
Args:
|
|
app_object_id: The object ID of the app registration
|
|
keep_key_id: The key ID to keep (newly created secret)
|
|
|
|
Returns:
|
|
int: Number of secrets removed
|
|
|
|
Raises:
|
|
Exception: If the API call fails
|
|
"""
|
|
try:
|
|
removed_count = 0
|
|
|
|
# Get the app with its password credentials
|
|
app = await self.graph_client.applications.by_application_id(app_object_id).get()
|
|
|
|
if app and app.password_credentials:
|
|
for cred in app.password_credentials:
|
|
# Remove if it's not the one we want to keep
|
|
if str(cred.key_id) != str(keep_key_id):
|
|
# Create request body
|
|
request_body = RemovePasswordPostRequestBody()
|
|
request_body.key_id = cred.key_id
|
|
|
|
# Call Graph API to remove password
|
|
await self.graph_client.applications.by_application_id(
|
|
app_object_id
|
|
).remove_password.post(request_body)
|
|
|
|
removed_count += 1
|
|
|
|
return removed_count
|
|
|
|
except Exception as e:
|
|
raise Exception(f"Failed to remove old secrets: {str(e)}")
|
|
|
|
async def list_secrets(self, app_object_id: str) -> List[Dict[str, Any]]:
|
|
"""
|
|
List all secrets for an app registration (metadata only, not the secret values).
|
|
|
|
Args:
|
|
app_object_id: The object ID of the app registration
|
|
|
|
Returns:
|
|
List[Dict]: List of secret metadata
|
|
|
|
Raises:
|
|
Exception: If the API call fails
|
|
"""
|
|
try:
|
|
app = await self.graph_client.applications.by_application_id(app_object_id).get()
|
|
|
|
secrets = []
|
|
if app and app.password_credentials:
|
|
for cred in app.password_credentials:
|
|
secrets.append({
|
|
'key_id': str(cred.key_id),
|
|
'display_name': cred.display_name,
|
|
'start_datetime': cred.start_date_time,
|
|
'end_datetime': cred.end_date_time
|
|
})
|
|
|
|
return secrets
|
|
|
|
except Exception as e:
|
|
raise Exception(f"Failed to list secrets: {str(e)}")
|