mirror of
https://github.com/Micke-K/IntuneManagement.git
synced 2026-09-28 19:05:38 +02:00
146 lines
5.5 KiB
PowerShell
146 lines
5.5 KiB
PowerShell
#ImportOrder 27
|
|
|
|
# Offline "mock tenant" provider.
|
|
#
|
|
# Signs in with no network and answers every Graph request from the JSON files
|
|
# under IM_MOCK_DATA (see Internal/MockGraph.ps1). Registered only when that
|
|
# variable points at a folder - a normal launch never sees it - and used for
|
|
# screenshots, demos and UI work without a tenant.
|
|
#
|
|
# The access token is a real-looking but unsigned JWT: the access-marking code
|
|
# reads scp / wids from it exactly as it would from Entra, so the menu renders
|
|
# with full access and no role lookup. Every request then goes through
|
|
# InvokeWebRequest (RoutesAllRequests) instead of HTTPS.
|
|
|
|
# What a mock 4xx throws. Invoke-MSGraphAPI reads the failure from
|
|
# $_.Exception.Response - StatusCode, Headers, and the body through
|
|
# GetResponseStream() - the same way it reads a WebException from
|
|
# Invoke-WebRequest, so a mock 404 reports its status, code and message like a
|
|
# real one. WebException.Response cannot be set from PowerShell, hence a class.
|
|
class MockGraphResponseException : System.Exception {
|
|
[object]$Response
|
|
|
|
MockGraphResponseException([string]$Message, [object]$Response) : base($Message) {
|
|
$this.Response = $Response
|
|
}
|
|
}
|
|
|
|
class AuthenticationMock : AuthenticationProvider {
|
|
|
|
static [hashtable]$Tokens = @{}
|
|
|
|
[string]$DataFolder
|
|
|
|
AuthenticationMock() {
|
|
$this.Id = "Mock"
|
|
$this.DisplayName = "Mock tenant (offline demo data)"
|
|
|
|
$this.SupportsInteractive = $true
|
|
$this.SupportsClientSecret = $false
|
|
$this.SupportsCertificate = $false
|
|
$this.SupportsIdentityProvider = $false
|
|
$this.SupportsBYOToken = $false
|
|
$this.SupportsClaimsChallenge = $false
|
|
$this.SupportsMultiTenant = $false
|
|
$this.SupportsRefresh = $true
|
|
$this.SupportsForget = $false
|
|
$this.SupportsCachedUsers = $false
|
|
$this.RoutesAllRequests = $true
|
|
}
|
|
|
|
[void] Initialize() {
|
|
$this.DataFolder = [string]$env:IM_MOCK_DATA
|
|
}
|
|
|
|
# Sign in at startup - there is nothing to prompt for.
|
|
[bool] TryResumeSession() {
|
|
if(-not $this.DataFolder) { return $false }
|
|
$token = $this.Connect(@{})
|
|
return [bool]$token
|
|
}
|
|
|
|
[PSCustomObject] Connect([hashtable]$Arguments) {
|
|
if(-not $this.DataFolder -or -not (Test-Path -LiteralPath $this.DataFolder -PathType Container)) {
|
|
Write-Log "Mock provider: IM_MOCK_DATA does not point at a folder ('$($this.DataFolder)')" 3
|
|
return $null
|
|
}
|
|
|
|
$tenant = Get-MockTenantProfile -Root $this.DataFolder
|
|
Initialize-MockGraphStore -Root $this.DataFolder | Out-Null
|
|
|
|
$tokenId = Get-NextAuthTokenId
|
|
[AuthenticationMock]::Tokens[$tokenId] = @{
|
|
Id = $tokenId
|
|
Tenant = $tenant
|
|
AccessToken = (New-MockAccessToken -Tenant $tenant)
|
|
AcquiredAt = [DateTime]::UtcNow
|
|
}
|
|
Write-Log "Mock provider: signed in to '$($tenant.TenantName)' as $($tenant.UPN) (TokenId=$tokenId)"
|
|
|
|
try {
|
|
$cur = Get-AuthProvider
|
|
if($cur -and $cur.Id -ne $this.Id) { Set-ActiveAuthProvider -Id $this.Id }
|
|
} catch { }
|
|
|
|
return (Register-AuthToken -Provider $this -TokenId $tokenId -Cloud (Get-DefaultCloud))
|
|
}
|
|
|
|
[bool] Disconnect([int]$TokenId) {
|
|
if(-not [AuthenticationMock]::Tokens.ContainsKey($TokenId)) { return $false }
|
|
Unregister-AuthToken -TokenId $TokenId
|
|
[AuthenticationMock]::Tokens.Remove($TokenId) | Out-Null
|
|
return $true
|
|
}
|
|
|
|
[bool] Refresh([int]$TokenId) {
|
|
return [AuthenticationMock]::Tokens.ContainsKey($TokenId)
|
|
}
|
|
|
|
[string] GetAccessToken([int]$TokenId, [string]$Resource) {
|
|
$entry = $this.GetEntry($TokenId)
|
|
if(-not $entry) { return $null }
|
|
return [string]$entry.AccessToken
|
|
}
|
|
|
|
[datetime] GetAccessTokenExpiry([int]$TokenId, [string]$Resource) {
|
|
return [datetime]::MaxValue
|
|
}
|
|
|
|
[object] InvokeWebRequest([string]$Url, [string]$Method, [object]$Body, [hashtable]$Headers) {
|
|
return (Invoke-MockGraphRequest -Url $Url -Method $Method -Body $Body)
|
|
}
|
|
|
|
[PSCustomObject] GetUserInfo([int]$TokenId) {
|
|
$entry = $this.GetEntry($TokenId)
|
|
if(-not $entry) { return $null }
|
|
$tenant = $entry.Tenant
|
|
return [PSCustomObject]@{
|
|
Provider = $this.Id
|
|
DisplayName = $tenant.DisplayName
|
|
UPN = $tenant.UPN
|
|
UserId = $tenant.UserId
|
|
TenantId = $tenant.TenantId
|
|
TenantName = $tenant.TenantName
|
|
AppId = $tenant.AppId
|
|
AppName = $tenant.AppName
|
|
AuthType = "Interactive"
|
|
ExpiresOn = [DateTime]::Now.AddYears(1)
|
|
}
|
|
}
|
|
|
|
[PSCustomObject[]] GetSessionInfoRows() {
|
|
$rows = [System.Collections.Generic.List[PSCustomObject]]::new()
|
|
$rows.Add([PSCustomObject]@{ Name = "Provider"; Value = "Mock (offline)" })
|
|
$rows.Add([PSCustomObject]@{ Name = "Data folder"; Value = $this.DataFolder })
|
|
return $rows.ToArray()
|
|
}
|
|
|
|
hidden [hashtable] GetEntry([int]$TokenId) {
|
|
if($TokenId -le 0 -and [AuthenticationMock]::Tokens.Count -gt 0) {
|
|
$TokenId = ([AuthenticationMock]::Tokens.Keys | Sort-Object -Descending | Select-Object -First 1)
|
|
}
|
|
if(-not [AuthenticationMock]::Tokens.ContainsKey($TokenId)) { return $null }
|
|
return [AuthenticationMock]::Tokens[$TokenId]
|
|
}
|
|
}
|