296 lines
10 KiB
Bash
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 ""
|
|
|