First commit
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
"""
|
||||
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)}")
|
||||
Reference in New Issue
Block a user