Install-ADFS_Demo_with_OTP.ps1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
#Requires -RunAsAdministrator #Requires -Version 4.0 <# .SYNOPSIS Installs ADFS Service with SecureMFA OTP Provider Web Portal on empty Windows Server. .DESCRIPTION Installs ADFS Service with SecureMFA OTP Provider on a single ADFS server using MS SQLEXPRESS database. Dependencies: * Deployment must be done with service account which will be used for ADFS service. Account must be member or local computer administrators� group and Domain Administrators groups for ADFS service to register successfully. * Server is Windows 2019 or 2016 serve and joined to domain. * Server has a valid certificate for ADFS Service communication. It must have CN name which is different to computer's FQDN * Server has "SqlServer" PS Module installed. * Server has a free edition of MSSQL SQLEXPRESS service installed using default Instance Name and Instance ID - SQLEXPRESS * Server has Microsoft Framework 4.6.1 and above installed. .NOTES Version: 2.0.0.1 Author: SecureMfa.com Creation Date: 27/07/2020 Purpose/Change: Release .EXAMPLE C:\PS> Install-ADFS_Demo_with_OTP -adfs_certificate_thumbprint "285394eae4e52bf64d3b6f6c304584f30c3f004f" This command will install ADFS service with SecureMFA OTP Provider and Web Portal which allows to enrol users on a single ADFS server using MSSQL SQLEXPRESS database. #> $zipfilepath = (Join-Path -Path $PSScriptRoot -ChildPath SecureMFA_OTP_SPA.zip) $sqlservermodulepath = "C:\Program Files\WindowsPowerShell\Modules\SqlServer" #Check if windows events source for application log exist, if not create one. if ([System.Diagnostics.EventLog]::SourceExists("Secure MFA OTP") -eq $False) {New-EventLog -LogName "Application" -Source "Secure MFA OTP" ; Write-Host "Secure MFA OTP Log Source Created."} Function Install-ADFS_Demo_with_OTP { Param ( [Parameter(Mandatory=$true)][string]$adfs_certificate_thumbprint, [Parameter(Mandatory=$false)][Switch]$Force ) #Check if ADFS service existi on the system if(((Get-Service adfssrv -ErrorAction SilentlyContinue).Status -ne $null) -and (!($Force))) {write-host "ADFS Service is allready running on this server $env:COMPUTERNAME . Please use new Windows build or unistall ADFS deployment before retry." -ForegroundColor Yellow; break} #Check if ADFS service existi on the system if(((Get-Service 'MSSQL$SQLEXPRESS' -ErrorAction SilentlyContinue).Status -ne 'Running') -and (!($Force))) {write-host "MSSQL SQLEXPRESS Edition is not running on a server $env:COMPUTERNAME . Please make sure you deploy a Free editon of MSSQL SQLEXPRESS Edition using default Instance Name and Instance ID: SQLEXPRESS on this computer to continue." -ForegroundColor Yellow; break} try { $Error.Clear() if (!(Test-Path $zipfilepath -Type Leaf) ) { throw "$zipfilepath does not exist" ; break} if (!(Test-Path $sqlservermodulepath) ) { throw "SqServer module $sqlservermodulepath does not exist please install it from PSGalery: Install-Module sqlserver" ; break} if(!(Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Thumbprint -eq $adfs_certificate_thumbprint})) {throw "Certificate $adfs_certificate_thumbprint does not exist in Cert:\LocalMachine\My. Please install certificate first before retry." ; break} #Start deployment #SQL Procedure for WID Database creation $SQLProcedureTemplate = @( "USE [master]", "GO", "/****** Object: Database [SecureMfaOTP] Script Date: 27/01/2020 21:52:40 ******/", "CREATE DATABASE [SecureMfaOTP]", "CONTAINMENT = NONE", "ON PRIMARY", "( NAME = N'SecureMfaOTP', FILENAME = N'C:\SecureMFA\SecureMfaOTP.mdf' , SIZE = 6144KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )", "LOG ON", "( NAME = N'SecureMfaOTP_log', FILENAME = N'C:\SecureMFA\SecureMfaOTP_log.ldf' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)", "GO", "ALTER DATABASE [SecureMfaOTP] SET COMPATIBILITY_LEVEL = 120", "GO", "IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))", "begin", "EXEC [SecureMfaOTP].[dbo].[sp_fulltext_database] @action = 'enable'", "end", "GO", "ALTER DATABASE [SecureMfaOTP] SET ANSI_NULL_DEFAULT OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET ANSI_NULLS OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET ANSI_PADDING OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET ANSI_WARNINGS OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET ARITHABORT OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET AUTO_CLOSE OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET AUTO_SHRINK OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET AUTO_UPDATE_STATISTICS ON", "GO", "ALTER DATABASE [SecureMfaOTP] SET CURSOR_CLOSE_ON_COMMIT OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET CURSOR_DEFAULT GLOBAL", "GO", "ALTER DATABASE [SecureMfaOTP] SET CONCAT_NULL_YIELDS_NULL OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET NUMERIC_ROUNDABORT OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET QUOTED_IDENTIFIER OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET RECURSIVE_TRIGGERS OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET DISABLE_BROKER", "GO", "ALTER DATABASE [SecureMfaOTP] SET AUTO_UPDATE_STATISTICS_ASYNC OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET DATE_CORRELATION_OPTIMIZATION OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET TRUSTWORTHY OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET ALLOW_SNAPSHOT_ISOLATION OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET PARAMETERIZATION SIMPLE", "GO", "ALTER DATABASE [SecureMfaOTP] SET READ_COMMITTED_SNAPSHOT OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET HONOR_BROKER_PRIORITY OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET RECOVERY SIMPLE", "GO", "ALTER DATABASE [SecureMfaOTP] SET MULTI_USER", "GO", "ALTER DATABASE [SecureMfaOTP] SET PAGE_VERIFY CHECKSUM", "GO", "ALTER DATABASE [SecureMfaOTP] SET DB_CHAINING OFF", "GO", "ALTER DATABASE [SecureMfaOTP] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF )", "GO", "ALTER DATABASE [SecureMfaOTP] SET TARGET_RECOVERY_TIME = 0 SECONDS", "GO", "ALTER DATABASE [SecureMfaOTP] SET DELAYED_DURABILITY = DISABLED", "GO", "EXEC sys.sp_db_vardecimal_storage_format N'SecureMfaOTP', N'ON'", "GO", "ALTER DATABASE [SecureMfaOTP] SET READ_WRITE", "GO", "USE [SecureMfaOTP]", "GO", "CREATE TABLE [dbo].[Secrets](", "[upn] [varchar](255) NOT NULL,", "[secret] [char](48) NOT NULL,", "[logon] [tinyint] NULL,", "[lastlogon] [datetime] NULL,", "[logoncount] [int] DEFAULT 0 NOT NULL,", "[failedlogoncount] [int] DEFAULT 0 NOT NULL,", "[failedlastlogon] [datetime] NULL,", "[failedcode] [char](6),", "[logonip] [varchar](64),", "[useragent] [varchar](128),", " CONSTRAINT [PK_Secrets] PRIMARY KEY CLUSTERED", "(", "[upn] ASC", ")WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]", ") ON [PRIMARY]", "GO", "CREATE TABLE [dbo].[UsedCodes](", "[upn] [varchar](255) NOT NULL,", "[interval] [bigint] NOT NULL", ") ON [PRIMARY]", "GO" ) #Start $adfs_service_account = "$env:USERDOMAIN\$env:USERNAME" do { if($inputfailures -eq 0) {Write-Host "Please enter a password for ADFS Service Account $adfs_service_account :"} else {Write-Host "[Retry: $inputfailures] Passwords didn't match for $adfs_service_account Try again:"} $pwd1 = Read-Host "Password" -AsSecureString $pwd2 = Read-Host "Re-enter Password" -AsSecureString $pwd1_text = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($pwd1)) $pwd2_text = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($pwd2)) $inputfailures++ } while ($pwd1_text -ne $pwd2_text ) $fscredential = new-object -typename System.Management.Automation.PSCredential -argumentlist $adfs_service_account,$pwd1 #Create Temp folder and export SQL procedure New-Item -Path "c:\" -Name "SecureMFA" -ItemType "directory" -Force $SQLProcedureTemplate | Out-File C:\SecureMFA\sql_Create_WID_Database_SecureMfaOTP.sql -Force #write-host "Adding $adfs_service_account account into the Local Administrators group" -ForegroundColor Green #Add-LocalGroupMember -Group "Administrators" -Member $adfs_service_account -ErrorAction SilentlyContinue #Select CN from certificate to use with ADFS FederationServiceName $adfs_service_name = Get-ChildItem -Path cert:\LocalMachine\My\$adfs_certificate_thumbprint | select subject | Select-String -Pattern 'CN\=([^},\r\n]+)' | %{$_.Matches.Groups[1].value} write-host "ADFS service name $adfs_service_name has been selected using CN value from $adfs_certificate_thumbprint certificate" -ForegroundColor Green #ADFS Install write-host "Installing ADFS service on a single server" -ForegroundColor Green Add-WindowsFeature ADFS-Federation -Includemanagementtools $install = Install-AdfsFarm -CertificateThumbprint $adfs_certificate_thumbprint -FederationServiceName $adfs_service_name -ServiceAccountCredential $fscredential sleep -Seconds 10 write-host "Installation status:" $install.Status write-host $install.Message -ForegroundColor Yellow #Enable AUdit AUDITPOL /SET /SUBCATEGORY:"Application Generated" /FAILURE:ENABLE /SUCCESS:ENABLE #Enable SAML 2.0 IdP-initiated sign-on set-adfsproperties -EnableIdpInitiatedSignon $True #Test ADFS Service installation Test-AdfsFarmInstallation -FederationServiceName $adfs_service_name -ServiceAccountCredential $fscredential write-host "Starting SecureMFA OTP Install" -ForegroundColor Green #SQL WID Configuration on localhost Invoke-Sqlcmd -ServerInstance "localhost\SQLEXPRESS" -InputFile "C:\SecureMFA\sql_Create_WID_Database_SecureMfaOTP.sql" #Deploy SecureMFA OTP Provider Install-SecureMfaOtpProvider # Verify your ADFS service by navigating into following URLs using your browser: write-host "Installation of ADFS service $adfs_service_name complete." -ForegroundColor Green write-host "ADFS service endpoints for FederationMetadata:" -ForegroundColor Green write-host "https://$adfs_service_name/FederationMetadata/2007-06/FederationMetadata.xml" -ForegroundColor Cyan write-host "https://$adfs_service_name/adfs/ls/IdpInitiatedSignon.aspx" -ForegroundColor Cyan #ADFS Application Group configuration New-AdfsApplicationGroup -Name "SecureMFA" -ApplicationGroupIdentifier "498a47d9-bbae-439e-9ffd-4f1afc609350" -Description "SecureMFA OTP WebPortal" Add-AdfsNativeClientApplication -ApplicationGroupIdentifier "498a47d9-bbae-439e-9ffd-4f1afc609350" -Name "SecureMFA - Native application" -Identifier "498a47d9-bbae-439e-9ffd-4f1afc609350" -RedirectUri (("http://" + (([System.Net.Dns]::GetHostByName(($env:computerName))).Hostname).tolower() + "/"),("http://" + ($env:computerName).tolower() + "/")) -Description "SecureMFA OTP WebPortal" Get-AdfsApplicationGroup -Name SecureMFa | Add-AdfsWebApiApplication -Name "SecureMFA - Web application" -Identifier "498a47d9-bbae-439e-9ffd-4f1afc609350" -AccessControlPolicyName "Permit everyone and require MFA" -IssueOAuthRefreshTokensTo "AllDevices" -AllowedClientTypes "Public, Confidential" Grant-AdfsApplicationPermission -ClientRoleIdentifier "498a47d9-bbae-439e-9ffd-4f1afc609350" -ServerRoleIdentifier "498a47d9-bbae-439e-9ffd-4f1afc609350" -ScopeNames "openid" -Description "SecureMFA WebPortal" #Deploy IIS Service with SecureMFA OTP WebPortal Install-WindowsFeature -Name Web-Server Remove-Item C:\inetpub\wwwroot\*.* -Force Expand-Archive -LiteralPath $zipfilepath -DestinationPath C:\inetpub\wwwroot -Force $ServiceHost = (([System.Net.Dns]::GetHostByName(($env:computerName))).Hostname).tolower() (Get-Content -path C:\inetpub\wwwroot\App\Scripts\app.js -Raw) -replace 'adfs.mydomain.com',$adfs_service_name| Set-Content -Path C:\inetpub\wwwroot\App\Scripts\app.js ##################### $RPURL = "http://" + (([System.Net.Dns]::GetHostByName(($env:computerName))).Hostname).tolower() + "/" write-host "To access SecureMFA OTP Web Portal go to: $RPURL" -ForegroundColor Cyan write-host "Single Node DEMO ADFS Deployment With SecureMFA OTP Provider Is Complete." -ForegroundColor Green } catch { Write-Host "$($MyInvocation.InvocationName): $_" -ForegroundColor red } } |