This commit is contained in:
Mikael Karlsson
2023-10-17 20:34:44 +11:00
parent ea3af64316
commit ab7b062946
33 changed files with 6545 additions and 4702 deletions

View File

@@ -10,7 +10,7 @@ This module manages Authentication for the application with MSAL. It is also res
#>
function Get-ModuleVersion
{
'3.9.1'
'3.9.2'
}
$global:msalAuthenticator = $null
@@ -158,6 +158,10 @@ function Clear-MSALCurentUserVaiables
{
$global:MSALTenantId = $null
$global:MSALGraphEnvironment = $null
$script:jwtAccessToken = $null
$script:jwtIdToken = $null
}
function Get-MSALCurrentApp
@@ -223,14 +227,23 @@ function Get-MSALUserInfo
if($global:MSALToken)
{
Write-Log "Get current user"
$tmpMe = MSGraph\Invoke-GraphRequest -Url "ME" -SkipAuthentication -ODataMetadata "Skip"
if($null -ne $tmpMe -and $tmpMe.creationType -ne "Invitation")
if($script:jwtAccessToken.Payload.idtyp -ne "app")
{
### Only get user info from home tenant
$global:Me = $tmpMe
Write-Log "Get profile picture"
$global:profilePhoto = "$($env:LOCALAPPDATA)\CloudAPIPowerShellManagement\$($global:Me.Id).jpeg"
MSGraph\Invoke-GraphRequest "me/photos/48x48/`$value" -OutFile $global:profilePhoto -SkipAuthentication -NoError | Out-Null
$tmpMe = MSGraph\Invoke-GraphRequest -Url "ME" -SkipAuthentication -ODataMetadata "Skip"
if($null -ne $tmpMe -and $tmpMe.creationType -ne "Invitation")
{
### Only get user info from home tenant
$global:Me = $tmpMe
Write-Log "Get profile picture"
$global:profilePhoto = "$($env:LOCALAPPDATA)\CloudAPIPowerShellManagement\$($global:Me.Id).jpeg"
MSGraph\Invoke-GraphRequest "me/photos/48x48/`$value" -OutFile $global:profilePhoto -SkipAuthentication -NoError | Out-Null
}
}
else
{
$global:profilePhoto = $null
$global:me = $script:jwtAccessToken.Payload.app_displayname
}
Write-Log "Get organization info"
@@ -834,6 +847,42 @@ function Connect-MSALUser
Write-LogDebug "Authenticate"
if($global:MainAppStarted -eq $false)
{
$script:AppLogin = (Get-SettingValue "GraphAzureAppLogin") -or ($global:TenantId -and $global:AzureAppId -and ($global:ClientSecret -or $global:ClientCert))
}
if($script:AppLogin)
{
if($global:MSALToken -and $global:MSALToken.ExpiresOn.LocalDateTime.Ticks -gt ((Get-Date).AddMinutes(-5)).Ticks)
{
return
}
# Get login info for silent job from settings
if(-not $global:AzureAppId) { $global:AzureAppId = Get-SettingValue "GraphAzureAppId" -TenantID $global:TenantId }
if(-not $global:ClientSecret -and -not $global:ClientCert) { $global:ClientSecret = Get-SettingValue "GraphAzureAppSecret" -TenantID $global:TenantId }
if(-not $global:ClientSecret -and -not $global:ClientCert) { $global:ClientCert = Get-SettingValue "GraphAzureAppCert" -TenantID $global:TenantId }
if($global:AzureAppId -and $global:ClientSecret -and $global:TenantId)
{
Connect-MSALClientApp $global:AzureAppId $global:TenantId -secret $global:ClientSecret
}
elseif($global:AzureAppId -and $global:ClientCert -and $global:TenantId)
{
Connect-MSALClientApp $global:AzureAppId $global:TenantId -certificate $global:ClientCert
}
else
{
Write-Log "Azure AppId, Tenant Id and Sercret/Cert must be specified for App logins" 3
}
Invoke-MSALAuthenticationUpdated $global:MSALToken
return
}
if($ShowMenu -eq $true -and ((Get-SettingValue "AzureADLoginMenu") -eq $true))
{
if((Show-MSALLoginMenu) -eq $false) { return }
@@ -1167,7 +1216,8 @@ function Connect-MSALUser
Save-Setting "" "LastLoggedOnUser" $authResult.Account.UserName
Save-Setting "" "LastLoggedOnUserId" $authResult.Account.HomeAccountId.ObjectId
}
Invoke-MSALAuthenticationUpdated $authResult
<#
Write-LogDebug "User, tenant or app has changed"
Get-MSALUserInfo
if($authResult)
@@ -1175,9 +1225,26 @@ function Connect-MSALUser
Invoke-MSALCheckObjectViewAccess $authResult
}
Invoke-ModuleFunction "Invoke-GraphAuthenticationUpdated"
#>
}
}
function local:Invoke-MSALAuthenticationUpdated
{
param($authResult)
Write-LogDebug "User, tenant or app has changed"
$script:jwtAccessToken = Get-JWTtoken $global:MSALToken.AccessToken
$script:jwtIdToken = Get-JWTtoken $global:MSALToken.IdToken
Get-MSALUserInfo
if($authResult)
{
Invoke-MSALCheckObjectViewAccess $authResult
}
Invoke-ModuleFunction "Invoke-GraphAuthenticationUpdated"
}
function Start-MSALConsentPrompt
{
param([switch]$PassThru, $authToken)
@@ -1254,6 +1321,22 @@ function Invoke-MSALCheckObjectViewAccess
Set-XamlProperty $script:userEllipsGrid "lnkRequestConsent" "Visibility" "Visible"
}
$accessToken = $null
if($authToken)
{
$accessToken = Get-JWTtoken $authToken.AccessToken
}
$curPermissions = $null
if($accessToken.Payload.idtyp -eq "app")
{
$curPermissions = $accessToken.Payload.roles
}
elseif($accessToken.Payload.scp)
{
$curPermissions = $accessToken.Payload.scp.Split(" ")
}
foreach($viewObjInfo in ($global:viewObjects | Where { $_.ViewInfo.AuthenticationID -eq "MSAL" }))
{
$viewObjInfo = $global:viewObjects | Where { $_.ViewInfo.Id -eq $global:EMViewObject.Id }
@@ -1262,10 +1345,8 @@ function Invoke-MSALCheckObjectViewAccess
{
if($authToken)
{
$accessToken = Get-JWTtoken $authToken.AccessToken
if($accessToken.Payload.scp)
if($curPermissions)
{
$curPermissions = $accessToken.Payload.scp.Split(" ")
foreach($viewItem in $viewObjInfo.ViewItems)
{
$full = 0
@@ -1400,7 +1481,7 @@ function Disconnect-MSALUser
$logout = $true
if(-not $global:MSALToken.Account) { return }
$user = $global:MSALToken.Account # Logout current user
$global:MSALToken = $null
$global:MSALToken = $null
Clear-MSALCurentUserVaiables # Only clear variables for current user
$msg = "Do you want to remove the token from the cache?"
$title = "Remove token?"
@@ -1563,6 +1644,10 @@ function Get-MSALProfileEllipse
{
$initials = "$($global:me.userPrincipalName[0])".ToUpper()
}
elseif($script:jwtAccessToken.Payload.idtyp -eq "app")
{
$initials = "APP"
}
$grd = Get-MSALUserPhotoEllips -size $size -fontSize $fontSize -Color $Color
@@ -1586,8 +1671,15 @@ function Get-MSALProfileEllipse
$global:grdProfileInfo.Tag = $grd
$grd.Tag = $global:grdProfileInfo
Set-XamlProperty $global:grdProfileInfo "txtOrganization" "Text" $global:Organization.displayName
Set-XamlProperty $global:grdProfileInfo "txtUsername" "Text" $global:me.displayName
Set-XamlProperty $global:grdProfileInfo "txtLogonName" "Text" $global:me.userPrincipalName
if($script:jwtAccessToken.Payload.idtyp -eq "app")
{
Set-XamlProperty $global:grdProfileInfo "txtUsername" "Text" "App Login"
}
else
{
Set-XamlProperty $global:grdProfileInfo "txtUsername" "Text" $global:me.displayName
Set-XamlProperty $global:grdProfileInfo "txtLogonName" "Text" $global:me.userPrincipalName
}
$global:tokenInfo = Get-JWTtoken $global:MSALToken.AccessToken
if($global:tokenInfo)
@@ -1606,11 +1698,16 @@ function Get-MSALProfileEllipse
$tmpObj.SetValue([System.Windows.Controls.Grid]::RowProperty,1)
$tmpObj.SetValue([System.Windows.Controls.Grid]::RowSpanProperty,2)
}
if($tmpObj)
{
$profileGrid.Children.Add($tmpObj) | Out-Null
}
if($script:jwtAccessToken.Payload.idtyp -eq "app")
{
$tmpObj.Visibility = "Collapsed"
}
$global:grdProfileInfo.Add_Loaded({param($obj, $e)
$point = $obj.Tag.TransformToAncestor($window).Transform([System.Windows.Point]::new(0,0));
@@ -1618,134 +1715,137 @@ function Get-MSALProfileEllipse
[System.Windows.Controls.Canvas]::SetTop($obj,($point.Y + $obj.Tag.ActualHeight))
})
#########################################################################################################
### Show / Hide consent button
#########################################################################################################
$script:userEllipsGrid = $tmpObj
if(($script:missingPermissions | measure).Count -eq 0)
if($script:jwtAccessToken.Payload.idtyp -ne "app")
{
Set-XamlProperty $script:userEllipsGrid "lnkRequestConsent" "Visibility" "Collapsed"
}
Add-XamlEvent $script:userEllipsGrid "lnkRequestConsent" "add_Click" {
Start-MSALConsentPrompt
}
$otherLogins = $global:grdProfileInfo.FindName("grdCachedAccounts")
#########################################################################################################
### Add cached users
#########################################################################################################
if((Get-SettingValue "SortAccountList") -eq $true)
{
$accounts = $global:MSALAccounts | Sort -Property Username
}
else
{
$accounts = $global:MSALAccounts
}
foreach($account in $accounts)
{
# Skip current logged on user
if($global:MSALToken.Account.Username -eq $Account.Username -or
$global:MSALToken.Account.HomeAccountId.ObjectId -eq $Account.HomeAccountId.ObjectId) { continue }
Add-CachedUser $account $otherLogins
}
#########################################################################################################
### Add login with another user
#########################################################################################################
$grdAccount = [System.Windows.Controls.Grid]::new()
$cd = [System.Windows.Controls.ColumnDefinition]::new()
$grdAccount.ColumnDefinitions.Add($cd)
$cd = [System.Windows.Controls.ColumnDefinition]::new()
$cd.Width = [double]::NaN
$grdAccount.ColumnDefinitions.Add($cd)
$icon = Get-XamlObject ($global:AppRootFolder + "\Xaml\Icons\Logon.xaml")
$icon.Width = 24
$icon.Height = 24
$icon.Margin = "0,0,5,0"
$grdAccount.Children.Add($icon) | Out-Null
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS>Sign in with a different account</TextBlock>")
$lbObj.SetValue([System.Windows.Controls.Grid]::ColumnProperty,1)
#$lbObj.Style = $window.TryFindResource("HoverUnderlineStyle")
$grdAccount.Children.Add($lbObj) | Out-Null
$lnkButton = [System.Windows.Controls.Button]::new()
$lnkButton.Content = $grdAccount
$lnkButton.Style = $window.TryFindResource("LinkButton")
$lnkButton.Margin = "0,5,0,0"
$lnkButton.Cursor = "Hand"
$lnkButton.Tag = $account
$lnkButton.add_Click({
Write-Status "Logging in..."
Hide-Popup
Connect-MSALUser -Interactive -ShowMenu
if($global:curObjectType)
#########################################################################################################
### Show / Hide consent button
#########################################################################################################
$script:userEllipsGrid = $tmpObj
if(($script:missingPermissions | measure).Count -eq 0)
{
Show-GraphObjects
Set-XamlProperty $script:userEllipsGrid "lnkRequestConsent" "Visibility" "Collapsed"
}
Write-Status ""
})
Add-XamlEvent $script:userEllipsGrid "lnkRequestConsent" "add_Click" {
Start-MSALConsentPrompt
}
$otherLogins = $global:grdProfileInfo.FindName("grdCachedAccounts")
$otherLogins = $global:grdProfileInfo.FindName("grdLoginAccount")
Add-GridObject $otherLogins $lnkButton
$otherLogins = $global:grdProfileInfo.FindName("grdTenantAccounts")
if(($script:AccessableTenants | measure).Count -gt 1)
{
#########################################################################################################
### Add switch to another tenant
### Add cached users
#########################################################################################################
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS><Bold>Tenants:</Bold></TextBlock>")
$lbObj.Margin = "0,5,0,0"
Add-GridObject $otherLogins $lbObj
foreach($tenant in $script:AccessableTenants)
if((Get-SettingValue "SortAccountList") -eq $true)
{
try
$accounts = $global:MSALAccounts | Sort -Property Username
}
else
{
$accounts = $global:MSALAccounts
}
foreach($account in $accounts)
{
# Skip current logged on user
if($global:MSALToken.Account.Username -eq $Account.Username -or
$global:MSALToken.Account.HomeAccountId.ObjectId -eq $Account.HomeAccountId.ObjectId) { continue }
Add-CachedUser $account $otherLogins
}
#########################################################################################################
### Add login with another user
#########################################################################################################
$grdAccount = [System.Windows.Controls.Grid]::new()
$cd = [System.Windows.Controls.ColumnDefinition]::new()
$grdAccount.ColumnDefinitions.Add($cd)
$cd = [System.Windows.Controls.ColumnDefinition]::new()
$cd.Width = [double]::NaN
$grdAccount.ColumnDefinitions.Add($cd)
$icon = Get-XamlObject ($global:AppRootFolder + "\Xaml\Icons\Logon.xaml")
$icon.Width = 24
$icon.Height = 24
$icon.Margin = "0,0,5,0"
$grdAccount.Children.Add($icon) | Out-Null
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS>Sign in with a different account</TextBlock>")
$lbObj.SetValue([System.Windows.Controls.Grid]::ColumnProperty,1)
#$lbObj.Style = $window.TryFindResource("HoverUnderlineStyle")
$grdAccount.Children.Add($lbObj) | Out-Null
$lnkButton = [System.Windows.Controls.Button]::new()
$lnkButton.Content = $grdAccount
$lnkButton.Style = $window.TryFindResource("LinkButton")
$lnkButton.Margin = "0,5,0,0"
$lnkButton.Cursor = "Hand"
$lnkButton.Tag = $account
$lnkButton.add_Click({
Write-Status "Logging in..."
Hide-Popup
Connect-MSALUser -Interactive -ShowMenu
if($global:curObjectType)
{
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS HorizontalAlignment=`"Stretch`"><Bold>$($tenant.DisplayName)</Bold><LineBreak/>$($tenant.defaultDomain)<LineBreak/>$($tenant.tenantId)</TextBlock>")
if($tenant.tenantId -ne $global:MSALToken.TenantId)
{
$lbObj.Style = $window.TryFindResource("HoverUnderlineStyleWithBackground")
$lbObj.HorizontalAlignment = "Stretch"
$lnkButton = [System.Windows.Controls.Button]::new()
$lnkButton.Content = $lbObj
$lnkButton.HorizontalAlignment = "Stretch"
$lnkButton.Style = $window.TryFindResource("ContentButton")
$lnkButton.Margin = "0,5,0,0"
$lnkButton.Cursor = "Hand"
$lnkButton.Tag = $tenant
$lnkButton.add_Click({
Write-Status "Logging in to $($this.Tag.DisplayName)"
# Set authority to selected tenant
$global:MSALTenantId = $this.Tag.tenantId
Hide-Popup
Connect-MSALUser -Account ($global:MSALAccounts | Where UserName -eq $global:MSALToken.Account.Username)
if($global:curObjectType)
{
Show-GraphObjects
}
Write-Status ""
})
Add-GridObject $otherLogins $lnkButton
}
else
{
$lbObj.Background = $window.TryFindResource("SelectedRowBackgroundColor")
$lbObj.Margin = "0,5,0,0"
Add-GridObject $otherLogins $lbObj
}
Show-GraphObjects
}
Write-Status ""
})
$otherLogins = $global:grdProfileInfo.FindName("grdLoginAccount")
Add-GridObject $otherLogins $lnkButton
$otherLogins = $global:grdProfileInfo.FindName("grdTenantAccounts")
if(($script:AccessableTenants | measure).Count -gt 1)
{
#########################################################################################################
### Add switch to another tenant
#########################################################################################################
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS><Bold>Tenants:</Bold></TextBlock>")
$lbObj.Margin = "0,5,0,0"
Add-GridObject $otherLogins $lbObj
foreach($tenant in $script:AccessableTenants)
{
try
{
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS HorizontalAlignment=`"Stretch`"><Bold>$($tenant.DisplayName)</Bold><LineBreak/>$($tenant.defaultDomain)<LineBreak/>$($tenant.tenantId)</TextBlock>")
if($tenant.tenantId -ne $global:MSALToken.TenantId)
{
$lbObj.Style = $window.TryFindResource("HoverUnderlineStyleWithBackground")
$lbObj.HorizontalAlignment = "Stretch"
$lnkButton = [System.Windows.Controls.Button]::new()
$lnkButton.Content = $lbObj
$lnkButton.HorizontalAlignment = "Stretch"
$lnkButton.Style = $window.TryFindResource("ContentButton")
$lnkButton.Margin = "0,5,0,0"
$lnkButton.Cursor = "Hand"
$lnkButton.Tag = $tenant
$lnkButton.add_Click({
Write-Status "Logging in to $($this.Tag.DisplayName)"
# Set authority to selected tenant
$global:MSALTenantId = $this.Tag.tenantId
Hide-Popup
Connect-MSALUser -Account ($global:MSALAccounts | Where UserName -eq $global:MSALToken.Account.Username)
if($global:curObjectType)
{
Show-GraphObjects
}
Write-Status ""
})
Add-GridObject $otherLogins $lnkButton
}
else
{
$lbObj.Background = $window.TryFindResource("SelectedRowBackgroundColor")
$lbObj.Margin = "0,5,0,0"
Add-GridObject $otherLogins $lbObj
}
}
catch {}
}
catch {}
}
}
@@ -1807,7 +1907,12 @@ function Get-MSALProfileEllipse
{
Show-GraphObjects
}
}
}
if($script:jwtAccessToken.Payload.idtyp -eq "app")
{
Set-XamlProperty $tmpObj "lnkLogout" "Visibility" "Collapsed"
}
}
catch {
Write-LogError "Failed to create profile information object. Error: " $_.Exception
@@ -1983,12 +2088,21 @@ function Get-MSALMissingScopes
$script:missingPermissions = @()
if($script:jwtAccessToken.Payload.idtyp -eq "app")
{
$curScopes = $script:jwtAccessToken.Payload.roles
}
else
{
$curScopes = $authToken.Scopes
}
foreach($scope in $reqScopes)
{
$tmpScope = $scope.Split('/')[-1]
if($tmpScope -eq ".default") { continue }
if($authToken.Scopes -contains $tmpScope) { continue }
if(($authToken.Scopes -like "*/$tmpScope")) { continue }
if($curScopes -contains $tmpScope) { continue }
if(($curScopes -like "*/$tmpScope")) { continue }
$arrTemp = $tmpScope.Split(".")
if($arrTemp[1] -eq "Read")
{
@@ -2012,6 +2126,9 @@ function Show-MSALDecodedToken {
$tokenData,
$title
)
if(-not $tokenData.Header) { return }
$tokenArr = @()
foreach($prop in ($tokenData.Header | GM | Where MemberType -eq NoteProperty))
{