src/client/GraphIdentity.ps1
# Copyright 2019, Adam Edwards # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. . (import-script ../GraphService/GraphEndpoint) . (import-script GraphApplication) . (import-script ../auth/AuthProvider) . (import-script ../auth/V1AuthProvider) . (import-script ../auth/V2AuthProvider) ScriptClass GraphIdentity { $App = strict-val [PSCustomObject] $Token = strict-val [PSCustomObject] $null $GraphEndpoint = strict-val [PSCustomObject] $null $TenantName = $null $TenantDisplayId = $null $TenantDisplayName = $null static { function __initialize { $::.V1AuthProvider |=> RegisterProvider $::.V2AuthProvider |=> RegisterProvider $::.AuthProvider |=> InitializeProviders } } function __initialize([PSCustomObject] $app, [PSCustomObject] $graphEndpoint, [String] $tenantName) { $this.App = $app $this.GraphEndpoint = $graphEndpoint $this.TenantName = $tenantName __UpdateTenantDisplayInfo } function GetUserInformation { if ( $this.App.AuthType -eq ([GraphAppAuthType]::Delegated) ) { $providerInstance = $::.AuthProvider |=> GetProviderInstance $this.graphEndpoint.AuthProtocol $providerInstance |=> GetUserInformation $this.token } else { [PSCustomObject]@{ AppId = $this.App.AppId userId = $null scopes = $null } } } function Authenticate($scopes = $null) { if ( $this.token ) { $tokenTimeLeft = $this.token.expireson - [DateTime]::UtcNow write-verbose ("Found existing token with {0} minutes left before expiration" -f $tokenTimeLeft.TotalMinutes) } write-verbose ("Getting token for resource {0} from auth endpoint: {1} with protocol {2}" -f $this.graphEndpoint.Graph, $this.graphEndpoint.Authentication, $this.graphEndpoint.AuthProtocol) $this.Token = getGraphToken $this.graphEndpoint $scopes if ($this.token -eq $null) { throw "Failed to acquire token, no additional error information" } __UpdateTenantDisplayInfo } function ClearAuthentication { if ( $this.token -and $this.app.AuthType -eq ([GraphAppAuthType]::Delegated) ) { $authUri = $this.graphEndpoint |=> GetAuthUri (GetTenantId $this.TenantName) $providerInstance = $::.AuthProvider |=> GetProviderInstance $this.graphEndpoint.AuthProtocol $authContext = $providerInstance |=> GetAuthContext $this.app $this.graphEndpoint.Graph $authUri $providerInstance |=> ClearToken $authContext $this.token } $this.token = $null } function getGraphToken($graphEndpoint, $scopes) { write-verbose "Attempting to get token for '$($graphEndpoint.Graph)' ..." write-verbose "Using app id '$($this.App.AppId)'" $isConfidential = ($this.app |=> IsConfidential) write-verbose ("Is confidential client: '{0}'" -f $isConfidential) write-verbose ("Adding scopes to request: {0}" -f ($scopes -join ';')) $authUri = $graphEndpoint |=> GetAuthUri (GetTenantId $this.TenantName) write-verbose ("Sending auth request to auth uri '{0}'" -f $authUri) $providerInstance = $::.AuthProvider |=> GetProviderInstance $graphEndpoint.AuthProtocol $authContext = $providerInstance |=> GetAuthContext $this.app $graphEndpoint.Graph $authUri $authResult = if ( $this.token ) { $providerInstance |=> AcquireRefreshedToken $authContext $this.token } else { if ( $this.App.AuthType -eq ([GraphAppAuthType]::Apponly) ) { $providerInstance |=> AcquireFirstAppToken $authContext } else { if ( $isConfidential ) { $providerInstance |=> AcquireFirstUserTokenConfidential $authContext $scopes } else { $providerInstance |=> AcquireFirstUserToken $authContext $scopes } } } write-verbose ("`nToken request status: {0}" -f $authResult.Status) if ( $authResult.Status -eq 'Faulted' ) { throw "Failed to acquire token for uri '$($graphEndpoint.Graph)' for AppID '$($this.App.AppId)'`n" + $authResult.exception, $authResult.exception } $result = $authResult.Result if ( $authResult.IsFaulted ) { write-verbose $authResult.Exception throw [Exception]::new(("An authentication error occurred: '{0}'. See verbose output for additional details" -f $authResult.Exception.message), $authResult.Exception) } try { if ( ! $this.tenantId -and $result.tenantid ) { $this.tenantid = $result.tenantid } } catch { } $result } function GetTenantId($specifiedTenantId) { if ( $specifiedTenantId ) { $specifiedTenantId } else { __UpdateTenantDisplayInfo $this.tenantDisplayId } } function __UpdateTenantDisplayInfo { $tenant = try { if ( $this.token ) { (([uri] $this.token.authority).segments | select -last 1).trimend('/') } } catch { } if ( ! $tenant ) { $tenant = try { (([uri] $this.token.user.identityprovider).segments | select -first 2 | select -last 1).trimend('/') } catch { } } $tenantName = $null $tenantId = try { if ( $this.token ) { $this.token.tenantId } } catch { } $parsedTenantId = try { if ( $tenant ) { [guid] $tenant } } catch { $tenantName = $tenant } if ( ! $tenantName ) { $tenantName = $this.tenantName } if ( ! $tenantId ) { $tenantId = $parsedTenantId } $this.tenantDisplayId = $tenantId $this.tenantDisplayName = $tenantName } } $::.GraphIdentity |=> __initialize |