Files
miracles_in_motion/scripts/setup-azure-entra.sh

296 lines
10 KiB
Bash

#!/bin/bash
# MS Entra (Azure AD) Setup Script for Miracles In Motion
# This script helps configure Azure AD authentication for the application
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
APP_NAME="Miracles In Motion Web App"
DOMAIN="miraclesinmotion.org"
STATIC_WEB_APP_NAME="${STATIC_WEB_APP_NAME:-mim-prod-web}"
AZURE_RESOURCE_GROUP="${AZURE_RESOURCE_GROUP:-rg-miraclesinmotion-prod}"
echo -e "${GREEN}🔐 MS Entra (Azure AD) Setup Script${NC}"
echo "=========================================="
echo ""
# Check if Azure CLI is installed
if ! command -v az &> /dev/null; then
echo -e "${RED}❌ Azure CLI not found. Please install it first.${NC}"
echo "Install from: https://docs.microsoft.com/cli/azure/install-azure-cli"
exit 1
fi
# Check if logged in to Azure
echo -e "${BLUE}📋 Checking Azure login status...${NC}"
CURRENT_USER=$(az account show --query "user.name" -o tsv 2>/dev/null || echo "")
if [ -z "$CURRENT_USER" ]; then
echo -e "${YELLOW}⚠️ Not logged in to Azure. Please log in...${NC}"
az login
CURRENT_USER=$(az account show --query "user.name" -o tsv)
fi
echo -e "${GREEN}✅ Logged in as: $CURRENT_USER${NC}"
echo ""
# Get Azure Static Web App URL
echo -e "${BLUE}📋 Getting Azure Static Web App information...${NC}"
AZURE_STATIC_WEB_APP_URL=$(az staticwebapp show \
--name "$STATIC_WEB_APP_NAME" \
--resource-group "$AZURE_RESOURCE_GROUP" \
--query "defaultHostname" -o tsv 2>/dev/null || echo "")
if [ -z "$AZURE_STATIC_WEB_APP_URL" ]; then
echo -e "${YELLOW}⚠️ Static Web App not found. Using default URL format.${NC}"
AZURE_STATIC_WEB_APP_URL="${STATIC_WEB_APP_NAME}.azurestaticapps.net"
fi
FULL_STATIC_WEB_APP_URL="https://${AZURE_STATIC_WEB_APP_URL}"
PRODUCTION_URL="https://${DOMAIN}"
WWW_URL="https://www.${DOMAIN}"
echo -e "${GREEN}✅ Static Web App URL: $FULL_STATIC_WEB_APP_URL${NC}"
echo ""
# Get Tenant ID
TENANT_ID=$(az account show --query "tenantId" -o tsv)
echo -e "${GREEN}✅ Tenant ID: $TENANT_ID${NC}"
echo ""
# Check if app registration already exists
echo -e "${BLUE}🔍 Checking for existing app registration...${NC}"
EXISTING_APP_ID=$(az ad app list --display-name "$APP_NAME" --query "[0].appId" -o tsv 2>/dev/null || echo "")
if [ -n "$EXISTING_APP_ID" ] && [ "$EXISTING_APP_ID" != "null" ]; then
echo -e "${YELLOW}⚠️ App registration already exists: $EXISTING_APP_ID${NC}"
read -p "Do you want to update it? (y/n): " UPDATE_APP
if [ "$UPDATE_APP" != "y" ]; then
APP_ID=$EXISTING_APP_ID
echo -e "${GREEN}✅ Using existing app registration${NC}"
else
echo -e "${BLUE}📝 Updating app registration...${NC}"
APP_ID=$EXISTING_APP_ID
fi
else
# Create app registration
echo -e "${BLUE}📝 Creating app registration...${NC}"
APP_ID=$(az ad app create \
--display-name "$APP_NAME" \
--sign-in-audience "AzureADMultipleOrgs" \
--web-redirect-uris "$PRODUCTION_URL" "$WWW_URL" "$FULL_STATIC_WEB_APP_URL" \
--query "appId" -o tsv)
echo -e "${GREEN}✅ App registration created: $APP_ID${NC}"
fi
echo ""
# Update redirect URIs
echo -e "${BLUE}📝 Updating redirect URIs...${NC}"
az ad app update --id "$APP_ID" \
--web-redirect-uris "$PRODUCTION_URL" "$WWW_URL" "$FULL_STATIC_WEB_APP_URL" \
--enable-id-token-issuance true \
--enable-access-token-issuance false \
--query "appId" -o tsv > /dev/null
echo -e "${GREEN}✅ Redirect URIs updated${NC}"
echo " - $PRODUCTION_URL"
echo " - $WWW_URL"
echo " - $FULL_STATIC_WEB_APP_URL"
echo ""
# Configure API permissions
echo -e "${BLUE}📝 Configuring API permissions...${NC}"
# Microsoft Graph permissions
GRAPH_PERMISSIONS=(
"User.Read"
"User.ReadBasic.All"
"email"
"openid"
"profile"
)
GRAPH_RESOURCE_ID=$(az ad sp show --id "00000003-0000-0000-c000-000000000000" --query "id" -o tsv)
for PERMISSION in "${GRAPH_PERMISSIONS[@]}"; do
PERMISSION_ID=$(az ad sp show --id "00000003-0000-0000-c000-000000000000" --query "oauth2PermissionScopes[?value=='$PERMISSION'].id" -o tsv)
if [ -n "$PERMISSION_ID" ]; then
echo " Adding permission: $PERMISSION"
az ad app permission add \
--id "$APP_ID" \
--api "00000003-0000-0000-c000-000000000000" \
--api-permissions "$PERMISSION_ID=Scope" \
--query "appId" -o tsv > /dev/null 2>&1 || echo " (may already exist)"
fi
done
echo -e "${GREEN}✅ API permissions configured${NC}"
echo ""
# Create app roles
echo -e "${BLUE}📝 Creating app roles...${NC}"
# Function to create app role
create_app_role() {
local role_name=$1
local role_value=$2
local role_description=$3
echo " Creating role: $role_name"
local role_json=$(cat <<EOF
{
"allowedMemberTypes": ["User"],
"description": "$role_description",
"displayName": "$role_name",
"id": "$(uuidgen | tr '[:upper:]' '[:lower:]')",
"isEnabled": true,
"value": "$role_value"
}
EOF
)
# Get existing roles
local existing_roles=$(az ad app show --id "$APP_ID" --query "appRoles" -o json)
# Check if role already exists
local role_exists=$(echo "$existing_roles" | jq -r ".[] | select(.value == \"$role_value\") | .value" 2>/dev/null || echo "")
if [ -z "$role_exists" ]; then
# Add new role to existing roles
local updated_roles=$(echo "$existing_roles" | jq ". + [$role_json]")
az ad app update --id "$APP_ID" --app-roles "$updated_roles" > /dev/null 2>&1
echo " ✅ Role created"
else
echo " ⚠️ Role already exists"
fi
}
# Create app roles
create_app_role "Admin" "Admin" "Administrator access to all features"
create_app_role "Volunteer" "Volunteer" "Volunteer access to assigned tasks"
create_app_role "Resource" "Resource" "Resource provider access"
echo -e "${GREEN}✅ App roles created${NC}"
echo ""
# Create service principal
echo -e "${BLUE}📝 Creating service principal...${NC}"
SP_ID=$(az ad sp create --id "$APP_ID" --query "id" -o tsv 2>/dev/null || \
az ad sp show --id "$APP_ID" --query "id" -o tsv)
echo -e "${GREEN}✅ Service principal created: $SP_ID${NC}"
echo ""
# Grant admin consent (requires admin privileges)
echo -e "${BLUE}📝 Granting admin consent for API permissions...${NC}"
read -p "Do you have admin privileges to grant consent? (y/n): " HAS_ADMIN
if [ "$HAS_ADMIN" == "y" ]; then
az ad app permission admin-consent --id "$APP_ID" && \
echo -e "${GREEN}✅ Admin consent granted${NC}" || \
echo -e "${YELLOW}⚠️ Could not grant admin consent. You may need to do this manually.${NC}"
else
echo -e "${YELLOW}⚠️ Skipping admin consent. Please grant consent manually in Azure Portal.${NC}"
echo " Go to: Azure Portal → Microsoft Entra ID → App registrations → $APP_NAME → API permissions → Grant admin consent"
fi
echo ""
# Create client secret (optional)
echo -e "${BLUE}📝 Client Secret Configuration...${NC}"
read -p "Do you want to create a client secret? (y/n): " CREATE_SECRET
if [ "$CREATE_SECRET" == "y" ]; then
SECRET_NAME="Miracles In Motion Secret $(date +%Y%m%d)"
SECRET=$(az ad app credential reset --id "$APP_ID" --display-name "$SECRET_NAME" --years 2 --query "password" -o tsv)
echo -e "${GREEN}✅ Client secret created${NC}"
echo -e "${RED}⚠️ IMPORTANT: Save this secret now - it won't be shown again!${NC}"
echo "Secret: $SECRET"
echo ""
read -p "Press Enter to continue after saving the secret..."
else
echo -e "${YELLOW}⚠️ Skipping client secret creation${NC}"
SECRET=""
fi
echo ""
# Store configuration in Key Vault (if available)
echo -e "${BLUE}📝 Storing configuration in Key Vault...${NC}"
KEY_VAULT_NAME=$(az keyvault list --resource-group "$AZURE_RESOURCE_GROUP" --query "[0].name" -o tsv 2>/dev/null || echo "")
if [ -n "$KEY_VAULT_NAME" ]; then
echo "Storing in Key Vault: $KEY_VAULT_NAME"
az keyvault secret set \
--vault-name "$KEY_VAULT_NAME" \
--name "azure-client-id" \
--value "$APP_ID" > /dev/null 2>&1 && echo -e "${GREEN}✅ Client ID stored${NC}" || echo -e "${YELLOW}⚠️ Could not store Client ID${NC}"
az keyvault secret set \
--vault-name "$KEY_VAULT_NAME" \
--name "azure-tenant-id" \
--value "$TENANT_ID" > /dev/null 2>&1 && echo -e "${GREEN}✅ Tenant ID stored${NC}" || echo -e "${YELLOW}⚠️ Could not store Tenant ID${NC}"
if [ -n "$SECRET" ]; then
az keyvault secret set \
--vault-name "$KEY_VAULT_NAME" \
--name "azure-client-secret" \
--value "$SECRET" > /dev/null 2>&1 && echo -e "${GREEN}✅ Client Secret stored${NC}" || echo -e "${YELLOW}⚠️ Could not store Client Secret${NC}"
fi
else
echo -e "${YELLOW}⚠️ Key Vault not found. Skipping secret storage.${NC}"
fi
echo ""
# Summary
echo -e "${GREEN}✅ MS Entra Setup Complete!${NC}"
echo "=================================="
echo ""
echo "Configuration Summary:"
echo " App Registration ID: $APP_ID"
echo " Tenant ID: $TENANT_ID"
echo " Service Principal ID: $SP_ID"
echo ""
echo "Redirect URIs:"
echo " - $PRODUCTION_URL"
echo " - $WWW_URL"
echo " - $FULL_STATIC_WEB_APP_URL"
echo ""
echo "App Roles:"
echo " - Admin"
echo " - Volunteer"
echo " - Resource"
echo ""
echo "Next Steps:"
echo "1. Assign users to app roles in Azure Portal"
echo "2. Update staticwebapp.config.json with authentication configuration"
echo "3. Update application code to use Azure AD authentication"
echo "4. Test authentication flow"
echo ""
echo "Azure Portal Links:"
echo " App Registration: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/appId/$APP_ID"
echo " API Permissions: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/CallAnAPI/appId/$APP_ID"
echo " App Roles: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/AppRoles/appId/$APP_ID"
echo ""
# Export variables for use in other scripts
cat > .azure-entra-config.env <<EOF
# Azure AD Configuration
AZURE_CLIENT_ID=$APP_ID
AZURE_TENANT_ID=$TENANT_ID
AZURE_CLIENT_SECRET=$SECRET
AZURE_STATIC_WEB_APP_URL=$FULL_STATIC_WEB_APP_URL
AZURE_PRODUCTION_URL=$PRODUCTION_URL
EOF
echo -e "${GREEN}✅ Configuration saved to .azure-entra-config.env${NC}"
echo ""