diff --git a/Tools/apiCompat/baseline/ApiCompatBaseline.net6.0.txt b/Tools/apiCompat/baseline/ApiCompatBaseline.net6.0.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Wilson.sln b/Wilson.sln index 3b3881eec7..234b01fca6 100644 --- a/Wilson.sln +++ b/Wilson.sln @@ -97,6 +97,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.IdentityModel.Val EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.IdentityModel.SampleTests", "test\Microsoft.IdentityModel.SampleTests\Microsoft.IdentityModel.SampleTests.csproj", "{578FDF8F-6568-448A-AB93-D94269593932}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.IdentityModel.Abstractions", "src\Microsoft.IdentityModel.Abstractions\Microsoft.IdentityModel.Abstractions.csproj", "{8057C69A-3D1E-46A3-86E4-E6B26249DD25}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.IdentityModel.LoggingExtensions", "src\Microsoft.IdentityModel.LoggingExtensions\Microsoft.IdentityModel.LoggingExtensions.csproj", "{C1F5A997-FAA9-45E5-8D28-D4E92D4A034D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.IdentityModel.Abstractions.Tests", "test\Microsoft.IdentityModel.Abstractions.Tests\Microsoft.IdentityModel.Abstractions.Tests.csproj", "{EF9A4431-6D2C-4DD1-BF6B-6F2CC619DEE1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -227,6 +232,18 @@ Global {578FDF8F-6568-448A-AB93-D94269593932}.Debug|Any CPU.Build.0 = Debug|Any CPU {578FDF8F-6568-448A-AB93-D94269593932}.Release|Any CPU.ActiveCfg = Release|Any CPU {578FDF8F-6568-448A-AB93-D94269593932}.Release|Any CPU.Build.0 = Release|Any CPU + {8057C69A-3D1E-46A3-86E4-E6B26249DD25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8057C69A-3D1E-46A3-86E4-E6B26249DD25}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8057C69A-3D1E-46A3-86E4-E6B26249DD25}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8057C69A-3D1E-46A3-86E4-E6B26249DD25}.Release|Any CPU.Build.0 = Release|Any CPU + {C1F5A997-FAA9-45E5-8D28-D4E92D4A034D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C1F5A997-FAA9-45E5-8D28-D4E92D4A034D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1F5A997-FAA9-45E5-8D28-D4E92D4A034D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C1F5A997-FAA9-45E5-8D28-D4E92D4A034D}.Release|Any CPU.Build.0 = Release|Any CPU + {EF9A4431-6D2C-4DD1-BF6B-6F2CC619DEE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EF9A4431-6D2C-4DD1-BF6B-6F2CC619DEE1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EF9A4431-6D2C-4DD1-BF6B-6F2CC619DEE1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EF9A4431-6D2C-4DD1-BF6B-6F2CC619DEE1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -266,6 +283,9 @@ Global {DA585910-0E6C-45A5-AABD-30917130FD63} = {BD2706C5-6C57-484D-89C8-A0CF5F8E3D19} {D17F097F-6024-40BA-A7A0-015BB90F203B} = {8905D2E3-4499-4A86-BF3E-F098F228DD59} {578FDF8F-6568-448A-AB93-D94269593932} = {8905D2E3-4499-4A86-BF3E-F098F228DD59} + {8057C69A-3D1E-46A3-86E4-E6B26249DD25} = {BD2706C5-6C57-484D-89C8-A0CF5F8E3D19} + {C1F5A997-FAA9-45E5-8D28-D4E92D4A034D} = {EB14B99B-2255-45BC-BF14-E488DCD4A4BA} + {EF9A4431-6D2C-4DD1-BF6B-6F2CC619DEE1} = {8905D2E3-4499-4A86-BF3E-F098F228DD59} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2F681326-7ED4-45F6-BD1D-1119EA388F42} diff --git a/build/apiCompat.ps1 b/build/apiCompat.ps1 new file mode 100644 index 0000000000..7aac440258 --- /dev/null +++ b/build/apiCompat.ps1 @@ -0,0 +1,224 @@ +param( + [string]$feedLocation = "ADO", # or 'ADO' or 'NuGet' + [string]$packageNames="", # comma-separated list of packages + [string]$packageVersion="latest", # or the exact version e.g. "5.4.0-preview" + [string]$adoFeedSource="", # required only for ADO feeds + [string]$adoFeedName="", # required only for ADO feeds + [string]$adoFeedUsername="VssSessionToken", # required only for ADO feeds + [string]$adoFeedPat="", # required only for ADO feeds + [string]$apiCompatRoot="$PSScriptRoot\tools\ApiCompat", + [string]$nugetPackageProviderVersion="2.8.5.208", + [string]$adoAllowPrerelease ="false" # uses the latest release (including preview releases) if packageVersion is 'latest' +) + +################################################# Functions ############################################################ + +function CreateBasicAuthHeader { +Param( + [string]$Username, + [string]$PAT +) + +$Auth = '{0}:{1}' -f $Username, $PAT +$Auth = [System.Text.Encoding]::UTF8.GetBytes($Auth) +$Auth = [System.Convert]::ToBase64String($Auth) +$Header = @{Authorization=("Basic {0}" -f $Auth)} +$Header +} + +function CreatePsCredential { +Param( + [string]$Username, + [string]$PAT +) + + $password = ConvertTo-SecureString $PAT -AsPlainText -Force + $pSCredential = New-Object System.Management.Automation.PSCredential $Username, $password + $pSCredential +} + +function CreateFolder { +Param( + [string]$Folder +) + if (Test-Path($folder)) + { + Write-Host ">>> $folder already exists!" + } + else + { + Write-Host ">>> New-Item -ItemType directory $Folder | Out-Null" + New-Item -ItemType directory $Folder | Out-Null + } +} + +function DownloadPackage { +Param( + [string]$PackageDownloadUrl, + [string]$OutFile, + [System.Collections.IDictionary]$Headers, + [string]$apiCompatRoot +) + Write-Host ">>> Invoke-WebRequest -Uri $PackageDownloadUrl -OutFile $OutFile -Headers $Headers" + Invoke-WebRequest -Uri $PackageDownloadUrl -OutFile $OutFile -Headers $Headers +} + +function FormAdoPackageDownloadUrl { +Param( + [string]$FeedSource, + [string]$FeedName, + [string]$PackageName, + [string]$PackageVersion +) + + $scheme = ([System.Uri]$FeedSource).Scheme + $baseUrl = ([System.Uri]$FeedSource).Host + $packageDownloadUrl = "$scheme`://$baseUrl/_apis/packaging/feeds/$FeedName/nuget/packages/$PackageName/versions/$PackageVersion/content" + Write-Host ">>> Formed ADO package download URL: $packageDownloadUrl" + $packageDownloadUrl +} + +function FormNugetPackageDownloadUrl { + Param( + [string]$PackageName, + [string]$PackageVersion + ) + + if ($PackageVersion -Eq 'latest') { + $packageDownloadUrl = "https://www.nuget.org/api/v2/package/$PackageName" + } else { + $packageDownloadUrl = "https://www.nuget.org/api/v2/package/$PackageName/$PackageVersion" + } + + Write-Host ">>> Formed NuGet package download URL: $packageDownloadUrl" + $packageDownloadUrl +} + +function PlaceContractAssemblies([String] $apiCompatRoot) { + Get-ChildItem "$apiCompatRoot\unzippedPackages" -Recurse -Include '*.dll' | Foreach-Object ` + { + # resolve target framework, destination directory and destination assembly file path + $targetFramework = Split-Path $_.Directory -leaf + $contractAssembliesPath = "$apiCompatRoot\contractAssemblies" + $destDir = Join-Path -Path $contractAssembliesPath -ChildPath $targetFramework + + CreateFolder($destDir) + + Write-Host ">>> Copy-Item $_ -Destination $destDir" + Copy-Item $_ -Destination $destDir + } +} + +function RemoveFolder { +Param( + [string]$Folder +) + if (Test-Path($Folder)) { + + Write-Host ">>> Remove-Item -Recurse -Force $Folder -Confirm:$false" + Remove-Item -Recurse -Force $Folder -Confirm:$false + } else { + Write-Host ">>> $Folder doesn't exist!" + } +} + +function UzipPackage { +Param( + [string]$Package, + [string]$DestinationPath +) + Write-Host ">>> Expand-Archive -Path $Package -DestinationPath $DestinationPath -Force" + Expand-Archive -Path $Package -DestinationPath $DestinationPath -Force +} + +################################################# Functions ############################################################ + +Write-Host (">>> Start ApiCompat - Prepare contract assemblies (v2) - parameters"); +Write-Host "feedLocation: " $feedLocation; +Write-Host "adoFeedSource: " $adoFeedSource; +Write-Host "adoFeedName: " $adoFeedName; +Write-Host "adoFeedUsername: " $adoFeedUsername; +Write-Host "packageNames: " $packageNames; +Write-Host "packageVersion: " $packageVersion; +Write-Host "apiCompatRoot: " $apiCompatRoot; +Write-Host "nugetPackageProviderVersion: " $nugetPackageProviderVersion; +Write-Host "adoAllowPrerelease: " $adoAllowPrerelease; +Write-Host (">>> End ApiCompat - Prepare contract assemblies (v2) - parameters"); + +if ($feedLocation -Eq 'ADO' -And ($adoFeedPat -Eq '' -Or $adoFeedSource -Eq '' -Or $adoFeedName -Eq '' -Or $adoFeedUsername -Eq '')) { + throw ">>> adoFeedPat, adoFeedSource, adoFeedName, and adoFeedUsername are required when feed location is set to 'ADO'. Run the script again and set the required values." +} + +if ($packageNames -Eq '') { + throw ">>> List of packageNames is empty. Run the script again and set the packageNames." +} + +$packageNamesArray = $packageNames.split(" ") + +if ($packageVersion -Eq 'latest') { + $useLatestVersion = 'true' +} else { + $useLatestVersion = 'false' +} + +# determine the latest package version from an ADO feed +if ($packageVersion -Eq 'latest' -And $feedLocation -Eq "ADO") { + $nugetPackageProviderResult = Get-PackageProvider -Name Nuget -ErrorAction SilentlyContinue + if ($null -Eq $nugetPackageProviderResult -Or $nugetPackageProviderResult.Version -ne [System.Version]$nugetPackageProviderVersion) { + Write-Host ">>> Install-PackageProvider Nuget -RequiredVersion $nugetPackageProviderVersion -Force -Scope CurrentUser | Out-Null" + Install-PackageProvider Nuget -RequiredVersion $nugetPackageProviderVersion -Force -Scope CurrentUser | Out-Null + } else { + Write-Host (">>> Nuget package provider (" + $nugetPackageProviderResult.Version + ") is already installed.") + } + + $credential = CreatePsCredential -Username $adoFeedUsername -PAT $adoFeedPat + + $getFeedResult = Get-PSRepository -Name $adoFeedName -ErrorAction SilentlyContinue + if ($null -Eq $getFeedResult) { + Write-Host ">>> Register-PSRepository -Name $adoFeedName -SourceLocation $adoFeedSource -InstallationPolicy Trusted -Credential $credential" + Register-PSRepository -Name $adoFeedName -SourceLocation $adoFeedSource -InstallationPolicy Trusted -Credential $credential + } else + { + Write-Host ">>> Feed $adoFeedName is already registered." + } +} + +# prepare directories +RemoveFolder -Folder "$apiCompatRoot\contractAssemblies" +CreateFolder -Folder "$apiCompatRoot\contractAssemblies" +CreateFolder("$apiCompatRoot\downloadedPackages") + +# download and unzip packages +foreach($packageName in $packageNamesArray) { + $packageName = $packageName.trim() + $outFile = "$apiCompatRoot\downloadedPackages\$packageName.zip" + $unzippedDir = "$apiCompatRoot\unzippedPackages\$packageName" + + if ($useLatestVersion -Eq 'true' -And $feedLocation -Eq "ADO") { + if ($adoAllowPrerelease -Eq 'true') { + $packageVersion = (Find-Module -Name $packageName -Repository $adoFeedName -Credential $credential -AllowPrerelease)[0].Version + } else { + $packageVersion = (Find-Module -Name $packageName -Repository $adoFeedName -Credential $credential)[0].Version + } + } + + Write-Host (">>> Latest " + $packageName + " version: $packageVersion") + + if ($feedLocation -eq 'ADO') { + $header = CreateBasicAuthHeader -Username $adoFeedUsername -PAT $adoFeedPat + $downloadPackageUrl = FormAdoPackageDownloadUrl -FeedSource $adoFeedSource -FeedName $adoFeedName -PackageName $packageName -PackageVersion $PackageVersion + DownloadPackage -packageDownloadUrl $downloadPackageUrl -header $header -outFile $outFile -apiCompatRoot $apiCompatRoot + } else { + $downloadPackageUrl = FormNugetPackageDownloadUrl -PackageName $packageName -PackageVersion $PackageVersion + DownloadPackage -packageDownloadUrl $downloadPackageUrl -outFile $outFile -apiCompatRoot $apiCompatRoot + } + + UzipPackage -package $outFile -destinationPath $unzippedDir +} + +# place the contract assemblies and clean-up +PlaceContractAssemblies($apiCompatRoot) +RemoveFolder -Folder "$apiCompatRoot\downloadedPackages" +RemoveFolder -Folder "$apiCompatRoot\unzippedPackages" + +Write-Host ">>> Done - ApiCompat - Prepare contract assemblies (v2)." \ No newline at end of file diff --git a/build/commonTest.props b/build/commonTest.props index f2841c11e1..9d82ef294a 100644 --- a/build/commonTest.props +++ b/build/commonTest.props @@ -15,14 +15,14 @@ true $(TestTargets) $(TestOnlyCoreTargets) - $(DotNetCoreAppRuntimeVersion) + $(DotNetCoreAppRuntimeVersion) - + $(DefineConstants);NET_CORE - + diff --git a/build/dependencies.props b/build/dependencies.props index f29b39a92b..472efa8d00 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,5 +1,6 @@ + 2.1.1 3.0.5 1.0.3 4.5.0 diff --git a/build/dependenciesTest.props b/build/dependenciesTest.props index 0d815f29e6..2c6874bcf6 100644 --- a/build/dependenciesTest.props +++ b/build/dependenciesTest.props @@ -1,11 +1,11 @@ - 2.1.19 + 2.1.30 2.0.3 2.0.5 2.4.0-prerelease-63213-02 1.0.4.403061554 - 15.9.0 + 16.10.0 4.0.4.403061554 4.3.4 2.4.0 diff --git a/build/releaseBuild.yml b/build/releaseBuild.yml new file mode 100644 index 0000000000..27c213b91f --- /dev/null +++ b/build/releaseBuild.yml @@ -0,0 +1,227 @@ +trigger: none +pr: none + +name: $(TeamProject)_$(Build.DefinitionName)_$(SourceBranchName)_$(Date:yyyyMMdd)$(Rev:.r) + +# Create a daily midnight build for release builds on master to ensure our release builds function +schedules: +- cron: "0 0 * * *" + displayName: Daily midnight build + branches: + include: + - dev + +variables: + - group: Middleware + - name: BuildPlatform + value: 'any cpu' + - name: BuildConfiguration + value: 'Release' + +jobs: +- job: build + pool: + name: MwWilson1EsHostedPool + demands: + - msbuild + - DotNetFramework + - visualstudio + timeoutInMinutes: 360 + + steps: + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk 2.1.818' + inputs: + version: 2.1.818 + installationPath: 'c:\Program Files\dotnet' + + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk 2.1.x' + inputs: + version: 2.1.x + installationPath: $(Agent.ToolsDirectory)/dotnet + + - task: UseDotNet@2 + displayName: 'Use .Net Core SDK 6' + inputs: + version: 6.0.x + + - task: DotNetCoreCLI@2 + displayName: 'dotnet --list-sdks ' + inputs: + command: custom + custom: '--list-sdks ' + + - task: CmdLine@1 + displayName: 'Run VerifyResourceUsage.pl' + inputs: + filename: perl + arguments: '$(Agent.BuildDirectory)\s\src\VerifyResourceUsage.pl' + + - powershell: | + regedit /s .\build\strongNameBypass.reg + regedit /s .\build\strongNameBypass2.reg + displayName: 'Strong Name Bypass' + + - task: PowerShell@2 + displayName: 'Update Assembly Info' + inputs: + targetType: filePath + filePath: ./updateAssemblyInfo.ps1 + arguments: '-packageType $(BuildConfiguration)' + + - task: PowerShell@2 + displayName: 'Prepare contract assemblies' + inputs: + targetType: 'filePath' + filePath: $(Agent.BuildDirectory)\s\build\apiCompat.ps1 + arguments: > + -feedLocation "NuGet" + -packageNames $(Wilson6xPackageList) + -packageVersion: "latest" + -adoFeedSource: $(AdoFeedSource) + -adoFeedName: $(AdoFeedName) + -adoAllowPrerelease: "false" + -apiCompatRoot: $(ApiCompatRootWilson) + -nugetPackageProviderVersion: "2.8.5.208" + + - task: MSBuild@1 + displayName: Build + inputs: + solution: wilson.sln + msbuildVersion: '17.0.0' + msbuildArchitecture: x64 + msbuildArguments: '/r:True /p:Configuration=$(BuildConfiguration) /p:Platform="Any CPU" /verbosity:m /p:SourceLinkCreate=true /p:RunApiCompat=true' + + - task: PowerShell@2 + displayName: 'Run Tests' + inputs: + targetType: filePath + filePath: ./runTests.ps1 + arguments: '-buildType $(BuildConfiguration)' + + - task: CopyFiles@2 + displayName: 'Copy Files to: [staging]\ProductBinaries' + inputs: + SourceFolder: src + Contents: | + **\bin\$(BuildConfiguration)\**\Microsoft.IdentityModel.*.dll + **\bin\$(BuildConfiguration)\**\Microsoft.IdentityModel.*.pdb + **\bin\$(BuildConfiguration)\**\System.IdentityModel.Tokens.Jwt.dll + **\bin\$(BuildConfiguration)\**\System.IdentityModel.Tokens.Jwt.pdb + TargetFolder: '$(Build.ArtifactStagingDirectory)\ProductBinaries' + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-policheck.PoliCheck@1 + displayName: 'Run PoliCheck' + inputs: + targetType: F + optionsFC: 0 + optionsXS: 0 + optionsHMENABLE: 0 + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@2 + displayName: 'Run CredScan' + inputs: + suppressionsFile: 'build/credscan-exclusion.json' + debugMode: false + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-roslynanalyzers.RoslynAnalyzers@2 + displayName: 'Run Roslyn Analyzers' + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-binskim.BinSkim@3 + displayName: 'Run BinSkim' + inputs: + InputType: Basic + AnalyzeTarget: '$(Build.ArtifactStagingDirectory)\*.dll' + AnalyzeSymPath: '$(Build.ArtifactStagingDirectory)\ProductBinaries' + AnalyzeVerbose: true + AnalyzeHashes: true + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2 + displayName: 'Publish Security Analysis Logs' + continueOnError: true + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-postanalysis.PostAnalysis@1 + displayName: 'Post SDL Analysis' + inputs: + BinSkim: true + CredScan: true + PoliCheck: true + continueOnError: true + + #Sign Wilson 6x task group + - template: template-sign-wilson-6x.yaml + + - task: PowerShell@2 + displayName: Pack + inputs: + targetType: filePath + filePath: ./pack.ps1 + arguments: '-buildType $(BuildConfiguration)' + + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 + displayName: 'Sign Nuget Packages' + inputs: + ConnectedServiceName: 'IDDP Code Signing' + FolderPath: artifacts + Pattern: '*.nupkg' + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-401405", + "operationSetCode": "NuGetSign", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + }, + { + "keyCode": "CP-401405", + "operationSetCode": "NuGetVerify", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + SessionTimeout: 20 + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + inputs: + scanType: 'Register' + verbosity: 'Verbose' + alertWarningLevel: 'High' + + - task: PublishSymbols@2 + displayName: 'Publish symbols on symweb (cross publish)' + inputs: + SearchPattern: '**\bin\**\*.IdentityModel.*' + SymbolServerType: TeamServices + TreatNotIndexedAsWarning: true + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-uploadtotsa.TSAUpload@1 + displayName: 'TSA upload to Codebase: WILSON Stamp: Azure' + inputs: + tsaVersion: TsaV2 + codeBaseName: WILSON + uploadAPIScan: false + uploadFortifySCA: false + uploadFxCop: false + uploadModernCop: false + uploadPREfast: false + uploadTSLint: false + + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: 'Manifest Generator ' + inputs: + BuildDropPath: '$(Build.SourcesDirectory)\src' + ManifestDirPath: '$(Build.SourcesDirectory)\artifacts' + + - task: PublishBuildArtifacts@1 + displayName: 'Publish NuGet Package Artifact' + inputs: + PathtoPublish: '$(Build.SourcesDirectory)\artifacts' + ArtifactName: '$(Build.BuildNumber)-nuget-package' + + - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 + displayName: 'Clean Agent Directories' diff --git a/build/strongNameBypass.reg b/build/strongNameBypass.reg index 242b5f53cb..970e9a7471 100644 Binary files a/build/strongNameBypass.reg and b/build/strongNameBypass.reg differ diff --git a/build/strongNameBypass2.reg b/build/strongNameBypass2.reg index ec084be794..930b518bda 100644 Binary files a/build/strongNameBypass2.reg and b/build/strongNameBypass2.reg differ diff --git a/build/targets.props b/build/targets.props index 3c93d991a6..e5ac9a6e94 100644 --- a/build/targets.props +++ b/build/targets.props @@ -1,6 +1,6 @@ - net45;net461;net472;netstandard2.0 + net45;net461;net472;netstandard2.0;net6.0 netstandard2.0 diff --git a/build/targetsTest.props b/build/targetsTest.props index 3bcbc92921..19306fa550 100644 --- a/build/targetsTest.props +++ b/build/targetsTest.props @@ -1,6 +1,6 @@ - net452;net461;net472;netcoreapp2.1 + net452;net461;net472;netcoreapp2.1;net6.0 netcoreapp2.1 diff --git a/build/template-sign-binary.yml b/build/template-sign-binary.yml new file mode 100644 index 0000000000..cf61a57fd6 --- /dev/null +++ b/build/template-sign-binary.yml @@ -0,0 +1,69 @@ +# template-sign-binary.yml +# Signs a binary via ESRP + +parameters: + LibraryName: '' + BuildConfiguration: '' + +steps: +- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 + displayName: 'Sign ${{ parameters.LibraryName }}' + inputs: + ConnectedServiceName: 'IDDP Code Signing' + FolderPath: 'src\${{ parameters.LibraryName }}\bin\${{ parameters.BuildConfiguration }}' + Pattern: ${{ parameters.LibraryName }}.dll + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "MSSharedLibSnKey", + "operationSetCode": "StrongNameSign", + "parameters": null, + "toolName": "sn.exe", + "toolVersion": "V4.6.1586.0" + }, + { + "keyCode": "MSSharedLibSnKey", + "operationSetCode": "StrongNameVerify", + "parameters": null, + "toolName": "sn.exe", + "toolVersion": "V4.6.1586.0" + }, + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolSign", + "parameters": [ + { + "parameterName": "OpusName", + "parameterValue": "TestSign" + }, + { + "parameterName": "OpusInfo", + "parameterValue": "http://test" + }, + { + "parameterName": "PageHash", + "parameterValue": "/NPH" + }, + { + "parameterName": "FileDigest", + "parameterValue": "/fd sha256" + }, + { + "parameterName": "TimeStamp", + "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + } + ], + "toolName": "signtool.exe", + "toolVersion": "6.2.9304.0" + }, + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolVerify", + "parameters": [ ], + "toolName": "signtool.exe", + "toolVersion": "6.2.9304.0" + } + ] + SessionTimeout: 20 + VerboseLogin: true diff --git a/build/template-sign-wilson-6x.yaml b/build/template-sign-wilson-6x.yaml new file mode 100644 index 0000000000..00a1be681d --- /dev/null +++ b/build/template-sign-wilson-6x.yaml @@ -0,0 +1,91 @@ +#template sign-wilson-6x + +parameters: + BuildConfiguration: 'release' + +steps: +- template: template-sign-binary.yml + parameters: + LibraryName: 'System.IdentityModel.Tokens.Jwt' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.JsonWebTokens' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.Logging' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.Protocols' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.Protocols.WsFederation' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.Tokens' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.Tokens.Saml' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.Xml' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.Protocols.OpenIdConnect' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.Protocols.SignedHttpRequest' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.KeyVaultExtensions' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.ManagedKeyVaultSecurityKey' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.Validators' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.Abstractions' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.LoggingExtensions' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- template: template-sign-binary.yml + parameters: + LibraryName: 'Microsoft.IdentityModel.TestExtensions' + BuildConfiguration: ${{ parameters.BuildConfiguration }} + +- task: PowerShell@1 + displayName: 'Verify Signing' + inputs: + scriptName: build/VerifySigning.ps1 + arguments: '-buildType ${{ parameters.BuildConfiguration }}' \ No newline at end of file diff --git a/buildConfiguration.xml b/buildConfiguration.xml index b5620f26ed..007ec93b93 100644 --- a/buildConfiguration.xml +++ b/buildConfiguration.xml @@ -2,7 +2,7 @@ x64 3.5.0-rc-1285 net45,net461,netstandard2.0 - 6.16.1 + 6.20.1 preview @@ -19,6 +19,9 @@ + + + @@ -36,7 +39,7 @@ - + diff --git a/src/Microsoft.IdentityModel.Abstractions/EventLogLevel.cs b/src/Microsoft.IdentityModel.Abstractions/EventLogLevel.cs new file mode 100644 index 0000000000..a23359df53 --- /dev/null +++ b/src/Microsoft.IdentityModel.Abstractions/EventLogLevel.cs @@ -0,0 +1,69 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.IdentityModel.Abstractions +{ + /// + /// Defines Event Log Levels. + /// + public enum EventLogLevel + { + /// + /// No level filtering is done on this log level. Log messages of all levels will be logged. + /// + LogAlways = 0, + + /// + /// Logs that describe an unrecoverable application or system crash, or a catastrophic failure that requires + /// immediate attention. + /// + Critical = 1, + + /// + /// Logs that highlight when the current flow of execution is stopped due to a failure. These should indicate a + /// failure in the current activity, not an application-wide failure. + /// + Error = 2, + + /// + /// Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the + /// application execution to stop. + /// + Warning = 3, + + /// + /// Logs that track the general flow of the application. These logs should have long-term value. + /// + Informational = 4, + + /// + /// Logs that are used for interactive investigation during development. These logs should primarily contain + /// information useful for debugging and have no long-term value. + /// + Verbose = 5 + } +} diff --git a/src/Microsoft.IdentityModel.Abstractions/IIdentityLogger.cs b/src/Microsoft.IdentityModel.Abstractions/IIdentityLogger.cs new file mode 100644 index 0000000000..c915f788d5 --- /dev/null +++ b/src/Microsoft.IdentityModel.Abstractions/IIdentityLogger.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.IdentityModel.Abstractions +{ + /// + /// Interface that needs to be implemented by classes providing logging in Microsoft identity libraries. + /// + public interface IIdentityLogger + { + /// + /// Checks to see if logging is enabled at given . + /// + /// Log level of a message. + bool IsEnabled(EventLogLevel eventLogLevel); + + /// + /// Writes a log entry. + /// + /// Defines a structured message to be logged at the provided . + void Log(LogEntry entry); + } +} diff --git a/src/Microsoft.IdentityModel.Abstractions/ITelemetryClient.cs b/src/Microsoft.IdentityModel.Abstractions/ITelemetryClient.cs new file mode 100644 index 0000000000..b6086bec89 --- /dev/null +++ b/src/Microsoft.IdentityModel.Abstractions/ITelemetryClient.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; + +namespace Microsoft.IdentityModel.Abstractions +{ + /// + /// Interface for Telemetry tracking. + /// + public interface ITelemetryClient + { + /// + /// Gets or sets the application or client ID that telemetry is being sent for. + /// + string ClientId { get; set; } + + /// + /// Perform any necessary bootstrapping for the telemetry client. + /// + /// + /// The expectation is that this should only be called once for the lifetime of the object however the + /// implementation should be idempotent. + /// + void Initialize(); + + /// + /// Checks to see if telemetry is enabled all up. + /// + /// + /// Returns if telemetry should be sent; otherwise. + /// + /// + /// This check should be used to gate any resource intensive operations to generate telemetry as well. + /// + bool IsEnabled(); + + /// + /// Checks to see if telemetry is enabled for the named event. + /// + /// Name of the event to check. + /// + /// Returns if telemetry should be sent for ; + /// otherwise. + /// + /// + /// This check should be used to gate any resource intensive operations to generate telemetry as well. + /// + bool IsEnabled(string eventName); + + /// + /// Tracks an instance of a named event. + /// + /// Details of the event to track. + void TrackEvent( + TelemetryEventDetails eventDetails); + + /// + /// Tracks an instance of a named event. + /// + /// Name of the event to track. Should be unique per scenario. + /// Key value pair of strings to long with the event. + /// Key value pair of longs to long with the event. + /// Key value pair of bools to long with the event. + /// Key value pair of DateTimes to long with the event. + /// Key value pair of doubles to long with the event. + /// Key value pair of Guids to long with the event. + void TrackEvent( + string eventName, + IDictionary stringProperties = null, + IDictionary longProperties = null, + IDictionary boolProperties = null, + IDictionary dateTimeProperties = null, + IDictionary doubleProperties = null, + IDictionary guidProperties = null); + } +} diff --git a/src/Microsoft.IdentityModel.Abstractions/LogEntry.cs b/src/Microsoft.IdentityModel.Abstractions/LogEntry.cs new file mode 100644 index 0000000000..f60726a286 --- /dev/null +++ b/src/Microsoft.IdentityModel.Abstractions/LogEntry.cs @@ -0,0 +1,53 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.IdentityModel.Abstractions +{ + /// + /// Defines the structure of a log entry. + /// + public class LogEntry + { + /// + /// Defines the . + /// + public EventLogLevel EventLogLevel { get; set; } + + /// + /// Message to be logged. + /// + public string Message { get; set; } + + /// + /// A unique identifier for a request that can help with diagnostics across components. + /// + /// + /// Also referred to as ActivityId in Microsoft.IdentityModel.Tokens.CallContext. + /// + public string CorrelationId { get; set; } + } +} diff --git a/src/Microsoft.IdentityModel.Abstractions/Microsoft.IdentityModel.Abstractions.csproj b/src/Microsoft.IdentityModel.Abstractions/Microsoft.IdentityModel.Abstractions.csproj new file mode 100644 index 0000000000..e605b66732 --- /dev/null +++ b/src/Microsoft.IdentityModel.Abstractions/Microsoft.IdentityModel.Abstractions.csproj @@ -0,0 +1,25 @@ + + + + + + Microsoft.IdentityModel.Abstractions + A package containing thin abstractions for Microsoft.IdentityModel. + true + Microsoft.IdentityModel.Abstractions + .NET;Windows;Authentication;Identity;Abstractions + + + + full + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/Microsoft.IdentityModel.Abstractions/NullIdentityModelLogger.cs b/src/Microsoft.IdentityModel.Abstractions/NullIdentityModelLogger.cs new file mode 100644 index 0000000000..9710b8d8d5 --- /dev/null +++ b/src/Microsoft.IdentityModel.Abstractions/NullIdentityModelLogger.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.IdentityModel.Abstractions +{ + /// + /// A minimalistic implementation that is disabled by default and doesn't log. + /// + public sealed class NullIdentityModelLogger : IIdentityLogger + { + /// + /// Default instance of . + /// + public static NullIdentityModelLogger Instance { get; } = new NullIdentityModelLogger(); + + private NullIdentityModelLogger() { } + + /// + public bool IsEnabled(EventLogLevel eventLogLevel) => false; + + /// + public void Log(LogEntry entry) + { + // no-op + } + } +} diff --git a/src/Microsoft.IdentityModel.Abstractions/NullTelemetryClient.cs b/src/Microsoft.IdentityModel.Abstractions/NullTelemetryClient.cs new file mode 100644 index 0000000000..3350d6b56a --- /dev/null +++ b/src/Microsoft.IdentityModel.Abstractions/NullTelemetryClient.cs @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; + +namespace Microsoft.IdentityModel.Abstractions +{ + /// + /// The default implementation of the interface which swallows all telemetry signals. + /// + public class NullTelemetryClient : ITelemetryClient + { + /// + public string ClientId { get; set; } + + /// + /// Singleton instance of . + /// + public static NullTelemetryClient Instance { get; } = new NullTelemetryClient(); + + /// + /// Initializes an instance of . + /// + /// + /// Private constructor to prevent the default constructor being exposed. + /// + private NullTelemetryClient() { } + + /// + public bool IsEnabled() => false; + + /// + public bool IsEnabled(string eventName) => false; + + /// + public void Initialize() + { + // no-op + } + + /// + public void TrackEvent(TelemetryEventDetails eventDetails) + { + // no-op + } + + /// + public void TrackEvent( + string eventName, + IDictionary stringProperties = null, + IDictionary longProperties = null, + IDictionary boolProperties = null, + IDictionary dateTimeProperties = null, + IDictionary doubleProperties = null, + IDictionary guidProperties = null) + { + // no-op + } + } +} diff --git a/src/Microsoft.IdentityModel.Abstractions/ObservabilityConstants.cs b/src/Microsoft.IdentityModel.Abstractions/ObservabilityConstants.cs new file mode 100644 index 0000000000..ef07cc7142 --- /dev/null +++ b/src/Microsoft.IdentityModel.Abstractions/ObservabilityConstants.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.IdentityModel.Abstractions +{ + /// + /// Common class containing observability constants to be used as well known metric keys. + /// + public static class ObservabilityConstants + { + /// + /// String used for the name of the property indicating if the call was successful. + /// + public const string Succeeded = "Succeeded"; + + /// + /// String used for the name of the property indicating the call in Duration (ms). + /// + public const string Duration = "Duration"; + + /// + /// String used for the name of the property indicating the call's Activity Id/Correlation Id. + /// + public const string ActivityId = "ActivityId"; + + /// + /// String used for the name of the property indicating the caller's ClientId. + /// + public const string ClientId = "ClientId"; + } +} diff --git a/src/Microsoft.IdentityModel.Abstractions/Properties/AssemblyInfo.cs b/src/Microsoft.IdentityModel.Abstractions/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..676a61750f --- /dev/null +++ b/src/Microsoft.IdentityModel.Abstractions/Properties/AssemblyInfo.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyInformationalVersion("0.0.1")] +[assembly: AssemblyFileVersion("0.0.1")] +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: AssemblyVersion("0.0.1")] +[assembly: CLSCompliant(true)] +[assembly: ComVisible(false)] diff --git a/src/Microsoft.IdentityModel.Abstractions/TelemetryEventDetails.cs b/src/Microsoft.IdentityModel.Abstractions/TelemetryEventDetails.cs new file mode 100644 index 0000000000..86972aaa39 --- /dev/null +++ b/src/Microsoft.IdentityModel.Abstractions/TelemetryEventDetails.cs @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; + +namespace Microsoft.IdentityModel.Abstractions +{ + /// + /// Details of the telemetry event. + /// + /// + /// This implementation is not meant to be thread-safe. This implementation would either need to be overridden or + /// usage should not be concurrently operated on. + /// + public abstract class TelemetryEventDetails + { + /// + /// The underlying properties making up the . + /// + protected internal IDictionary PropertyValues { get; } = new Dictionary(); + + /// + /// Name of the telemetry event, should be unique between events. + /// + public virtual string Name { get; set; } + + /// + /// Properties which describe the event. + /// + public virtual IReadOnlyDictionary Properties + { + get + { + return (IReadOnlyDictionary)PropertyValues; + } + } + + /// + /// Sets a property on the event details. + /// + /// Property key. + /// Property value. + /// 'key' is null. + public virtual void SetProperty( + string key, + string value) + { + SetPropertyCore(key, value); + } + + /// + /// Sets a property on the event details. + /// + /// Property key. + /// Property value. + /// 'key' is null. + public virtual void SetProperty( + string key, + long value) + { + SetPropertyCore(key, value); + } + + /// + /// Sets a property on the event details. + /// + /// Property key. + /// Property value. + /// 'key' is null. + public virtual void SetProperty( + string key, + bool value) + { + SetPropertyCore(key, value); + } + + /// + /// Sets a property on the event details. + /// + /// Property key. + /// Property value. + /// 'key' is null. + public virtual void SetProperty( + string key, + DateTime value) + { + SetPropertyCore(key, value); + } + + /// + /// Sets a property on the event details. + /// + /// Property key. + /// Property value. + /// 'key' is null. + public virtual void SetProperty( + string key, + double value) + { + SetPropertyCore(key, value); + } + + /// + /// Sets a property on the event details. + /// + /// Property key. + /// Property value. + /// 'key' is null. + public virtual void SetProperty( + string key, + Guid value) + { + SetPropertyCore(key, value); + } + + private void SetPropertyCore( + string key, + object value) + { + if (key == null) + throw new ArgumentNullException(nameof(key)); + + PropertyValues[key] = value; + } + } +} diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/GlobalSuppressions.cs b/src/Microsoft.IdentityModel.JsonWebTokens/GlobalSuppressions.cs index 2b09e611a9..4c9f5ebb89 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/GlobalSuppressions.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/GlobalSuppressions.cs @@ -24,7 +24,8 @@ [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exception is written to a string", Scope = "member", Target = "~M:Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateSignature(System.String,Microsoft.IdentityModel.Tokens.TokenValidationParameters,Microsoft.IdentityModel.Tokens.BaseConfiguration)~Microsoft.IdentityModel.JsonWebTokens.JsonWebToken")] [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exception is returned in the TokenValidationResult", Scope = "member", Target = "~M:Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateJWE(Microsoft.IdentityModel.JsonWebTokens.JsonWebToken,System.String,Microsoft.IdentityModel.Tokens.TokenValidationParameters,Microsoft.IdentityModel.Tokens.BaseConfiguration)~Microsoft.IdentityModel.Tokens.TokenValidationResult")] [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exception is returned in the TokenValidationResult", Scope = "member", Target = "~M:Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateJWS(System.String,Microsoft.IdentityModel.Tokens.TokenValidationParameters,Microsoft.IdentityModel.Tokens.BaseConfiguration)~Microsoft.IdentityModel.Tokens.TokenValidationResult")] -[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exception is written to a string", Scope = "member", Target = "~M:Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateToken(System.String,Microsoft.IdentityModel.JsonWebTokens.JsonWebToken,System.String,Microsoft.IdentityModel.Tokens.TokenValidationParameters)~Microsoft.IdentityModel.Tokens.TokenValidationResult")] -[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exception is written to a string", Scope = "member", Target = "~M:Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.GetConfigurationAndLogError(Microsoft.IdentityModel.Tokens.TokenValidationParameters)~Microsoft.IdentityModel.Tokens.BaseConfiguration")] [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exception is returned in the TokenValidationResult", Scope = "member", Target = "~M:Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateTokenAsync(System.String,Microsoft.IdentityModel.Tokens.TokenValidationParameters)~System.Threading.Tasks.Task{Microsoft.IdentityModel.Tokens.TokenValidationResult}")] [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exception is written to a string", Scope = "member", Target = "~M:Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateTokenAsync(System.String,Microsoft.IdentityModel.JsonWebTokens.JsonWebToken,System.String,Microsoft.IdentityModel.Tokens.TokenValidationParameters)~System.Threading.Tasks.Task{Microsoft.IdentityModel.Tokens.TokenValidationResult}")] +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Vendored component", Scope = "module")] +[assembly: SuppressMessage("Usage", "CA1801:Review unused parameters", Justification = "It is used within a defined if condition", Scope = "member", Target = "~M:Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.GetSecurityKey(Microsoft.IdentityModel.Tokens.EncryptingCredentials,Microsoft.IdentityModel.Tokens.CryptoProviderFactory,System.Collections.Generic.IDictionary{System.String,System.Object},System.Byte[]@)~Microsoft.IdentityModel.Tokens.SecurityKey")] +[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exception is written to a string", Scope = "member", Target = "~M:Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.CreateTokenPrivate(System.String,Microsoft.IdentityModel.Tokens.SigningCredentials,Microsoft.IdentityModel.Tokens.EncryptingCredentials,System.String,System.Collections.Generic.IDictionary{System.String,System.Object},System.Collections.Generic.IDictionary{System.String,System.Object},System.String)~System.String")] diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cd b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cd new file mode 100644 index 0000000000..e5a50696fe --- /dev/null +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cd @@ -0,0 +1,21 @@ + + + + + + + + hAcTICgAAAAMggAEAIQYCAUAAAIwBCCAwKAAYQAQAAA= + JsonWebToken.cs + + + + \ No newline at end of file diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cs index d162f82d94..68db639f91 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cs @@ -331,7 +331,6 @@ public override SecurityKey SigningKey /// the original token. private void Decode(string[] tokenParts, string rawData) { - LogHelper.LogInformation(LogMessages.IDX14106, rawData); try { Header = JObject.Parse(Base64UrlEncoder.Decode(tokenParts[0])); diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs index 3a2bea60a3..5680655f90 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs @@ -65,6 +65,19 @@ public Type TokenType get { return typeof(JsonWebToken); } } + internal static IDictionary AddCtyClaimDefaultValue(IDictionary additionalClaims, bool setDefaultCtyClaim) + { + if (!setDefaultCtyClaim) + return additionalClaims; + + if (additionalClaims == null) + additionalClaims = new Dictionary { { JwtHeaderParameterNames.Cty, JwtConstants.HeaderType } }; + else if (!additionalClaims.TryGetValue(JwtHeaderParameterNames.Cty, out _)) + additionalClaims.Add(JwtHeaderParameterNames.Cty, JwtConstants.HeaderType); + + return additionalClaims; + } + /// /// Determines if the string is a well formed Json Web Token (JWT). /// See: https://datatracker.ietf.org/doc/html/rfc7519 @@ -177,7 +190,7 @@ public virtual string CreateToken(string payload) if (string.IsNullOrEmpty(payload)) throw LogHelper.LogArgumentNullException(nameof(payload)); - return CreateTokenPrivate(JObject.Parse(payload), null, null, null, null, null); + return CreateTokenPrivate(payload, null, null, null, null, null, null); } /// @@ -196,7 +209,7 @@ public virtual string CreateToken(string payload, IDictionary ad if (additionalHeaderClaims == null) throw LogHelper.LogArgumentNullException(nameof(additionalHeaderClaims)); - return CreateTokenPrivate(JObject.Parse(payload), null, null, null, additionalHeaderClaims, null); + return CreateTokenPrivate(payload, null, null, null, additionalHeaderClaims, null, null); } /// @@ -215,7 +228,7 @@ public virtual string CreateToken(string payload, SigningCredentials signingCred if (signingCredentials == null) throw LogHelper.LogArgumentNullException(nameof(signingCredentials)); - return CreateTokenPrivate(JObject.Parse(payload), signingCredentials, null, null, null, null); + return CreateTokenPrivate(payload, signingCredentials, null, null, null, null, null); } /// @@ -242,7 +255,7 @@ public virtual string CreateToken(string payload, SigningCredentials signingCred if (additionalHeaderClaims == null) throw LogHelper.LogArgumentNullException(nameof(additionalHeaderClaims)); - return CreateTokenPrivate(JObject.Parse(payload), signingCredentials, null, null, additionalHeaderClaims, null); + return CreateTokenPrivate(payload, signingCredentials, null, null, additionalHeaderClaims, null, null); } /// @@ -310,7 +323,14 @@ public virtual string CreateToken(SecurityTokenDescriptor tokenDescriptor) payload[JwtRegisteredClaimNames.Nbf] = EpochTime.GetIntDate(tokenDescriptor.NotBefore.Value); } - return CreateTokenPrivate(payload, tokenDescriptor.SigningCredentials, tokenDescriptor.EncryptingCredentials, tokenDescriptor.CompressionAlgorithm, tokenDescriptor.AdditionalHeaderClaims, tokenDescriptor.TokenType); + return CreateTokenPrivate( + payload.ToString(Formatting.None), + tokenDescriptor.SigningCredentials, + tokenDescriptor.EncryptingCredentials, + tokenDescriptor.CompressionAlgorithm, + tokenDescriptor.AdditionalHeaderClaims, + tokenDescriptor.AdditionalInnerHeaderClaims, + tokenDescriptor.TokenType); } /// @@ -327,7 +347,34 @@ public virtual string CreateToken(string payload, EncryptingCredentials encrypti if (encryptingCredentials == null) throw LogHelper.LogArgumentNullException(nameof(encryptingCredentials)); - return CreateTokenPrivate(JObject.Parse(payload), null, encryptingCredentials, null, null, null); + return CreateTokenPrivate(payload, null, encryptingCredentials, null, null, null, null); + } + + /// + /// Creates a JWE (Json Web Encryption). + /// + /// A string containing JSON which represents the JWT token payload. + /// Defines the security key and algorithm that will be used to encrypt the JWT. + /// Defines the dictionary containing any custom header claims that need to be added to the outer JWT token header. + /// if is null. + /// if is null. + /// if is null. + /// if , + /// , , and/or + /// are present inside of . + /// A JWS in Compact Serialization Format. + public virtual string CreateToken(string payload, EncryptingCredentials encryptingCredentials, IDictionary additionalHeaderClaims) + { + if (string.IsNullOrEmpty(payload)) + throw LogHelper.LogArgumentNullException(nameof(payload)); + + if (encryptingCredentials == null) + throw LogHelper.LogArgumentNullException(nameof(encryptingCredentials)); + + if (additionalHeaderClaims == null) + throw LogHelper.LogArgumentNullException(nameof(additionalHeaderClaims)); + + return CreateTokenPrivate(payload, null, encryptingCredentials, null, additionalHeaderClaims, null, null); } /// @@ -351,7 +398,7 @@ public virtual string CreateToken(string payload, SigningCredentials signingCred if (encryptingCredentials == null) throw LogHelper.LogArgumentNullException(nameof(encryptingCredentials)); - return CreateTokenPrivate(JObject.Parse(payload), signingCredentials, encryptingCredentials, null, null, null); + return CreateTokenPrivate(payload, signingCredentials, encryptingCredentials, null, null, null, null); } /// @@ -369,7 +416,11 @@ public virtual string CreateToken(string payload, SigningCredentials signingCred /// , , and/or /// are present inside of . /// A JWE in compact serialization format. - public virtual string CreateToken(string payload, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials, IDictionary additionalHeaderClaims) + public virtual string CreateToken( + string payload, + SigningCredentials signingCredentials, + EncryptingCredentials encryptingCredentials, + IDictionary additionalHeaderClaims) { if (string.IsNullOrEmpty(payload)) throw LogHelper.LogArgumentNullException(nameof(payload)); @@ -383,7 +434,7 @@ public virtual string CreateToken(string payload, SigningCredentials signingCred if (additionalHeaderClaims == null) throw LogHelper.LogArgumentNullException(nameof(additionalHeaderClaims)); - return CreateTokenPrivate(JObject.Parse(payload), signingCredentials, encryptingCredentials, null, additionalHeaderClaims, null); + return CreateTokenPrivate(payload, signingCredentials, encryptingCredentials, null, additionalHeaderClaims, null, null); } /// @@ -404,7 +455,7 @@ public virtual string CreateToken(string payload, EncryptingCredentials encrypti if (string.IsNullOrEmpty(compressionAlgorithm)) throw LogHelper.LogArgumentNullException(nameof(compressionAlgorithm)); - return CreateTokenPrivate(JObject.Parse(payload), null, encryptingCredentials, compressionAlgorithm, null, null); + return CreateTokenPrivate(payload, null, encryptingCredentials, compressionAlgorithm, null, null, null); } /// @@ -433,7 +484,61 @@ public virtual string CreateToken(string payload, SigningCredentials signingCred if (string.IsNullOrEmpty(compressionAlgorithm)) throw LogHelper.LogArgumentNullException(nameof(compressionAlgorithm)); - return CreateTokenPrivate(JObject.Parse(payload), signingCredentials, encryptingCredentials, compressionAlgorithm, null, null); + return CreateTokenPrivate(payload, signingCredentials, encryptingCredentials, compressionAlgorithm, null, null, null); + } + + /// + /// Creates a JWE (Json Web Encryption). + /// + /// A string containing JSON which represents the JWT token payload. + /// Defines the security key and algorithm that will be used to sign the JWT. + /// Defines the security key and algorithm that will be used to encrypt the JWT. + /// Defines the compression algorithm that will be used to compress the JWT token payload. + /// Defines the dictionary containing any custom header claims that need to be added to the outer JWT token header. + /// Defines the dictionary containing any custom header claims that need to be added to the inner JWT token header. + /// if is null. + /// if is null. + /// if is null. + /// if is null. + /// if is null. + /// if , + /// , , and/or + /// are present inside of . + /// A JWE in compact serialization format. + public virtual string CreateToken( + string payload, + SigningCredentials signingCredentials, + EncryptingCredentials encryptingCredentials, + string compressionAlgorithm, + IDictionary additionalHeaderClaims, + IDictionary additionalInnerHeaderClaims) + { + if (string.IsNullOrEmpty(payload)) + throw LogHelper.LogArgumentNullException(nameof(payload)); + + if (signingCredentials == null) + throw LogHelper.LogArgumentNullException(nameof(signingCredentials)); + + if (encryptingCredentials == null) + throw LogHelper.LogArgumentNullException(nameof(encryptingCredentials)); + + if (string.IsNullOrEmpty(compressionAlgorithm)) + throw LogHelper.LogArgumentNullException(nameof(compressionAlgorithm)); + + if (additionalHeaderClaims == null) + throw LogHelper.LogArgumentNullException(nameof(additionalHeaderClaims)); + + if (additionalInnerHeaderClaims == null) + throw LogHelper.LogArgumentNullException(nameof(additionalInnerHeaderClaims)); + + return CreateTokenPrivate( + payload, + signingCredentials, + encryptingCredentials, + compressionAlgorithm, + additionalHeaderClaims, + additionalInnerHeaderClaims, + null); } /// @@ -453,7 +558,12 @@ public virtual string CreateToken(string payload, SigningCredentials signingCred /// , , and/or /// are present inside of . /// A JWE in compact serialization format. - public virtual string CreateToken(string payload, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials, string compressionAlgorithm, IDictionary additionalHeaderClaims) + public virtual string CreateToken( + string payload, + SigningCredentials signingCredentials, + EncryptingCredentials encryptingCredentials, + string compressionAlgorithm, + IDictionary additionalHeaderClaims) { if (string.IsNullOrEmpty(payload)) throw LogHelper.LogArgumentNullException(nameof(payload)); @@ -470,40 +580,69 @@ public virtual string CreateToken(string payload, SigningCredentials signingCred if (additionalHeaderClaims == null) throw LogHelper.LogArgumentNullException(nameof(additionalHeaderClaims)); - return CreateTokenPrivate(JObject.Parse(payload), signingCredentials, encryptingCredentials, compressionAlgorithm, additionalHeaderClaims, null); + return CreateTokenPrivate(payload, signingCredentials, encryptingCredentials, compressionAlgorithm, additionalHeaderClaims, null, null); } - private string CreateTokenPrivate(JObject payload, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials, string compressionAlgorithm, IDictionary additionalHeaderClaims, string tokenType) + private string CreateTokenPrivate( + string payload, + SigningCredentials signingCredentials, + EncryptingCredentials encryptingCredentials, + string compressionAlgorithm, + IDictionary additionalHeaderClaims, + IDictionary additionalInnerHeaderClaims, + string tokenType) { if (additionalHeaderClaims?.Count > 0 && additionalHeaderClaims.Keys.Intersect(JwtTokenUtilities.DefaultHeaderParameters, StringComparer.OrdinalIgnoreCase).Any()) throw LogHelper.LogExceptionMessage(new SecurityTokenException(LogHelper.FormatInvariant(LogMessages.IDX14116, LogHelper.MarkAsNonPII(nameof(additionalHeaderClaims)), LogHelper.MarkAsNonPII(string.Join(", ", JwtTokenUtilities.DefaultHeaderParameters))))); + if (additionalInnerHeaderClaims?.Count > 0 && additionalInnerHeaderClaims.Keys.Intersect(JwtTokenUtilities.DefaultHeaderParameters, StringComparer.OrdinalIgnoreCase).Any()) + throw LogHelper.LogExceptionMessage(new SecurityTokenException(LogHelper.FormatInvariant(LogMessages.IDX14116, nameof(additionalInnerHeaderClaims), string.Join(", ", JwtTokenUtilities.DefaultHeaderParameters)))); + var header = CreateDefaultJWSHeader(signingCredentials, tokenType); if (encryptingCredentials == null && additionalHeaderClaims != null && additionalHeaderClaims.Count > 0) header.Merge(JObject.FromObject(additionalHeaderClaims)); - var rawHeader = Base64UrlEncoder.Encode(Encoding.UTF8.GetBytes(header.ToString(Formatting.None))); + if (additionalInnerHeaderClaims != null && additionalInnerHeaderClaims.Count > 0) + header.Merge(JObject.FromObject(additionalInnerHeaderClaims)); - if (SetDefaultTimesOnTokenCreation) + var rawHeader = Base64UrlEncoder.Encode(Encoding.UTF8.GetBytes(header.ToString(Formatting.None))); + JObject jsonPayload = null; + try { - var now = EpochTime.GetIntDate(DateTime.UtcNow); - if (!payload.TryGetValue(JwtRegisteredClaimNames.Exp, out _)) - payload.Add(JwtRegisteredClaimNames.Exp, now + TokenLifetimeInMinutes * 60); + if (SetDefaultTimesOnTokenCreation) + { + jsonPayload = JObject.Parse(payload); + if (jsonPayload != null) + { + var now = EpochTime.GetIntDate(DateTime.UtcNow); + if (!jsonPayload.TryGetValue(JwtRegisteredClaimNames.Exp, out _)) + jsonPayload.Add(JwtRegisteredClaimNames.Exp, now + TokenLifetimeInMinutes * 60); - if (!payload.TryGetValue(JwtRegisteredClaimNames.Iat, out _)) - payload.Add(JwtRegisteredClaimNames.Iat, now); + if (!jsonPayload.TryGetValue(JwtRegisteredClaimNames.Iat, out _)) + jsonPayload.Add(JwtRegisteredClaimNames.Iat, now); - if (!payload.TryGetValue(JwtRegisteredClaimNames.Nbf, out _)) - payload.Add(JwtRegisteredClaimNames.Nbf, now); + if (!jsonPayload.TryGetValue(JwtRegisteredClaimNames.Nbf, out _)) + jsonPayload.Add(JwtRegisteredClaimNames.Nbf, now); + } + } + } + catch(Exception ex) + { + LogHelper.LogExceptionMessage(new SecurityTokenException(LogHelper.FormatInvariant(LogMessages.IDX14307, ex, payload))); } - var rawPayload = Base64UrlEncoder.Encode(Encoding.UTF8.GetBytes(payload.ToString(Formatting.None))); + payload = jsonPayload != null ? jsonPayload.ToString(Formatting.None) : payload; + var rawPayload = Base64UrlEncoder.Encode(Encoding.UTF8.GetBytes(payload)); var message = rawHeader + "." + rawPayload; var rawSignature = signingCredentials == null ? string.Empty : JwtTokenUtilities.CreateEncodedSignature(message, signingCredentials); if (encryptingCredentials != null) + { + additionalHeaderClaims = AddCtyClaimDefaultValue(additionalHeaderClaims, encryptingCredentials.SetDefaultCtyClaim); + return EncryptTokenPrivate(message + "." + rawSignature, encryptingCredentials, compressionAlgorithm, additionalHeaderClaims, tokenType); + } return message + "." + rawSignature; } @@ -533,6 +672,13 @@ private static byte[] CompressToken(string token, string compressionAlgorithm) return compressionProvider.Compress(Encoding.UTF8.GetBytes(token)) ?? throw LogHelper.LogExceptionMessage(new InvalidOperationException(LogHelper.FormatInvariant(TokenLogMessages.IDX10680, LogHelper.MarkAsNonPII(compressionAlgorithm)))); } + private static StringComparison GetStringComparisonRuleIf509(SecurityKey securityKey) => (securityKey is X509SecurityKey) + ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; + + private static StringComparison GetStringComparisonRuleIf509OrECDsa(SecurityKey securityKey) => (securityKey is X509SecurityKey + || securityKey is ECDsaSecurityKey) + ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; + /// /// Creates a from a . /// @@ -755,7 +901,7 @@ private static string EncryptTokenPrivate(string innerJwt, EncryptingCredentials throw LogHelper.LogExceptionMessage(new ArgumentException(TokenLogMessages.IDX10620)); byte[] wrappedKey = null; - SecurityKey securityKey = JwtTokenUtilities.GetSecurityKey(encryptingCredentials, cryptoProviderFactory, out wrappedKey); + SecurityKey securityKey = JwtTokenUtilities.GetSecurityKey(encryptingCredentials, cryptoProviderFactory, additionalHeaderClaims, out wrappedKey); using (var encryptionProvider = cryptoProviderFactory.CreateAuthenticatedEncryptionProvider(securityKey, encryptingCredentials.Enc)) { @@ -763,7 +909,6 @@ private static string EncryptTokenPrivate(string innerJwt, EncryptingCredentials throw LogHelper.LogExceptionMessage(new SecurityTokenEncryptionFailedException(LogMessages.IDX14103)); var header = CreateDefaultJWEHeader(encryptingCredentials, compressionAlgorithm, tokenType); - if (additionalHeaderClaims != null) header.Merge(JObject.FromObject(additionalHeaderClaims)); @@ -788,7 +933,7 @@ private static string EncryptTokenPrivate(string innerJwt, EncryptingCredentials { var rawHeader = Base64UrlEncoder.Encode(Encoding.UTF8.GetBytes(header.ToString(Formatting.None))); var encryptionResult = encryptionProvider.Encrypt(plainText, Encoding.ASCII.GetBytes(rawHeader)); - return JwtConstants.DirectKeyUseAlg.Equals(encryptingCredentials.Alg, StringComparison.Ordinal) ? + return JwtConstants.DirectKeyUseAlg.Equals(encryptingCredentials.Alg) ? string.Join(".", rawHeader, string.Empty, Base64UrlEncoder.Encode(encryptionResult.IV), Base64UrlEncoder.Encode(encryptionResult.Ciphertext), Base64UrlEncoder.Encode(encryptionResult.AuthenticationTag)): string.Join(".", rawHeader, Base64UrlEncoder.Encode(wrappedKey), Base64UrlEncoder.Encode(encryptionResult.IV), Base64UrlEncoder.Encode(encryptionResult.Ciphertext), Base64UrlEncoder.Encode(encryptionResult.AuthenticationTag)); } @@ -812,6 +957,9 @@ internal IEnumerable GetContentEncryptionKeys(JsonWebToken jwtToken keys = new List { key }; } + // on decryption for ECDH-ES, we get the public key from the EPK value see: https://datatracker.ietf.org/doc/html/rfc7518#appendix-C + // we need the ECDSASecurityKey for the receiver, use TokenValidationParameters.TokenDecryptionKey + // control gets here if: // 1. User specified delegate: TokenDecryptionKeyResolver returned null // 2. ResolveTokenDecryptionKey returned null @@ -819,7 +967,8 @@ internal IEnumerable GetContentEncryptionKeys(JsonWebToken jwtToken if (keys == null) keys = JwtTokenUtilities.GetAllDecryptionKeys(validationParameters); - if (jwtToken.Alg.Equals(JwtConstants.DirectKeyUseAlg, StringComparison.Ordinal)) + if (jwtToken.Alg.Equals(JwtConstants.DirectKeyUseAlg, StringComparison.Ordinal) + || jwtToken.Alg.Equals(SecurityAlgorithms.EcdhEs, StringComparison.Ordinal)) return keys; var unwrappedKeys = new List(); @@ -830,6 +979,24 @@ internal IEnumerable GetContentEncryptionKeys(JsonWebToken jwtToken { try { +#if NET472 || NET6_0 + if (SupportedAlgorithms.EcdsaWrapAlgorithms.Contains(jwtToken.Alg)) + { + //// on decryption we get the public key from the EPK value see: https://datatracker.ietf.org/doc/html/rfc7518#appendix-C + var ecdhKeyExchangeProvider = new EcdhKeyExchangeProvider( + key as ECDsaSecurityKey, + validationParameters.TokenDecryptionKey as ECDsaSecurityKey, + jwtToken.Alg, + jwtToken.Enc); + jwtToken.TryGetHeaderValue(JwtHeaderParameterNames.Apu, out string apu); + jwtToken.TryGetHeaderValue(JwtHeaderParameterNames.Apv, out string apv); + SecurityKey kdf = ecdhKeyExchangeProvider.GenerateKdf(apu, apv); + var kwp = key.CryptoProviderFactory.CreateKeyWrapProviderForUnwrap(kdf, ecdhKeyExchangeProvider.GetEncryptionAlgorithm()); + var unwrappedKey = kwp.UnwrapKey(Base64UrlEncoder.DecodeBytes(jwtToken.EncryptedKey)); + unwrappedKeys.Add(new SymmetricSecurityKey(unwrappedKey)); + } + else +#endif if (key.CryptoProviderFactory.IsSupportedAlgorithm(jwtToken.Alg, key)) { var kwp = key.CryptoProviderFactory.CreateKeyWrapProviderForUnwrap(key, jwtToken.Alg); @@ -866,17 +1033,18 @@ protected virtual SecurityKey ResolveTokenDecryptionKey(string token, JsonWebTok if (validationParameters == null) throw LogHelper.LogArgumentNullException(nameof(validationParameters)); + StringComparison stringComparison = GetStringComparisonRuleIf509OrECDsa(validationParameters.TokenDecryptionKey); if (!string.IsNullOrEmpty(jwtToken.Kid)) { if (validationParameters.TokenDecryptionKey != null - && string.Equals(validationParameters.TokenDecryptionKey.KeyId, jwtToken.Kid, validationParameters.TokenDecryptionKey is X509SecurityKey ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) + && string.Equals(validationParameters.TokenDecryptionKey.KeyId, jwtToken.Kid, stringComparison)) return validationParameters.TokenDecryptionKey; if (validationParameters.TokenDecryptionKeys != null) { foreach (var key in validationParameters.TokenDecryptionKeys) { - if (key != null && string.Equals(key.KeyId, jwtToken.Kid, key is X509SecurityKey ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) + if (key != null && string.Equals(key.KeyId, jwtToken.Kid, GetStringComparisonRuleIf509OrECDsa(key))) return key; } } @@ -886,7 +1054,7 @@ protected virtual SecurityKey ResolveTokenDecryptionKey(string token, JsonWebTok { if (validationParameters.TokenDecryptionKey != null) { - if (string.Equals(validationParameters.TokenDecryptionKey.KeyId, jwtToken.X5t, validationParameters.TokenDecryptionKey is X509SecurityKey ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) + if (string.Equals(validationParameters.TokenDecryptionKey.KeyId, jwtToken.X5t, stringComparison)) return validationParameters.TokenDecryptionKey; var x509Key = validationParameters.TokenDecryptionKey as X509SecurityKey; @@ -898,7 +1066,7 @@ protected virtual SecurityKey ResolveTokenDecryptionKey(string token, JsonWebTok { foreach (var key in validationParameters.TokenDecryptionKeys) { - if (key != null && string.Equals(key.KeyId, jwtToken.X5t, key is X509SecurityKey ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) + if (key != null && string.Equals(key.KeyId, jwtToken.X5t, GetStringComparisonRuleIf509(key))) return key; var x509Key = key as X509SecurityKey; @@ -907,6 +1075,7 @@ protected virtual SecurityKey ResolveTokenDecryptionKey(string token, JsonWebTok } } } + return null; } @@ -1058,7 +1227,7 @@ private async Task ValidateTokenAsync(string token, JsonW // Only try to re-validate using the newly obtained config if it doesn't reference equal the previously used configuration. if (lastConfig != currentConfiguration) - return decryptedJwt != null ? ValidateJWE(outerToken, decryptedJwt, validationParameters, currentConfiguration) : ValidateJWS(token, validationParameters, currentConfiguration); ; + return decryptedJwt != null ? ValidateJWE(outerToken, decryptedJwt, validationParameters, currentConfiguration) : ValidateJWS(token, validationParameters, currentConfiguration); } } } @@ -1285,7 +1454,7 @@ private static JsonWebToken ValidateSignature(string token, TokenValidationParam { if (kidMatched) { - var isKidInTVP = keysInTokenValidationParameters.Any(x => x.KeyId.Equals(jwtToken.Kid, StringComparison.Ordinal)); + var isKidInTVP = keysInTokenValidationParameters.Any(x => x.KeyId.Equals(jwtToken.Kid)); var keyLocation = isKidInTVP ? "TokenValidationParameters" : "Configuration"; throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSignatureException( LogHelper.FormatInvariant(TokenLogMessages.IDX10511, diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JwtHeaderParameterNames.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JwtHeaderParameterNames.cs index 01f58b747d..f23f335540 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JwtHeaderParameterNames.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JwtHeaderParameterNames.cs @@ -93,5 +93,20 @@ public struct JwtHeaderParameterNames /// See: https://datatracker.ietf.org/doc/html/rfc7516#section-4.1.3 /// public const string Zip = "zip"; + + /// + /// See: https://datatracker.ietf.org/doc/html/rfc7518#section-4.6.1.1 + /// + public const string Epk = "epk"; + + /// + /// See: https://datatracker.ietf.org/doc/html/rfc7518#section-4.6.1.2 + /// + public const string Apu = "apu"; + + /// + /// See: https://datatracker.ietf.org/doc/html/rfc7518#section-4.6.1.3 + /// + public const string Apv = "apv"; } } diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs index 7bb0d94b3f..4213b415a9 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs @@ -49,7 +49,7 @@ public class JwtTokenUtilities /// Regex that is used to figure out if a token is in JWS format. /// public static Regex RegexJws = new Regex(JwtConstants.JsonCompactSerializationRegex, RegexOptions.Compiled | RegexOptions.CultureInvariant, TimeSpan.FromMilliseconds(100)); - + /// /// Regex that is used to figure out if a token is in JWE format. /// @@ -200,6 +200,10 @@ internal static string DecryptJwtToken( { Validators.ValidateAlgorithm(decryptionParameters.Enc, key, jwtToken, validationParameters); decryptedTokenBytes = DecryptToken(cryptoProviderFactory, key, decryptionParameters); + X509SecurityKey x509Key = key as X509SecurityKey; + if (x509Key != null) + LogHelper.LogInformation(TokenLogMessages.IDX10903, x509Key.Certificate?.Thumbprint); + decryptionSucceeded = true; break; } @@ -278,32 +282,68 @@ public static byte[] GenerateKeyBytes(int sizeInBits) return key; } - internal static SecurityKey GetSecurityKey(EncryptingCredentials encryptingCredentials, CryptoProviderFactory cryptoProviderFactory, out byte[] wrappedKey) + internal static SecurityKey GetSecurityKey( + EncryptingCredentials encryptingCredentials, + CryptoProviderFactory cryptoProviderFactory, + IDictionary additionalHeaderClaims, + out byte[] wrappedKey) { SecurityKey securityKey = null; KeyWrapProvider kwProvider = null; wrappedKey = null; // if direct algorithm, look for support - if (JwtConstants.DirectKeyUseAlg.Equals(encryptingCredentials.Alg, StringComparison.Ordinal)) + if (JwtConstants.DirectKeyUseAlg.Equals(encryptingCredentials.Alg)) { if (!cryptoProviderFactory.IsSupportedAlgorithm(encryptingCredentials.Enc, encryptingCredentials.Key)) throw LogHelper.LogExceptionMessage(new SecurityTokenEncryptionFailedException(LogHelper.FormatInvariant(TokenLogMessages.IDX10615, LogHelper.MarkAsNonPII(encryptingCredentials.Enc), encryptingCredentials.Key))); securityKey = encryptingCredentials.Key; } +#if NET472 || NET6_0 + else if (SupportedAlgorithms.EcdsaWrapAlgorithms.Contains(encryptingCredentials.Alg)) + { + // on decryption we get the public key from the EPK value see: https://datatracker.ietf.org/doc/html/rfc7518#appendix-C + string apu = null, apv = null; + if (additionalHeaderClaims != null && additionalHeaderClaims.Count > 0) + { + if (additionalHeaderClaims.TryGetValue(JwtHeaderParameterNames.Apu, out object objApu)) + apu = objApu?.ToString(); + + if (additionalHeaderClaims.TryGetValue(JwtHeaderParameterNames.Apv, out object objApv)) + apv = objApv?.ToString(); + } + + EcdhKeyExchangeProvider ecdhKeyExchangeProvider = new EcdhKeyExchangeProvider(encryptingCredentials.Key as ECDsaSecurityKey, encryptingCredentials.KeyExchangePublicKey, encryptingCredentials.Alg, encryptingCredentials.Enc); + SecurityKey kdf = ecdhKeyExchangeProvider.GenerateKdf(apu, apv); + kwProvider = cryptoProviderFactory.CreateKeyWrapProvider(kdf, ecdhKeyExchangeProvider.GetEncryptionAlgorithm()); + + // only 128, 384 and 512 AesKeyWrap for CEK algorithm + if (SecurityAlgorithms.Aes128KW.Equals(kwProvider.Algorithm, StringComparison.Ordinal)) + securityKey = new SymmetricSecurityKey(GenerateKeyBytes(256)); + else if (SecurityAlgorithms.Aes192KW.Equals(kwProvider.Algorithm, StringComparison.Ordinal)) + securityKey = new SymmetricSecurityKey(GenerateKeyBytes(384)); + else if (SecurityAlgorithms.Aes256KW.Equals(kwProvider.Algorithm, StringComparison.Ordinal)) + securityKey = new SymmetricSecurityKey(GenerateKeyBytes(512)); + else + throw LogHelper.LogExceptionMessage( + new SecurityTokenEncryptionFailedException(LogHelper.FormatInvariant(TokenLogMessages.IDX10617, LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes128KW), LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes192KW), LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes256KW), LogHelper.MarkAsNonPII(kwProvider.Algorithm)))); + + wrappedKey = kwProvider.WrapKey(((SymmetricSecurityKey)securityKey).Key); + } +#endif else { if (!cryptoProviderFactory.IsSupportedAlgorithm(encryptingCredentials.Alg, encryptingCredentials.Key)) throw LogHelper.LogExceptionMessage(new SecurityTokenEncryptionFailedException(LogHelper.FormatInvariant(TokenLogMessages.IDX10615, LogHelper.MarkAsNonPII(encryptingCredentials.Alg), encryptingCredentials.Key))); // only 128, 384 and 512 AesCbcHmac for CEK algorithm - if (SecurityAlgorithms.Aes128CbcHmacSha256.Equals(encryptingCredentials.Enc, StringComparison.Ordinal)) - securityKey = new SymmetricSecurityKey(JwtTokenUtilities.GenerateKeyBytes(256)); - else if (SecurityAlgorithms.Aes192CbcHmacSha384.Equals(encryptingCredentials.Enc, StringComparison.Ordinal)) - securityKey = new SymmetricSecurityKey(JwtTokenUtilities.GenerateKeyBytes(384)); - else if (SecurityAlgorithms.Aes256CbcHmacSha512.Equals(encryptingCredentials.Enc, StringComparison.Ordinal)) - securityKey = new SymmetricSecurityKey(JwtTokenUtilities.GenerateKeyBytes(512)); + if (SecurityAlgorithms.Aes128CbcHmacSha256.Equals(encryptingCredentials.Enc)) + securityKey = new SymmetricSecurityKey(GenerateKeyBytes(256)); + else if (SecurityAlgorithms.Aes192CbcHmacSha384.Equals(encryptingCredentials.Enc)) + securityKey = new SymmetricSecurityKey(GenerateKeyBytes(384)); + else if (SecurityAlgorithms.Aes256CbcHmacSha512.Equals(encryptingCredentials.Enc)) + securityKey = new SymmetricSecurityKey(GenerateKeyBytes(512)); else throw LogHelper.LogExceptionMessage( new SecurityTokenEncryptionFailedException(LogHelper.FormatInvariant(TokenLogMessages.IDX10617, LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes128CbcHmacSha256), LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes192CbcHmacSha384), LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes256CbcHmacSha512), LogHelper.MarkAsNonPII(encryptingCredentials.Enc)))); @@ -401,7 +441,7 @@ internal static SecurityKey ResolveTokenSigningKey(string kid, string x5t, Token { foreach (SecurityKey signingKey in configuration.SigningKeys) { - if (signingKey != null && string.Equals(signingKey.KeyId, x5t, StringComparison.Ordinal)) + if (signingKey != null && string.Equals(signingKey.KeyId, x5t)) return signingKey; } } @@ -420,7 +460,7 @@ internal static SecurityKey ResolveTokenSigningKey(string kid, string x5t, Token internal static SecurityKey ResolveTokenSigningKey(string kid, string x5t, TokenValidationParameters validationParameters) { if (!string.IsNullOrEmpty(kid)) - { + { if (validationParameters.IssuerSigningKey != null && string.Equals(validationParameters.IssuerSigningKey.KeyId, kid, validationParameters.IssuerSigningKey is X509SecurityKey ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) return validationParameters.IssuerSigningKey; @@ -453,7 +493,7 @@ internal static SecurityKey ResolveTokenSigningKey(string kid, string x5t, Token { foreach (SecurityKey signingKey in validationParameters.IssuerSigningKeys) { - if (signingKey != null && string.Equals(signingKey.KeyId, x5t, StringComparison.Ordinal)) + if (signingKey != null && string.Equals(signingKey.KeyId, x5t)) { return signingKey; } diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/LogMessages.cs b/src/Microsoft.IdentityModel.JsonWebTokens/LogMessages.cs index 9862078d70..04293daf8e 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/LogMessages.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/LogMessages.cs @@ -46,7 +46,7 @@ internal static class LogMessages internal const string IDX14102 = "IDX14102: Unable to decode the header '{0}' as Base64Url encoded string. jwtEncodedString: '{1}'."; internal const string IDX14103 = "IDX14103: Failed to create the token encryption provider."; internal const string IDX14105 = "IDX14105: Header.Cty != null, assuming JWS. Cty: '{0}'."; - internal const string IDX14106 = "IDX14106: Decoding token: '{0}' into header, payload and signature."; + // internal const string IDX14106 = "IDX14106:"; internal const string IDX14107 = "IDX14107: Token string does not match the token formats: JWE (header.encryptedKey.iv.ciphertext.tag) or JWS (header.payload.signature)"; internal const string IDX14111 = "IDX14111: JWT: '{0}' must have three segments (JWS) or five segments (JWE)."; internal const string IDX14112 = "IDX14112: Only a single 'Actor' is supported. Found second claim of type: '{0}', value: '{1}'"; @@ -67,6 +67,7 @@ internal static class LogMessages internal const string IDX14304 = "IDX14304: Claim with name '{0}' does not exist in the payload."; internal const string IDX14305 = "IDX14305: Unable to convert the '{0}' claim to the following type: '{1}'. Claim type was: '{2}'."; internal const string IDX14306 = "IDX14306: JWE Ciphertext cannot be an empty string."; + internal const string IDX14307 = "IDX14307: An exception has been caught while parsing the payload. Exception: {0}, Payload: {1}"; #pragma warning restore 1591 } } diff --git a/src/Microsoft.IdentityModel.KeyVaultExtensions/Microsoft.IdentityModel.KeyVaultExtensions.csproj b/src/Microsoft.IdentityModel.KeyVaultExtensions/Microsoft.IdentityModel.KeyVaultExtensions.csproj index ffad76f767..79dfe9e428 100644 --- a/src/Microsoft.IdentityModel.KeyVaultExtensions/Microsoft.IdentityModel.KeyVaultExtensions.csproj +++ b/src/Microsoft.IdentityModel.KeyVaultExtensions/Microsoft.IdentityModel.KeyVaultExtensions.csproj @@ -8,8 +8,8 @@ true latest Microsoft.IdentityModel.KeyVaultExtensions - net452;netstandard2.0 - netstandard2.0 + net452;netstandard2.0;net6.0 + netstandard2.0;net6.0 .NET;Windows;Authentication;Identity;Azure;Key;Vault;Extensions @@ -24,6 +24,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Microsoft.IdentityModel.Logging/GlobalSuppressions.cs b/src/Microsoft.IdentityModel.Logging/GlobalSuppressions.cs index c544c4d70c..dbc50a6607 100644 --- a/src/Microsoft.IdentityModel.Logging/GlobalSuppressions.cs +++ b/src/Microsoft.IdentityModel.Logging/GlobalSuppressions.cs @@ -7,3 +7,4 @@ [assembly: SuppressMessage("Design", "CA1052:Static holder types should be Static or NotInheritable", Justification = "Previously released as non-static / inheritable", Scope = "type", Target = "~T:Microsoft.IdentityModel.Logging.LogHelper")] [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Execution should not be altered for exceptions on format", Scope = "member", Target = "~M:Microsoft.IdentityModel.Logging.IdentityModelEventSource.PrepareMessage(System.Diagnostics.Tracing.EventLevel,System.String,System.Object[])~System.String")] +[assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Breaking change", Scope = "member", Target = "~P:Microsoft.IdentityModel.Logging.LoggerContext.PropertyBag")] diff --git a/src/Microsoft.IdentityModel.Logging/IdentityModelTelemetryUtil.cs b/src/Microsoft.IdentityModel.Logging/IdentityModelTelemetryUtil.cs index 04fca859cf..ac07417efc 100644 --- a/src/Microsoft.IdentityModel.Logging/IdentityModelTelemetryUtil.cs +++ b/src/Microsoft.IdentityModel.Logging/IdentityModelTelemetryUtil.cs @@ -59,6 +59,8 @@ public static class IdentityModelTelemetryUtil "ID_NET472"; #elif NETSTANDARD2_0 "ID_NETSTANDARD2_0"; +#elif NET6_0 + "ID_NET6_0"; #endif /// diff --git a/src/Microsoft.IdentityModel.Logging/LogHelper.cs b/src/Microsoft.IdentityModel.Logging/LogHelper.cs index 474e5a1434..ef0af25ba2 100644 --- a/src/Microsoft.IdentityModel.Logging/LogHelper.cs +++ b/src/Microsoft.IdentityModel.Logging/LogHelper.cs @@ -29,6 +29,7 @@ using System.Diagnostics.Tracing; using System.Globalization; using System.Linq; +using Microsoft.IdentityModel.Abstractions; namespace Microsoft.IdentityModel.Logging { @@ -37,6 +38,26 @@ namespace Microsoft.IdentityModel.Logging /// public class LogHelper { + /// + /// Gets or sets a logger to which logs will be written to. + /// + public static IIdentityLogger Logger { get; set; } = NullIdentityModelLogger.Instance; + + /// + /// Indicates whether the log message header (contains library version, date/time, and PII debugging information) has been written. + /// + private static bool _isHeaderWritten = false; + + /// + /// The log message that is shown when PII is off. + /// + private static string _piiOffLogMessage = "PII logging is OFF. See https://aka.ms/IdentityModel/PII for details. "; + + /// + /// The log message that is shown when PII is on. + /// + private static string _piiOnLogMessage = "PII logging is ON, do not use in production. See https://aka.ms/IdentityModel/PII for details. "; + /// /// Logs an exception using the event source logger and returns new exception. /// @@ -44,7 +65,7 @@ public class LogHelper /// EventLevel is set to Error. public static ArgumentNullException LogArgumentNullException(string argument) { - return LogArgumentException(EventLevel.Error, argument, "IDX10000: The parameter '{0}' cannot be a 'null' or an empty object.", argument); + return LogArgumentException(EventLevel.Error, argument, "IDX10000: The parameter '{0}' cannot be a 'null' or an empty object. ", argument); } /// @@ -254,6 +275,10 @@ public static Exception LogExceptionMessage(EventLevel eventLevel, Exception exc if (IdentityModelEventSource.Logger.IsEnabled() && IdentityModelEventSource.Logger.LogLevel >= eventLevel) IdentityModelEventSource.Logger.Write(eventLevel, exception.InnerException, exception.Message); + EventLogLevel eventLogLevel = Enum.IsDefined(typeof(EventLogLevel), (int)eventLevel) ? (EventLogLevel)eventLevel : EventLogLevel.Error; + if (Logger.IsEnabled(eventLogLevel)) + Logger.Log(WriteEntry((EventLogLevel)eventLevel, exception.InnerException, exception.Message, null)); + return exception; } @@ -264,8 +289,11 @@ public static Exception LogExceptionMessage(EventLevel eventLevel, Exception exc /// An object array that contains zero or more objects to format. public static void LogInformation(string message, params object[] args) { - if (IdentityModelEventSource.Logger.IsEnabled()) + if (IdentityModelEventSource.Logger.IsEnabled() && IdentityModelEventSource.Logger.LogLevel >= EventLevel.Informational) IdentityModelEventSource.Logger.WriteInformation(message, args); + + if (Enum.IsDefined(typeof(EventLogLevel), (int)EventLevel.Informational) && Logger.IsEnabled((EventLogLevel)EventLevel.Informational)) + Logger.Log(WriteEntry((EventLogLevel)EventLevel.Informational, null, message, args)); } /// @@ -277,6 +305,9 @@ public static void LogVerbose(string message, params object[] args) { if (IdentityModelEventSource.Logger.IsEnabled()) IdentityModelEventSource.Logger.WriteVerbose(message, args); + + if (Enum.IsDefined(typeof(EventLogLevel), (int)EventLevel.Verbose) && Logger.IsEnabled((EventLogLevel)EventLevel.Verbose)) + Logger.Log(WriteEntry((EventLogLevel)EventLevel.Verbose, null, message, args)); } /// @@ -288,6 +319,9 @@ public static void LogWarning(string message, params object[] args) { if (IdentityModelEventSource.Logger.IsEnabled()) IdentityModelEventSource.Logger.WriteWarning(message, args); + + if (Enum.IsDefined(typeof(EventLogLevel), (int)EventLevel.Warning) && Logger.IsEnabled((EventLogLevel)EventLevel.Warning)) + Logger.Log(WriteEntry((EventLogLevel)EventLevel.Warning, null, message, args)); } /// @@ -310,6 +344,10 @@ private static T LogExceptionImpl(EventLevel eventLevel, string argumentName, if (IdentityModelEventSource.Logger.IsEnabled() && IdentityModelEventSource.Logger.LogLevel >= eventLevel) IdentityModelEventSource.Logger.Write(eventLevel, innerException, message); + EventLogLevel eventLogLevel = Enum.IsDefined(typeof(EventLogLevel), (int)eventLevel) ? (EventLogLevel)eventLevel : EventLogLevel.Error; + if (Logger.IsEnabled(eventLogLevel)) + Logger.Log(WriteEntry((EventLogLevel)eventLevel, innerException, message, null)); + if (innerException != null) if (string.IsNullOrEmpty(argumentName)) return (T)Activator.CreateInstance(typeof(T), message, innerException); @@ -371,5 +409,53 @@ public static object MarkAsNonPII(object arg) { return new NonPII(arg); } + + /// + /// Creates a by using the provided event level, exception argument, string argument and arguments list. + /// + /// + /// + /// The log message. + /// An object array that contains zero or more objects to format. + private static LogEntry WriteEntry(EventLogLevel eventLogLevel, Exception innerException, string message, params object[] args) + { + if (string.IsNullOrEmpty(message)) + return null; + + if (innerException != null) + { + // if PII is turned off and 'innerException' is a System exception only display the exception type + if (!IdentityModelEventSource.ShowPII && !LogHelper.IsCustomException(innerException)) + message = string.Format(CultureInfo.InvariantCulture, "Message: {0}, InnerException: {1}. ", message, innerException.GetType()); + else // otherwise it's safe to display the entire exception message + message = string.Format(CultureInfo.InvariantCulture, "Message: {0}, InnerException: {1}. ", message, innerException.Message); + } + + message = args == null ? message : FormatInvariant(message, args); + + // Logs basic information (library version, DateTime, whether PII is ON/OFF) once before any log messages are written. + if (!_isHeaderWritten) + { + string headerMessage = string.Format( + CultureInfo.InvariantCulture, + "Microsoft.IdentityModel Version: {0}. Date {1}. {2}", + typeof(IdentityModelEventSource).Assembly.GetName().Version.ToString(), + DateTime.UtcNow, + IdentityModelEventSource.ShowPII ? _piiOnLogMessage : _piiOffLogMessage); + + LogEntry headerEntry = new LogEntry(); + headerEntry.EventLogLevel = EventLogLevel.LogAlways; + headerEntry.Message = headerMessage; + Logger.Log(headerEntry); + + _isHeaderWritten = true; + } + + LogEntry entry = new LogEntry(); + entry.EventLogLevel = eventLogLevel; + entry.Message = message; + + return entry; + } } } diff --git a/src/Microsoft.IdentityModel.Logging/LoggerContext.cs b/src/Microsoft.IdentityModel.Logging/LoggerContext.cs new file mode 100644 index 0000000000..24d015e1a2 --- /dev/null +++ b/src/Microsoft.IdentityModel.Logging/LoggerContext.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Microsoft.IdentityModel.Logging +{ + /// + /// A context class that can be used to store work per request to aid with debugging. + /// + public class LoggerContext + { + /// + /// Instantiates a new with the default activityId. + /// + public LoggerContext() + { + } + + /// + /// Instantiates a new with an activityId. + /// + /// + public LoggerContext(Guid activityId) + { + ActivityId = activityId; + } + + /// + /// Gets or set a that will be used in the call to EventSource.SetCurrentThreadActivityId before logging. + /// + public Guid ActivityId { get; set; } = Guid.Empty; + + /// + /// Gets or sets a boolean controlling if logs are written into the context. + /// Useful when debugging. + /// + public bool CaptureLogs { get; set; } = false; + + /// + /// Gets or sets a string that helps with setting breakpoints when debugging. + /// + public virtual string DebugId { get; set; } = string.Empty; + + /// + /// The collection of logs associated with a request. Use to control capture. + /// + public ICollection Logs { get; private set; } = new Collection(); + + /// + /// Gets or sets an that enables custom extensibility scenarios. + /// + public IDictionary PropertyBag { get; set; } + } +} diff --git a/src/Microsoft.IdentityModel.Logging/Microsoft.IdentityModel.Logging.csproj b/src/Microsoft.IdentityModel.Logging/Microsoft.IdentityModel.Logging.csproj index 5c9a54d36a..7d92669e5d 100644 --- a/src/Microsoft.IdentityModel.Logging/Microsoft.IdentityModel.Logging.csproj +++ b/src/Microsoft.IdentityModel.Logging/Microsoft.IdentityModel.Logging.csproj @@ -26,4 +26,8 @@ + + + + diff --git a/src/Microsoft.IdentityModel.LoggingExtensions/IdentityLoggerAdapter.cs b/src/Microsoft.IdentityModel.LoggingExtensions/IdentityLoggerAdapter.cs new file mode 100644 index 0000000000..229d82ea09 --- /dev/null +++ b/src/Microsoft.IdentityModel.LoggingExtensions/IdentityLoggerAdapter.cs @@ -0,0 +1,116 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//------------------------------------------------------------------------------ + +using System; +using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Abstractions; + +namespace Microsoft.IdentityModel.LoggingExtensions +{ + /// + /// The default implementation of that provides a wrapper around instance. + /// + public class IdentityLoggerAdapter : IIdentityLogger + { + private readonly ILogger _logger; + + /// + /// Instantiates using . + /// + /// An instance to which identity log messages are written. + +#pragma warning disable CS3001 // Argument type is not CLS-compliant + public IdentityLoggerAdapter(ILogger logger) +#pragma warning restore CS3001 // Argument type is not CLS-compliant + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + public bool IsEnabled(EventLogLevel eventLogLevel) + { + return _logger.IsEnabled(ConvertToLogLevel(eventLogLevel)); + } + + /// + public void Log(LogEntry entry) + { + if (entry != null) + { + switch (entry.EventLogLevel) + { + case EventLogLevel.Critical: + case EventLogLevel.LogAlways: + _logger.LogCritical(entry.Message); + break; + + case EventLogLevel.Error: + _logger.LogError(entry.Message); + break; + + case EventLogLevel.Warning: + _logger.LogWarning(entry.Message); + break; + + case EventLogLevel.Informational: + _logger.LogInformation(entry.Message); + break; + + case EventLogLevel.Verbose: + _logger.LogDebug(entry.Message); + break; + + default: + break; + } + } + } + + private static LogLevel ConvertToLogLevel(EventLogLevel eventLogLevel) + { + switch (eventLogLevel) + { + case EventLogLevel.Critical: + case EventLogLevel.LogAlways: + return LogLevel.Critical; + + case EventLogLevel.Error: + return LogLevel.Error; + + case EventLogLevel.Warning: + return LogLevel.Warning; + + case EventLogLevel.Informational: + return LogLevel.Information; + + case EventLogLevel.Verbose: + default: + return LogLevel.Debug; + } + } + } +} diff --git a/src/Microsoft.IdentityModel.LoggingExtensions/Microsoft.IdentityModel.LoggingExtensions.csproj b/src/Microsoft.IdentityModel.LoggingExtensions/Microsoft.IdentityModel.LoggingExtensions.csproj new file mode 100644 index 0000000000..81381568c4 --- /dev/null +++ b/src/Microsoft.IdentityModel.LoggingExtensions/Microsoft.IdentityModel.LoggingExtensions.csproj @@ -0,0 +1,34 @@ + + + + + + Microsoft.IdentityModel.LoggingExtensions + A package containing logging extensions to support writing Identity logs to Microsoft.Extensions.Logging.ILogger. + true + Microsoft.IdentityModel.LoggingExtensions + .NET;Windows;Authentication;Identity;Extensions;Logging + netstandard2.0 + + + + full + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/src/Microsoft.IdentityModel.LoggingExtensions/Properties/AssemblyInfo.cs b/src/Microsoft.IdentityModel.LoggingExtensions/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..2743e6bc85 --- /dev/null +++ b/src/Microsoft.IdentityModel.LoggingExtensions/Properties/AssemblyInfo.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyInformationalVersion("0.0.1")] +[assembly: AssemblyFileVersion("0.0.1")] +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: AssemblyVersion("0.0.1")] +[assembly: CLSCompliant(true)] +[assembly: ComVisible(false)] diff --git a/src/Microsoft.IdentityModel.ManagedKeyVaultSecurityKey/Microsoft.IdentityModel.ManagedKeyVaultSecurityKey.csproj b/src/Microsoft.IdentityModel.ManagedKeyVaultSecurityKey/Microsoft.IdentityModel.ManagedKeyVaultSecurityKey.csproj index 70dfa95498..8ae7733056 100644 --- a/src/Microsoft.IdentityModel.ManagedKeyVaultSecurityKey/Microsoft.IdentityModel.ManagedKeyVaultSecurityKey.csproj +++ b/src/Microsoft.IdentityModel.ManagedKeyVaultSecurityKey/Microsoft.IdentityModel.ManagedKeyVaultSecurityKey.csproj @@ -26,6 +26,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/GlobalSuppressions.cs b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/GlobalSuppressions.cs index 1a18c024a7..332d530766 100644 --- a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/GlobalSuppressions.cs +++ b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/GlobalSuppressions.cs @@ -18,3 +18,4 @@ [assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Previously released as non-static", Scope = "member", Target = "~M:Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfiguration.ShouldSerializeSigningKeys~System.Boolean")] [assembly: SuppressMessage("Design", "CA1033:Interface methods should be callable by child types", Justification = "Previously released as explicit implementation", Scope = "member", Target = "~M:Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.Microsoft#IdentityModel#Protocols#IConfigurationRetriever#GetConfigurationAsync(System.String,Microsoft.IdentityModel.Protocols.IDocumentRetriever,System.Threading.CancellationToken)~System.Threading.Tasks.Task{Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfiguration}")] [assembly: SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Normalized only for display", Scope = "member", Target = "~M:Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolValidator.ValidateIdToken(Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolValidationContext)")] +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Vendored component", Scope = "module")] diff --git a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/LogMessages.cs b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/LogMessages.cs index d0fa487ae9..bb5fc9974e 100644 --- a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/LogMessages.cs +++ b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/LogMessages.cs @@ -49,7 +49,7 @@ internal static class LogMessages internal const string IDX21305 = "IDX21305: OpenIdConnectProtocolValidationContext.ProtocolMessage.Code is null, there is no 'code' in the OpenIdConnect Response to validate."; internal const string IDX21306 = "IDX21306: The 'c_hash' claim was not a string in the 'id_token', but a 'code' was in the OpenIdConnectMessage, 'id_token': '{0}'."; internal const string IDX21307 = "IDX21307: The 'c_hash' claim was not found in the id_token, but a 'code' was in the OpenIdConnectMessage, id_token: '{0}'"; - internal const string IDX21308 = "IDX21308: 'Azp' claim exists in the 'id_token' but 'ciient_id' is null. Cannot validate the 'azp' claim."; + internal const string IDX21308 = "IDX21308: 'azp' claim exists in the 'id_token' but 'client_id' is null. Cannot validate the 'azp' claim."; internal const string IDX21309 = "IDX21309: Validating 'at_hash' using id_token and access_token."; internal const string IDX21310 = "IDX21310: OpenIdConnectProtocolValidationContext.ProtocolMessage.AccessToken is null, there is no 'token' in the OpenIdConnect Response to validate."; internal const string IDX21311 = "IDX21311: The 'at_hash' claim was not a string in the 'id_token', but an 'access_token' was in the OpenIdConnectMessage, 'id_token': '{0}'."; diff --git a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/OpenIdConnectProtocolValidator.cs b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/OpenIdConnectProtocolValidator.cs index ae4ef80c2d..c676bc417b 100644 --- a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/OpenIdConnectProtocolValidator.cs +++ b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/OpenIdConnectProtocolValidator.cs @@ -345,7 +345,7 @@ public virtual void ValidateUserInfoResponse(OpenIdConnectProtocolValidationCont if (string.IsNullOrEmpty(validationContext.ValidatedIdToken.Payload.Sub)) throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolException(LogMessages.IDX21346)); - if (!string.Equals(validationContext.ValidatedIdToken.Payload.Sub, sub, StringComparison.Ordinal)) + if (!string.Equals(validationContext.ValidatedIdToken.Payload.Sub, sub)) throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolException(LogHelper.FormatInvariant(LogMessages.IDX21338, validationContext.ValidatedIdToken.Payload.Sub, sub))); } @@ -421,7 +421,7 @@ protected virtual void ValidateIdToken(OpenIdConnectProtocolValidationContext va { throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolException(LogMessages.IDX21308)); } - else if (!string.Equals(idToken.Payload.Azp, validationContext.ClientId, StringComparison.Ordinal)) + else if (!string.Equals(idToken.Payload.Azp, validationContext.ClientId)) { throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolException(LogHelper.FormatInvariant(LogMessages.IDX21340, idToken.Payload.Azp, validationContext.ClientId))); } @@ -498,7 +498,7 @@ private static void CheckHash(HashAlgorithm hashAlgorithm, string expectedValue, { var hashBytes = hashAlgorithm.ComputeHash(Encoding.ASCII.GetBytes(hashItem)); var hashString = Base64UrlEncoder.Encode(hashBytes, 0, hashBytes.Length / 2); - if (!string.Equals(expectedValue, hashString, StringComparison.Ordinal)) + if (!string.Equals(expectedValue, hashString)) { throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolException(LogHelper.FormatInvariant(LogMessages.IDX21300, expectedValue, hashItem, LogHelper.MarkAsNonPII(algorithm)))); } @@ -544,11 +544,15 @@ protected virtual void ValidateCHash(OpenIdConnectProtocolValidationContext vali throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolInvalidCHashException(LogHelper.FormatInvariant(LogMessages.IDX21306, validationContext.ValidatedIdToken))); } + var idToken = validationContext.ValidatedIdToken; + + var alg = idToken.InnerToken != null ? idToken.InnerToken.Header.Alg : idToken.Header.Alg; + try { - ValidateHash(chash, validationContext.ProtocolMessage.Code, validationContext.ValidatedIdToken.Header.Alg); + ValidateHash(chash, validationContext.ProtocolMessage.Code, alg); } - catch(OpenIdConnectProtocolException ex) + catch (OpenIdConnectProtocolException ex) { throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolInvalidCHashException(LogMessages.IDX21347, ex)); } @@ -590,9 +594,13 @@ protected virtual void ValidateAtHash(OpenIdConnectProtocolValidationContext val if (atHash == null) throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolInvalidAtHashException(LogHelper.FormatInvariant(LogMessages.IDX21311, validationContext.ValidatedIdToken))); + var idToken = validationContext.ValidatedIdToken; + + var alg = idToken.InnerToken != null ? idToken.InnerToken.Header.Alg : idToken.Header.Alg; + try { - ValidateHash(atHash, validationContext.ProtocolMessage.AccessToken, validationContext.ValidatedIdToken.Header.Alg); + ValidateHash(atHash, validationContext.ProtocolMessage.AccessToken, alg); } catch (OpenIdConnectProtocolException ex) { @@ -638,7 +646,7 @@ protected virtual void ValidateNonce(OpenIdConnectProtocolValidationContext vali else if (string.IsNullOrEmpty(nonceFoundInJwt)) throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolInvalidNonceException(LogHelper.FormatInvariant(LogMessages.IDX21349, LogHelper.MarkAsNonPII(RequireNonce)))); - if (!string.Equals(nonceFoundInJwt, validationContext.Nonce, StringComparison.Ordinal)) + if (!string.Equals(nonceFoundInJwt, validationContext.Nonce)) throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolInvalidNonceException(LogHelper.FormatInvariant(LogMessages.IDX21321, validationContext.Nonce, nonceFoundInJwt, validationContext.ValidatedIdToken))); if (RequireTimeStampInNonce) @@ -666,7 +674,7 @@ protected virtual void ValidateNonce(OpenIdConnectProtocolValidationContext vali { nonceTime = DateTime.FromBinary(ticks); } - catch(Exception ex) + catch (Exception ex) { throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolInvalidNonceException(LogHelper.FormatInvariant(LogMessages.IDX21327, LogHelper.MarkAsNonPII(timestamp), LogHelper.MarkAsNonPII(DateTime.MinValue.Ticks.ToString(CultureInfo.InvariantCulture)), LogHelper.MarkAsNonPII(DateTime.MaxValue.Ticks.ToString(CultureInfo.InvariantCulture))), ex)); } @@ -715,7 +723,7 @@ protected virtual void ValidateState(OpenIdConnectProtocolValidationContext vali throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolInvalidStateException(LogHelper.FormatInvariant(LogMessages.IDX21330, LogHelper.MarkAsNonPII(RequireState)))); } - if (!string.Equals(validationContext.State, validationContext.ProtocolMessage.State, StringComparison.Ordinal)) + if (!string.Equals(validationContext.State, validationContext.ProtocolMessage.State)) { throw LogHelper.LogExceptionMessage(new OpenIdConnectProtocolInvalidStateException(LogHelper.FormatInvariant(LogMessages.IDX21331, validationContext.State, validationContext.ProtocolMessage.State))); } diff --git a/src/Microsoft.IdentityModel.Protocols.SignedHttpRequest/GlobalSuppressions.cs b/src/Microsoft.IdentityModel.Protocols.SignedHttpRequest/GlobalSuppressions.cs index a64586da17..c4a4856de7 100644 --- a/src/Microsoft.IdentityModel.Protocols.SignedHttpRequest/GlobalSuppressions.cs +++ b/src/Microsoft.IdentityModel.Protocols.SignedHttpRequest/GlobalSuppressions.cs @@ -10,5 +10,6 @@ [assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Previously released as read / write", Scope = "member", Target = "~P:Microsoft.IdentityModel.Protocols.SignedHttpRequest.SignedHttpRequestDescriptor.AdditionalPayloadClaims")] [assembly: SuppressMessage("Performance", "CA1825: Avoid zero-length array allocations", Justification = "net45 target doesn't support Array.Empty")] [assembly: SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Headers need to be lowercase to calcuate appropriate hash", Scope = "type", Target = "~T:Microsoft.IdentityModel.Protocols.SignedHttpRequest.SignedHttpRequestHandler")] +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Vendored component", Scope = "module")] [assembly: SuppressMessage("Design", "CA1001:Types that own disposable fields should be disposable", Justification = "Breaking change", Scope = "type", Target = "~T:Microsoft.IdentityModel.Protocols.SignedHttpRequest.SignedHttpRequestHandler")] [assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Previously released as read / write", Scope = "member", Target = "~P:Microsoft.IdentityModel.Protocols.SignedHttpRequest.SignedHttpRequestInvalidNonceClaimException.PropertyBag")] diff --git a/src/Microsoft.IdentityModel.Protocols.SignedHttpRequest/Microsoft.IdentityModel.Protocols.SignedHttpRequest.csproj b/src/Microsoft.IdentityModel.Protocols.SignedHttpRequest/Microsoft.IdentityModel.Protocols.SignedHttpRequest.csproj index f427c7885e..f96b956717 100644 --- a/src/Microsoft.IdentityModel.Protocols.SignedHttpRequest/Microsoft.IdentityModel.Protocols.SignedHttpRequest.csproj +++ b/src/Microsoft.IdentityModel.Protocols.SignedHttpRequest/Microsoft.IdentityModel.Protocols.SignedHttpRequest.csproj @@ -31,7 +31,7 @@ - + diff --git a/src/Microsoft.IdentityModel.Protocols.SignedHttpRequest/SignedHttpRequestHandler.cs b/src/Microsoft.IdentityModel.Protocols.SignedHttpRequest/SignedHttpRequestHandler.cs index 4dbe56485f..f3e936f7fd 100644 --- a/src/Microsoft.IdentityModel.Protocols.SignedHttpRequest/SignedHttpRequestHandler.cs +++ b/src/Microsoft.IdentityModel.Protocols.SignedHttpRequest/SignedHttpRequestHandler.cs @@ -103,7 +103,6 @@ public string CreateSignedHttpRequest(SignedHttpRequestDescriptor signedHttpRequ return message + "." + JwtTokenUtilities.CreateEncodedSignature(message, signedHttpRequestDescriptor.SigningCredentials, false); } - /// /// Creates a JSON representation of a HttpRequest payload. /// @@ -209,7 +208,7 @@ internal virtual void AddMClaim(Dictionary payload, SignedHttpRe if (string.IsNullOrEmpty(httpMethod)) throw LogHelper.LogArgumentNullException(nameof(signedHttpRequestDescriptor.HttpRequestData.Method)); - if (!httpMethod.ToUpperInvariant().Equals(httpMethod, StringComparison.Ordinal)) + if (!httpMethod.ToUpperInvariant().Equals(httpMethod)) throw LogHelper.LogExceptionMessage(new SignedHttpRequestCreationException(LogHelper.FormatInvariant(LogMessages.IDX23002, LogHelper.MarkAsNonPII(httpMethod)))); payload.Add(SignedHttpRequestClaimTypes.M, httpMethod); @@ -856,7 +855,7 @@ internal virtual void ValidateQClaim(JsonWebToken signedHttpRequest, SignedHttpR if (!signedHttpRequestValidationContext.SignedHttpRequestValidationParameters.AcceptUnsignedQueryParameters && sanitizedQueryParams.Any()) throw LogHelper.LogExceptionMessage(new SignedHttpRequestInvalidQClaimException(LogHelper.FormatInvariant(LogMessages.IDX23029, LogHelper.MarkAsNonPII(string.Join(", ", sanitizedQueryParams.Select(x => x.Key)))))); - if (!string.Equals(expectedBase64UrlEncodedHash, qClaimBase64UrlEncodedHash, StringComparison.Ordinal)) + if (!string.Equals(expectedBase64UrlEncodedHash, qClaimBase64UrlEncodedHash)) throw LogHelper.LogExceptionMessage(new SignedHttpRequestInvalidQClaimException(LogHelper.FormatInvariant(LogMessages.IDX23011, LogHelper.MarkAsNonPII(SignedHttpRequestClaimTypes.Q), expectedBase64UrlEncodedHash, qClaimBase64UrlEncodedHash))); } @@ -924,7 +923,7 @@ internal virtual void ValidateHClaim(JsonWebToken signedHttpRequest, SignedHttpR if (!signedHttpRequestValidationContext.SignedHttpRequestValidationParameters.AcceptUnsignedHeaders && sanitizedHeaders.Any()) throw LogHelper.LogExceptionMessage(new SignedHttpRequestInvalidHClaimException(LogHelper.FormatInvariant(LogMessages.IDX23026, LogHelper.MarkAsNonPII(string.Join(", ", sanitizedHeaders.Select(x => x.Key)))))); - if (!string.Equals(expectedBase64UrlEncodedHash, hClaimBase64UrlEncodedHash, StringComparison.Ordinal)) + if (!string.Equals(expectedBase64UrlEncodedHash, hClaimBase64UrlEncodedHash)) throw LogHelper.LogExceptionMessage(new SignedHttpRequestInvalidHClaimException(LogHelper.FormatInvariant(LogMessages.IDX23011, LogHelper.MarkAsNonPII(SignedHttpRequestClaimTypes.H), expectedBase64UrlEncodedHash, hClaimBase64UrlEncodedHash))); } @@ -958,7 +957,7 @@ internal virtual void ValidateBClaim(JsonWebToken signedHttpRequest, SignedHttpR throw LogHelper.LogExceptionMessage(new SignedHttpRequestCreationException(LogHelper.FormatInvariant(LogMessages.IDX23008, LogHelper.MarkAsNonPII(SignedHttpRequestClaimTypes.B), e), e)); } - if (!string.Equals(expectedBase64UrlEncodedHash, bClaim, StringComparison.Ordinal)) + if (!string.Equals(expectedBase64UrlEncodedHash, bClaim)) throw LogHelper.LogExceptionMessage(new SignedHttpRequestInvalidBClaimException(LogHelper.FormatInvariant(LogMessages.IDX23011, LogHelper.MarkAsNonPII(SignedHttpRequestClaimTypes.B), expectedBase64UrlEncodedHash, bClaim))); } #endregion @@ -1102,7 +1101,7 @@ internal virtual async Task ResolvePopKeyFromJkuAsync(string jkuSet { foreach (var key in popKeys) { - if (string.Equals(key.KeyId, kid.ToString(), StringComparison.Ordinal)) + if (string.Equals(key.KeyId, kid.ToString())) return key; } @@ -1189,7 +1188,7 @@ internal virtual async Task ResolvePopKeyFromCnfReferenceAsync(stri jwkPopKeyThumprint = Base64UrlEncoder.Encode(popKey.ComputeJwkThumbprint()); // validate reference - if (!string.Equals(cnfReferenceId, jwkPopKeyThumprint, StringComparison.Ordinal)) + if (!string.Equals(cnfReferenceId, jwkPopKeyThumprint)) throw LogHelper.LogExceptionMessage(new SignedHttpRequestInvalidPopKeyException(LogHelper.FormatInvariant(LogMessages.IDX23033, cnfReferenceId, jwkPopKeyThumprint, confirmationClaim))); return popKey; diff --git a/src/Microsoft.IdentityModel.Protocols.WsFederation/GlobalSuppressions.cs b/src/Microsoft.IdentityModel.Protocols.WsFederation/GlobalSuppressions.cs index dc2dbb01cc..6a35dd1f18 100644 --- a/src/Microsoft.IdentityModel.Protocols.WsFederation/GlobalSuppressions.cs +++ b/src/Microsoft.IdentityModel.Protocols.WsFederation/GlobalSuppressions.cs @@ -31,3 +31,7 @@ [assembly: SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "Doesn't own object", Scope = "member", Target = "~M:Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMetadataSerializer.ReadEntityDescriptor(System.Xml.XmlReader)~Microsoft.IdentityModel.Protocols.WsFederation.WsFederationConfiguration")] [assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Breaking change", Scope = "member", Target = "~P:Microsoft.IdentityModel.Protocols.WsFederation.SecurityTokenServiceTypeRoleDescriptor.KeyInfos")] +#if NET6_0 +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Adding StringComparison.Ordinal adds a performance penalty.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Protocols.WsFederation.QueryHelper.ParseNullableQuery(System.String)~System.Collections.Generic.IDictionary{System.String,System.Collections.Generic.IList{System.String}}")] +#endif + diff --git a/src/Microsoft.IdentityModel.Protocols.WsFederation/Microsoft.IdentityModel.Protocols.WsFederation.csproj b/src/Microsoft.IdentityModel.Protocols.WsFederation/Microsoft.IdentityModel.Protocols.WsFederation.csproj index 248ae24373..90baa73364 100644 --- a/src/Microsoft.IdentityModel.Protocols.WsFederation/Microsoft.IdentityModel.Protocols.WsFederation.csproj +++ b/src/Microsoft.IdentityModel.Protocols.WsFederation/Microsoft.IdentityModel.Protocols.WsFederation.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/Microsoft.IdentityModel.Protocols/Configuration/ConfigurationManager.cs b/src/Microsoft.IdentityModel.Protocols/Configuration/ConfigurationManager.cs index dde466a6d1..3a1cc8aa90 100644 --- a/src/Microsoft.IdentityModel.Protocols/Configuration/ConfigurationManager.cs +++ b/src/Microsoft.IdentityModel.Protocols/Configuration/ConfigurationManager.cs @@ -57,7 +57,6 @@ public class ConfigurationManager : BaseConfigurationManager, IConfigurationM /// static ConfigurationManager() { - LogHelper.LogVerbose("Assembly version info: " + LogHelper.MarkAsNonPII(typeof(ConfigurationManager).AssemblyQualifiedName)); } /// @@ -163,7 +162,7 @@ public async Task GetConfigurationAsync(CancellationToken cancel) if (_configValidator != null) { ConfigurationValidationResult result = _configValidator.Validate(configuration); - if (!result.Succeeded) + if (!result.Succeeded) LogHelper.LogWarning(LogMessages.IDX20810, result.ErrorMessage); } diff --git a/src/Microsoft.IdentityModel.Protocols/GlobalSuppressions.cs b/src/Microsoft.IdentityModel.Protocols/GlobalSuppressions.cs index e79eb2c67c..7b5a935521 100644 --- a/src/Microsoft.IdentityModel.Protocols/GlobalSuppressions.cs +++ b/src/Microsoft.IdentityModel.Protocols/GlobalSuppressions.cs @@ -9,3 +9,6 @@ [assembly: SuppressMessage("Performance", "CA1819:Properties should not return arrays", Justification = "Previously released as returning an array", Scope = "member", Target = "~P:Microsoft.IdentityModel.Protocols.HttpRequestData.Body")] [assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Previously released read/write", Scope = "member", Target = "~P:Microsoft.IdentityModel.Protocols.HttpRequestData.Headers")] [assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Previously released read/write", Scope = "member", Target = "~P:Microsoft.IdentityModel.Protocols.HttpRequestData.PropertyBag")] +#if NET6_0 +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Adding StringComparison.Ordinal adds a performance penalty.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Protocols.AuthenticationProtocolMessage.BuildRedirectUrl~System.String")] +#endif diff --git a/src/Microsoft.IdentityModel.TestExtensions/Microsoft.IdentityModel.TestExtensions.csproj b/src/Microsoft.IdentityModel.TestExtensions/Microsoft.IdentityModel.TestExtensions.csproj index c5895d612d..8948aa7508 100644 --- a/src/Microsoft.IdentityModel.TestExtensions/Microsoft.IdentityModel.TestExtensions.csproj +++ b/src/Microsoft.IdentityModel.TestExtensions/Microsoft.IdentityModel.TestExtensions.csproj @@ -1,6 +1,6 @@ - + Microsoft.IdentityModel.TestExtensions diff --git a/src/Microsoft.IdentityModel.TestExtensions/Properties/AssemblyInfo.cs b/src/Microsoft.IdentityModel.TestExtensions/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..2743e6bc85 --- /dev/null +++ b/src/Microsoft.IdentityModel.TestExtensions/Properties/AssemblyInfo.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyInformationalVersion("0.0.1")] +[assembly: AssemblyFileVersion("0.0.1")] +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: AssemblyVersion("0.0.1")] +[assembly: CLSCompliant(true)] +[assembly: ComVisible(false)] diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/GlobalSuppressions.cs b/src/Microsoft.IdentityModel.Tokens.Saml/GlobalSuppressions.cs index 07185abb0b..0dfb75d6f5 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/GlobalSuppressions.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/GlobalSuppressions.cs @@ -30,3 +30,4 @@ [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Breaking change", Scope = "member", Target = "~P:Microsoft.IdentityModel.Tokens.Saml2.Saml2Assertion.CanonicalString")] [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Catching all exceptions to match old model, in new models, we should try to avoid this behavior", Scope = "member", Target = "~M:Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidateTokenAsync(System.String,Microsoft.IdentityModel.Tokens.TokenValidationParameters)~System.Threading.Tasks.Task{Microsoft.IdentityModel.Tokens.TokenValidationResult}")] [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Catching all exceptions to match old model, in new models, we should try to avoid this behavior", Scope = "member", Target = "~M:Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateTokenAsync(System.String,Microsoft.IdentityModel.Tokens.TokenValidationParameters)~System.Threading.Tasks.Task{Microsoft.IdentityModel.Tokens.TokenValidationResult}")] +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Vendored component", Scope = "module")] diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlAttributeKeyComparer.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlAttributeKeyComparer.cs index 49df3a982a..203bcee0f4 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlAttributeKeyComparer.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlAttributeKeyComparer.cs @@ -96,12 +96,12 @@ int ComputeHashCode() public bool Equals(AttributeKey other) { return other != null && - FriendlyName.Equals(other.FriendlyName, StringComparison.Ordinal) && - Name.Equals(other.Name, StringComparison.Ordinal) && - NameFormat.Equals(other.NameFormat, StringComparison.Ordinal) && - Namespace.Equals(other.Namespace, StringComparison.Ordinal) && - OriginalIssuer.Equals(other.OriginalIssuer, StringComparison.Ordinal) && - ValueType.Equals(other.ValueType, StringComparison.Ordinal); + FriendlyName.Equals(other.FriendlyName) && + Name.Equals(other.Name) && + NameFormat.Equals(other.NameFormat) && + Namespace.Equals(other.Namespace) && + OriginalIssuer.Equals(other.OriginalIssuer) && + ValueType.Equals(other.ValueType); } } diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlAuthorizationDecisionStatement.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlAuthorizationDecisionStatement.cs index 1a601ffee8..ca2c0b5b33 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlAuthorizationDecisionStatement.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlAuthorizationDecisionStatement.cs @@ -97,9 +97,9 @@ public string Decision if (string.IsNullOrEmpty(value)) throw LogArgumentNullException(nameof(value)); - if (SamlConstants.AccessDecision.Deny.Equals(value, StringComparison.Ordinal) - || SamlConstants.AccessDecision.Permit.Equals(value, StringComparison.Ordinal) - || SamlConstants.AccessDecision.Indeterminate.Equals(value, StringComparison.Ordinal)) + if (SamlConstants.AccessDecision.Deny.Equals(value) + || SamlConstants.AccessDecision.Permit.Equals(value) + || SamlConstants.AccessDecision.Indeterminate.Equals(value)) _decision = value; else throw LogExceptionMessage(new SamlSecurityTokenException(LogMessages.IDX11508)); diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSerializer.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSerializer.cs index e8bcae5f3a..6a07d9b1a1 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSerializer.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSerializer.cs @@ -234,7 +234,7 @@ public virtual SamlAssertion ReadAssertion(XmlReader reader) if (string.IsNullOrEmpty(majorVersion)) throw LogReadException(LogMessages.IDX11115, SamlConstants.Elements.Assertion, SamlConstants.Attributes.MajorVersion); - if (!majorVersion.Equals(SamlConstants.MajorVersionValue, StringComparison.Ordinal)) + if (!majorVersion.Equals(SamlConstants.MajorVersionValue)) throw LogReadException(LogMessages.IDX11116, majorVersion); // @MinorVersion - required - must be "1" @@ -242,7 +242,7 @@ public virtual SamlAssertion ReadAssertion(XmlReader reader) if (string.IsNullOrEmpty(minorVersion)) throw LogReadException(LogMessages.IDX11115, SamlConstants.Elements.Assertion, SamlConstants.Attributes.MinorVersion); - if (!minorVersion.Equals(SamlConstants.MinorVersionValue, StringComparison.Ordinal)) + if (!minorVersion.Equals(SamlConstants.MinorVersionValue)) throw LogReadException(LogMessages.IDX11117, minorVersion); // @AssertionId - required diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2AttributeKeyComparer.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2AttributeKeyComparer.cs index c612a3f89a..c29f7a31ba 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2AttributeKeyComparer.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2AttributeKeyComparer.cs @@ -92,11 +92,11 @@ int ComputeHashCode() public bool Equals(AttributeKey other) { return other != null && - FriendlyName.Equals(other.FriendlyName, StringComparison.Ordinal) && - Name.Equals(other.Name, StringComparison.Ordinal) && - NameFormat.Equals(other.NameFormat, StringComparison.Ordinal) && - ValueType.Equals(other.ValueType, StringComparison.Ordinal) && - OriginalIssuer.Equals(other.OriginalIssuer, StringComparison.Ordinal); + FriendlyName.Equals(other.FriendlyName) && + Name.Equals(other.Name) && + NameFormat.Equals(other.NameFormat) && + ValueType.Equals(other.ValueType) && + OriginalIssuer.Equals(other.OriginalIssuer); } } diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2AuthorizationDecisionStatement.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2AuthorizationDecisionStatement.cs index 947532186f..90000381de 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2AuthorizationDecisionStatement.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2AuthorizationDecisionStatement.cs @@ -94,9 +94,9 @@ public string Decision if (string.IsNullOrEmpty(value)) throw LogArgumentNullException(nameof(value)); - if (Saml2Constants.AccessDecision.Deny.Equals(value, StringComparison.Ordinal) - || Saml2Constants.AccessDecision.Permit.Equals(value, StringComparison.Ordinal) - || Saml2Constants.AccessDecision.Indeterminate.Equals(value, StringComparison.Ordinal)) + if (Saml2Constants.AccessDecision.Deny.Equals(value) + || Saml2Constants.AccessDecision.Permit.Equals(value) + || Saml2Constants.AccessDecision.Indeterminate.Equals(value)) _decision = value; else throw LogExceptionMessage(new Saml2SecurityTokenException(LogMessages.IDX13310)); diff --git a/src/Microsoft.IdentityModel.Tokens/AsymmetricAdapter.cs b/src/Microsoft.IdentityModel.Tokens/AsymmetricAdapter.cs index 20b8911fd5..c0260b6087 100644 --- a/src/Microsoft.IdentityModel.Tokens/AsymmetricAdapter.cs +++ b/src/Microsoft.IdentityModel.Tokens/AsymmetricAdapter.cs @@ -33,7 +33,7 @@ using System.Reflection; #endif -#if NET461 || NET472 || NETSTANDARD2_0 +#if NET461 || NET472 || NETSTANDARD2_0 || NET6_0 using System.Security.Cryptography.X509Certificates; #endif @@ -194,8 +194,8 @@ private void InitializeUsingRsa(RSA rsa, string algorithm) #if DESKTOP if (rsa is RSACryptoServiceProvider rsaCryptoServiceProvider) { - _useRSAOeapPadding = algorithm.Equals(SecurityAlgorithms.RsaOAEP, StringComparison.Ordinal) - || algorithm.Equals(SecurityAlgorithms.RsaOaepKeyWrap, StringComparison.Ordinal); + _useRSAOeapPadding = algorithm.Equals(SecurityAlgorithms.RsaOAEP) + || algorithm.Equals(SecurityAlgorithms.RsaOaepKeyWrap); RsaCryptoServiceProviderProxy = new RSACryptoServiceProviderProxy(rsaCryptoServiceProvider); DecryptFunction = DecryptWithRsaCryptoServiceProviderProxy; @@ -215,10 +215,10 @@ private void InitializeUsingRsa(RSA rsa, string algorithm) // This requires 4.6+ to be installed. If a dependent library is targeting 4.5, 4.5.1, 4.5.2 or 4.6 // they will bind to our Net45 target, but the type is RSACng. // The 'lightup' code will bind to the correct operators. - else if (rsa.GetType().ToString().Equals(_rsaCngTypeName, StringComparison.Ordinal) && IsRsaCngSupported()) + else if (rsa.GetType().ToString().Equals(_rsaCngTypeName) && IsRsaCngSupported()) { - _useRSAOeapPadding = algorithm.Equals(SecurityAlgorithms.RsaOAEP, StringComparison.Ordinal) - || algorithm.Equals(SecurityAlgorithms.RsaOaepKeyWrap, StringComparison.Ordinal); + _useRSAOeapPadding = algorithm.Equals(SecurityAlgorithms.RsaOAEP) + || algorithm.Equals(SecurityAlgorithms.RsaOaepKeyWrap); _lightUpHashAlgorithmName = GetLightUpHashAlgorithmName(); DecryptFunction = DecryptNet45; @@ -235,13 +235,13 @@ private void InitializeUsingRsa(RSA rsa, string algorithm) } #endif -#if NET461 || NET472 || NETSTANDARD2_0 - if (algorithm.Equals(SecurityAlgorithms.RsaSsaPssSha256, StringComparison.Ordinal) || - algorithm.Equals(SecurityAlgorithms.RsaSsaPssSha256Signature, StringComparison.Ordinal) || - algorithm.Equals(SecurityAlgorithms.RsaSsaPssSha384, StringComparison.Ordinal) || - algorithm.Equals(SecurityAlgorithms.RsaSsaPssSha384Signature, StringComparison.Ordinal) || - algorithm.Equals(SecurityAlgorithms.RsaSsaPssSha512, StringComparison.Ordinal) || - algorithm.Equals(SecurityAlgorithms.RsaSsaPssSha512Signature, StringComparison.Ordinal)) +#if NET461 || NET472 || NETSTANDARD2_0 || NET6_0 + if (algorithm.Equals(SecurityAlgorithms.RsaSsaPssSha256) || + algorithm.Equals(SecurityAlgorithms.RsaSsaPssSha256Signature) || + algorithm.Equals(SecurityAlgorithms.RsaSsaPssSha384) || + algorithm.Equals(SecurityAlgorithms.RsaSsaPssSha384Signature) || + algorithm.Equals(SecurityAlgorithms.RsaSsaPssSha512) || + algorithm.Equals(SecurityAlgorithms.RsaSsaPssSha512Signature)) { RSASignaturePadding = RSASignaturePadding.Pss; } @@ -251,7 +251,7 @@ private void InitializeUsingRsa(RSA rsa, string algorithm) RSASignaturePadding = RSASignaturePadding.Pkcs1; } - RSAEncryptionPadding = (algorithm.Equals(SecurityAlgorithms.RsaOAEP, StringComparison.Ordinal) || algorithm.Equals(SecurityAlgorithms.RsaOaepKeyWrap, StringComparison.Ordinal)) + RSAEncryptionPadding = (algorithm.Equals(SecurityAlgorithms.RsaOAEP) || algorithm.Equals(SecurityAlgorithms.RsaOaepKeyWrap)) ? RSAEncryptionPadding.OaepSHA1 : RSAEncryptionPadding.Pkcs1; RSA = rsa; @@ -270,7 +270,7 @@ private void InitializeUsingRsaSecurityKey(RsaSecurityKey rsaSecurityKey, string } else { -#if NET472 +#if NET472 || NET6_0 var rsa = RSA.Create(rsaSecurityKey.Parameters); #else var rsa = RSA.Create(); @@ -323,8 +323,8 @@ private bool VerifyWithECDsa(byte[] bytes, byte[] signature) return ECDsa.VerifyHash(HashAlgorithm.ComputeHash(bytes), signature); } -#region NET61+ related code -#if NET461 || NET472 || NETSTANDARD2_0 + #region NET61+ related code +#if NET461 || NET472 || NETSTANDARD2_0 || NET6_0 // HasAlgorithmName was introduced into Net46 internal AsymmetricAdapter(SecurityKey key, string algorithm, HashAlgorithm hashAlgorithm, HashAlgorithmName hashAlgorithmName, bool requirePrivateKey) : this(key, algorithm, hashAlgorithm, requirePrivateKey) diff --git a/src/Microsoft.IdentityModel.Tokens/AsymmetricSignatureProvider.cs b/src/Microsoft.IdentityModel.Tokens/AsymmetricSignatureProvider.cs index dc1cd213d7..465c557634 100644 --- a/src/Microsoft.IdentityModel.Tokens/AsymmetricSignatureProvider.cs +++ b/src/Microsoft.IdentityModel.Tokens/AsymmetricSignatureProvider.cs @@ -185,8 +185,8 @@ private static PrivateKeyStatus FoundPrivateKey(SecurityKey key) return PrivateKeyStatus.Unknown; } - -#if NET461 || NET472 || NETSTANDARD2_0 + +#if NET461 || NET472 || NETSTANDARD2_0 || NET6_0 /// /// Creating a Signature requires the use of a . /// This method returns the diff --git a/src/Microsoft.IdentityModel.Tokens/CallContext.cs b/src/Microsoft.IdentityModel.Tokens/CallContext.cs index 359d94d067..d800d7dd05 100644 --- a/src/Microsoft.IdentityModel.Tokens/CallContext.cs +++ b/src/Microsoft.IdentityModel.Tokens/CallContext.cs @@ -26,51 +26,27 @@ //------------------------------------------------------------------------------ using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics.Tracing; +using Microsoft.IdentityModel.Logging; namespace Microsoft.IdentityModel.Tokens { /// /// An opaque context used to store work when working with authentication artifacts. /// - public class CallContext + public class CallContext : LoggerContext { /// /// Instantiates a new with a default activityId. /// - public CallContext() + public CallContext() : base() { } /// /// Instantiates a new with an activityId. /// - public CallContext(Guid activityId) + public CallContext(Guid activityId) : base(activityId) { - ActivityId = activityId; } - - /// - /// Gets or set a that will be used in the call to EventSource.SetCurrentThreadActivityId before logging. - /// - public Guid ActivityId { get; set; } = Guid.Empty; - - /// - /// Gets or sets a boolean controlling if logs are written into the context. - /// Useful when debugging. - /// - public bool CaptureLogs { get; set; } = false; - - /// - /// The collection of logs associated with a request. Use to control capture. - /// - public ICollection Logs { get; private set; } = new Collection(); - - /// - /// Gets or sets an that enables custom extensibility scenarios. - /// - public IDictionary PropertyBag { get; set; } } } diff --git a/src/Microsoft.IdentityModel.Tokens/CompressionProviderFactory.cs b/src/Microsoft.IdentityModel.Tokens/CompressionProviderFactory.cs index 139bd0ea03..1042e36ac2 100644 --- a/src/Microsoft.IdentityModel.Tokens/CompressionProviderFactory.cs +++ b/src/Microsoft.IdentityModel.Tokens/CompressionProviderFactory.cs @@ -93,7 +93,7 @@ public virtual bool IsSupportedAlgorithm(string algorithm) private static bool IsSupportedCompressionAlgorithm(string algorithm) { - return CompressionAlgorithms.Deflate.Equals(algorithm, StringComparison.Ordinal); + return CompressionAlgorithms.Deflate.Equals(algorithm); } /// @@ -109,7 +109,7 @@ public ICompressionProvider CreateCompressionProvider(string algorithm) if (CustomCompressionProvider != null && CustomCompressionProvider.IsSupportedAlgorithm(algorithm)) return CustomCompressionProvider; - if (algorithm.Equals(CompressionAlgorithms.Deflate, StringComparison.Ordinal)) + if (algorithm.Equals(CompressionAlgorithms.Deflate)) return new DeflateCompressionProvider(); throw LogHelper.LogExceptionMessage(new NotSupportedException(LogHelper.FormatInvariant(LogMessages.IDX10652, LogHelper.MarkAsNonPII(algorithm)))); diff --git a/src/Microsoft.IdentityModel.Tokens/CryptoProviderFactory.cs b/src/Microsoft.IdentityModel.Tokens/CryptoProviderFactory.cs index c206c468b5..66a0c75532 100644 --- a/src/Microsoft.IdentityModel.Tokens/CryptoProviderFactory.cs +++ b/src/Microsoft.IdentityModel.Tokens/CryptoProviderFactory.cs @@ -342,7 +342,7 @@ public virtual SignatureProvider CreateForVerifying(SecurityKey key, string algo return CreateSignatureProvider(key, algorithm, false, cacheProvider); } -#if NET461 || NET472 || NETSTANDARD2_0 +#if NET461 || NET472 || NETSTANDARD2_0 || NET6_0 /// /// Creates a for a specific algorithm. /// diff --git a/src/Microsoft.IdentityModel.Tokens/DeflateCompressionProvider.cs b/src/Microsoft.IdentityModel.Tokens/DeflateCompressionProvider.cs index 9eac17f586..60b48beff6 100644 --- a/src/Microsoft.IdentityModel.Tokens/DeflateCompressionProvider.cs +++ b/src/Microsoft.IdentityModel.Tokens/DeflateCompressionProvider.cs @@ -118,7 +118,7 @@ public byte[] Compress(byte[] value) /// true if the compression algorithm is supported, false otherwise. public bool IsSupportedAlgorithm(string algorithm) { - return Algorithm.Equals(algorithm, StringComparison.Ordinal); + return Algorithm.Equals(algorithm); } } } diff --git a/src/Microsoft.IdentityModel.Tokens/ECDsaAdapter.cs b/src/Microsoft.IdentityModel.Tokens/ECDsaAdapter.cs index c0264f7930..7a40a30f5f 100644 --- a/src/Microsoft.IdentityModel.Tokens/ECDsaAdapter.cs +++ b/src/Microsoft.IdentityModel.Tokens/ECDsaAdapter.cs @@ -52,7 +52,7 @@ internal class ECDsaAdapter /// internal ECDsaAdapter() { -#if NET472 +#if NET472 || NET6_0 CreateECDsaFunction = CreateECDsaUsingECParams; #elif NETSTANDARD2_0 // Although NETSTANDARD2_0 specifies that ECParameters are supported, we still need to call SupportsECParameters() @@ -269,7 +269,9 @@ private static bool SupportsCNGKey() { try { +#pragma warning disable CA1416 // Validate platform compatibility _ = CngKeyBlobFormat.EccPrivateBlob; +#pragma warning restore CA1416 // Validate platform compatibility return true; } catch @@ -278,7 +280,7 @@ private static bool SupportsCNGKey() } } -#if NET472 || NETSTANDARD2_0 +#if NET472 || NETSTANDARD2_0 || NET6_0 /// /// Creates an ECDsa object using the and . /// 'ECParameters' structure is available in .NET Framework 4.7+, .NET Standard 1.6+, and .NET Core 1.0+. @@ -349,11 +351,11 @@ internal static string GetCrvParameterValue(ECCurve curve) if (curve.Oid == null) throw LogHelper.LogArgumentNullException(nameof(curve.Oid)); - if (string.Equals(curve.Oid.Value, ECCurve.NamedCurves.nistP256.Oid.Value, StringComparison.Ordinal) || string.Equals(curve.Oid.FriendlyName, ECCurve.NamedCurves.nistP256.Oid.FriendlyName, StringComparison.Ordinal)) + if (string.Equals(curve.Oid.Value, ECCurve.NamedCurves.nistP256.Oid.Value) || string.Equals(curve.Oid.FriendlyName, ECCurve.NamedCurves.nistP256.Oid.FriendlyName)) return JsonWebKeyECTypes.P256; - else if (string.Equals(curve.Oid.Value, ECCurve.NamedCurves.nistP384.Oid.Value, StringComparison.Ordinal) || string.Equals(curve.Oid.FriendlyName, ECCurve.NamedCurves.nistP384.Oid.FriendlyName, StringComparison.Ordinal)) + else if (string.Equals(curve.Oid.Value, ECCurve.NamedCurves.nistP384.Oid.Value) || string.Equals(curve.Oid.FriendlyName, ECCurve.NamedCurves.nistP384.Oid.FriendlyName)) return JsonWebKeyECTypes.P384; - else if (string.Equals(curve.Oid.Value, ECCurve.NamedCurves.nistP521.Oid.Value, StringComparison.Ordinal) || string.Equals(curve.Oid.FriendlyName, ECCurve.NamedCurves.nistP521.Oid.FriendlyName, StringComparison.Ordinal)) + else if (string.Equals(curve.Oid.Value, ECCurve.NamedCurves.nistP521.Oid.Value) || string.Equals(curve.Oid.FriendlyName, ECCurve.NamedCurves.nistP521.Oid.FriendlyName)) return JsonWebKeyECTypes.P521; else throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX10645, (curve.Oid.Value ?? curve.Oid.FriendlyName) ?? "null"))); @@ -366,7 +368,7 @@ internal static string GetCrvParameterValue(ECCurve curve) /// True if structure is supported, false otherwise. internal static bool SupportsECParameters() { -#if NET472 +#if NET472 || NET6_0 return true; #else try diff --git a/src/Microsoft.IdentityModel.Tokens/ECDsaSecurityKey.cs b/src/Microsoft.IdentityModel.Tokens/ECDsaSecurityKey.cs index 11cb930038..5096aa35f0 100644 --- a/src/Microsoft.IdentityModel.Tokens/ECDsaSecurityKey.cs +++ b/src/Microsoft.IdentityModel.Tokens/ECDsaSecurityKey.cs @@ -116,7 +116,7 @@ public override int KeySize /// https://datatracker.ietf.org/doc/html/rfc7638 public override bool CanComputeJwkThumbprint() { -#if NET472 || NETSTANDARD2_0 +#if NET472 || NETSTANDARD2_0 || NET6_0 if (ECDsaAdapter.SupportsECParameters()) return true; #endif @@ -130,7 +130,7 @@ public override bool CanComputeJwkThumbprint() /// https://datatracker.ietf.org/doc/html/rfc7638 public override byte[] ComputeJwkThumbprint() { -#if NET472 || NETSTANDARD2_0 +#if NET472 || NETSTANDARD2_0 || NET6_0 if (ECDsaAdapter.SupportsECParameters()) { ECParameters parameters = ECDsa.ExportParameters(false); diff --git a/src/Microsoft.IdentityModel.Tokens/EncryptingCredentials.cs b/src/Microsoft.IdentityModel.Tokens/EncryptingCredentials.cs index 5e0db2b8d5..03d29926a9 100644 --- a/src/Microsoft.IdentityModel.Tokens/EncryptingCredentials.cs +++ b/src/Microsoft.IdentityModel.Tokens/EncryptingCredentials.cs @@ -109,11 +109,24 @@ public string Enc private set => _enc = string.IsNullOrEmpty(value) ? throw LogHelper.LogArgumentNullException("enc") : value; } + /// + /// Public key used in Key Agreement Algorithms + /// + public SecurityKey KeyExchangePublicKey { get; set; } + /// /// Users can override the default with this property. This factory will be used for creating encryption providers. /// public CryptoProviderFactory CryptoProviderFactory { get; set; } + /// + /// Gets or sets a bool that controls if the encrypted token creation will set default 'cty' if not specified. + /// + /// Applies to only JWT tokens. + /// + /// + public bool SetDefaultCtyClaim { get; set; } = true; + /// /// Gets the used for encryption. /// diff --git a/src/Microsoft.IdentityModel.Tokens/Encryption/AuthenticatedEncryptionProvider.cs b/src/Microsoft.IdentityModel.Tokens/Encryption/AuthenticatedEncryptionProvider.cs index 0644798645..896195c24a 100644 --- a/src/Microsoft.IdentityModel.Tokens/Encryption/AuthenticatedEncryptionProvider.cs +++ b/src/Microsoft.IdentityModel.Tokens/Encryption/AuthenticatedEncryptionProvider.cs @@ -83,7 +83,7 @@ public AuthenticatedEncryptionProvider(SecurityKey key, string algorithm) { if (SupportedAlgorithms.IsAesGcm(algorithm)) { -#if NETSTANDARD2_0 +#if NETSTANDARD2_0 || NET6_0 if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) throw LogHelper.LogExceptionMessage(new PlatformNotSupportedException(LogHelper.FormatInvariant(LogMessages.IDX10713, LogHelper.MarkAsNonPII(algorithm)))); #endif @@ -377,11 +377,11 @@ protected virtual bool IsSupportedAlgorithm(SecurityKey key, string algorithm) private AuthenticatedKeys GetAlgorithmParameters(SecurityKey key, string algorithm) { int keyLength = -1; - if (algorithm.Equals(SecurityAlgorithms.Aes256CbcHmacSha512, StringComparison.Ordinal)) + if (algorithm.Equals(SecurityAlgorithms.Aes256CbcHmacSha512)) keyLength = 32; - else if (algorithm.Equals(SecurityAlgorithms.Aes192CbcHmacSha384, StringComparison.Ordinal)) + else if (algorithm.Equals(SecurityAlgorithms.Aes192CbcHmacSha384)) keyLength = 24; - else if (algorithm.Equals(SecurityAlgorithms.Aes128CbcHmacSha256, StringComparison.Ordinal)) + else if (algorithm.Equals(SecurityAlgorithms.Aes128CbcHmacSha256)) keyLength = 16; else throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX10668, LogHelper.MarkAsNonPII(_className), LogHelper.MarkAsNonPII(algorithm), key))); @@ -406,13 +406,13 @@ private AuthenticatedKeys GetAlgorithmParameters(SecurityKey key, string algorit /// private static string GetHmacAlgorithm(string algorithm) { - if (SecurityAlgorithms.Aes128CbcHmacSha256.Equals(algorithm, StringComparison.Ordinal)) + if (SecurityAlgorithms.Aes128CbcHmacSha256.Equals(algorithm)) return SecurityAlgorithms.HmacSha256; - if (SecurityAlgorithms.Aes192CbcHmacSha384.Equals(algorithm, StringComparison.Ordinal)) + if (SecurityAlgorithms.Aes192CbcHmacSha384.Equals(algorithm)) return SecurityAlgorithms.HmacSha384; - if (SecurityAlgorithms.Aes256CbcHmacSha512.Equals(algorithm, StringComparison.Ordinal)) + if (SecurityAlgorithms.Aes256CbcHmacSha512.Equals(algorithm)) return SecurityAlgorithms.HmacSha512; throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX10652, LogHelper.MarkAsNonPII(algorithm)), nameof(algorithm))); @@ -475,7 +475,7 @@ protected virtual void ValidateKeySize(SecurityKey key, string algorithm) if (string.IsNullOrEmpty(algorithm)) throw LogHelper.LogArgumentNullException(nameof(algorithm)); - if (SecurityAlgorithms.Aes128CbcHmacSha256.Equals(algorithm, StringComparison.Ordinal)) + if (SecurityAlgorithms.Aes128CbcHmacSha256.Equals(algorithm)) { if (key.KeySize < 256) throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), LogHelper.FormatInvariant(LogMessages.IDX10653, LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes128CbcHmacSha256), LogHelper.MarkAsNonPII(256), key.KeyId, LogHelper.MarkAsNonPII(key.KeySize)))); @@ -483,7 +483,7 @@ protected virtual void ValidateKeySize(SecurityKey key, string algorithm) return; } - if (SecurityAlgorithms.Aes192CbcHmacSha384.Equals(algorithm, StringComparison.Ordinal)) + if (SecurityAlgorithms.Aes192CbcHmacSha384.Equals(algorithm)) { if (key.KeySize < 384) throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), LogHelper.FormatInvariant(LogMessages.IDX10653, LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes192CbcHmacSha384), LogHelper.MarkAsNonPII(384), key.KeyId, LogHelper.MarkAsNonPII(key.KeySize)))); @@ -491,7 +491,7 @@ protected virtual void ValidateKeySize(SecurityKey key, string algorithm) return; } - if (SecurityAlgorithms.Aes256CbcHmacSha512.Equals(algorithm, StringComparison.Ordinal)) + if (SecurityAlgorithms.Aes256CbcHmacSha512.Equals(algorithm)) { if (key.KeySize < 512) throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), LogHelper.FormatInvariant(LogMessages.IDX10653, LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes256CbcHmacSha512), LogHelper.MarkAsNonPII(512), key.KeyId, LogHelper.MarkAsNonPII(key.KeySize)))); @@ -499,7 +499,7 @@ protected virtual void ValidateKeySize(SecurityKey key, string algorithm) return; } - if (SecurityAlgorithms.Aes128Gcm.Equals(algorithm, StringComparison.Ordinal)) + if (SecurityAlgorithms.Aes128Gcm.Equals(algorithm)) { if (key.KeySize < 128) throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), LogHelper.FormatInvariant(LogMessages.IDX10653, LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes128Gcm), LogHelper.MarkAsNonPII(128), key.KeyId, LogHelper.MarkAsNonPII(key.KeySize)))); @@ -507,7 +507,7 @@ protected virtual void ValidateKeySize(SecurityKey key, string algorithm) return; } - if (SecurityAlgorithms.Aes192Gcm.Equals(algorithm, StringComparison.Ordinal)) + if (SecurityAlgorithms.Aes192Gcm.Equals(algorithm)) { if (key.KeySize < 192) throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), LogHelper.FormatInvariant(LogMessages.IDX10653, LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes192Gcm), LogHelper.MarkAsNonPII(192), key.KeyId, LogHelper.MarkAsNonPII(key.KeySize)))); @@ -515,7 +515,7 @@ protected virtual void ValidateKeySize(SecurityKey key, string algorithm) return; } - if (SecurityAlgorithms.Aes256Gcm.Equals(algorithm, StringComparison.Ordinal)) + if (SecurityAlgorithms.Aes256Gcm.Equals(algorithm)) { if (key.KeySize < 256) throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), LogHelper.FormatInvariant(LogMessages.IDX10653, LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes256Gcm), LogHelper.MarkAsNonPII(256), key.KeyId, LogHelper.MarkAsNonPII(key.KeySize)))); diff --git a/src/Microsoft.IdentityModel.Tokens/Encryption/EcdhKeyExchangeProvider.cs b/src/Microsoft.IdentityModel.Tokens/Encryption/EcdhKeyExchangeProvider.cs new file mode 100644 index 0000000000..114bb5da28 --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/Encryption/EcdhKeyExchangeProvider.cs @@ -0,0 +1,244 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//------------------------------------------------------------------------------ + +using System; +using System.Text; +using System.Security.Cryptography; +using Microsoft.IdentityModel.Logging; + +namespace Microsoft.IdentityModel.Tokens +{ +#if NET472 || NET6_0 + /// + /// Provides a Security Key that can be used as Content Encryption Key (CEK) for use with a JWE + /// + public class EcdhKeyExchangeProvider + { + /// + /// Number of bits in the desired output key + /// + public int KeyDataLen { get; set; } + + private ECDiffieHellman _ecdhPublic; + private ECDiffieHellman _ecdhPrivate; + private ECParameters _ecParamsPublic; + private ECParameters _ecParamsPrivate; + private string _algorithmId; + + /// + /// Initializes a new instance of used for CEKs + /// The that will be used for cryptographic operations and represents the private key. + /// The that will be used for cryptographic operations and represents the public key. + /// alg header parameter value. + /// enc header parameter value. + /// + public EcdhKeyExchangeProvider(SecurityKey privateKey, SecurityKey publicKey, string alg, string enc) + { + if (privateKey == null) + throw LogHelper.LogArgumentNullException(nameof(privateKey)); + + if (publicKey is null) + throw LogHelper.LogArgumentNullException(nameof(publicKey)); + + ValidateAlgAndEnc(alg, enc); + SetKeyDataLenAndEncryptionAlgorithm(alg, enc); + _ecParamsPublic = GetECParametersFromKey(publicKey, false, nameof(publicKey)); + _ecParamsPrivate = GetECParametersFromKey(privateKey, true, nameof(privateKey)); + ValidateCurves(nameof(privateKey), nameof(publicKey)); + _ecdhPublic = ECDiffieHellman.Create(_ecParamsPublic); + _ecdhPrivate = ECDiffieHellman.Create(_ecParamsPrivate); + } + + /// + /// Generates the KDF + /// + /// Agreement PartyUInfo (optional). When used, the PartyVInfo value contains information about the producer, + /// represented as a base64url-encoded string. + /// Agreement PartyVInfo (optional). When used, the PartyUInfo value contains information about the recipient, + /// represented as a base64url-encoded string. + /// Returns that represents the key generated + public SecurityKey GenerateKdf(string apu = null, string apv = null) + { + //The "apu" and "apv" values MUST be distinct when used (per rfc7518 section 4.6.2) https://datatracker.ietf.org/doc/html/rfc7518#section-4.6.2 + if (!string.IsNullOrEmpty(apu) && !string.IsNullOrEmpty(apv) && apu.Equals(apv)) + throw LogHelper.LogArgumentException( + nameof(apu), + LogHelper.FormatInvariant( + LogMessages.IDX11001, + LogHelper.MarkAsNonPII(nameof(apu)), + LogHelper.MarkAsNonPII(apu), + LogHelper.MarkAsNonPII(nameof(apv)), + LogHelper.MarkAsNonPII(apv)) + ); + + int kdfLength = KeyDataLen / 8; // number of octets + // prepend bytes that represent n = ceiling of (keydatalen / hashlen), see section 5.8.1.1: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf + // hashlen is always 256 for ecdh-es, see: https://datatracker.ietf.org/doc/html/rfc7518#section-4.6.2 + // for supported algorithms it is always '1', for saml might be different + byte[] prepend = new byte[4] { 0, 0, 0, 1 }; + SetAppendBytes(apu, apv, out byte[] append); + byte[] kdf = new byte[kdfLength]; + + // JWA's spec https://datatracker.ietf.org/doc/html/rfc7518#section-4.6.2 specifies SHA256, saml might be different + byte[] derivedKey = _ecdhPrivate.DeriveKeyFromHash(_ecdhPublic.PublicKey, HashAlgorithmName.SHA256, prepend, append); + Array.Copy(derivedKey, kdf, kdfLength); + + return new SymmetricSecurityKey(kdf); + } + + private void SetAppendBytes(string apu, string apv, out byte[] append) + { + byte[] encBytes = Encoding.ASCII.GetBytes(_algorithmId); + byte[] apuBytes = Base64UrlEncoder.DecodeBytes(string.IsNullOrEmpty(apu) ? string.Empty : apu); + byte[] apvBytes = Base64UrlEncoder.DecodeBytes(string.IsNullOrEmpty(apv) ? string.Empty : apv); + byte[] numOctetsEnc = BitConverter.GetBytes(encBytes.Length); + byte[] numOctetsApu = BitConverter.GetBytes(apuBytes.Length); + byte[] numOctetsApv = BitConverter.GetBytes(apvBytes.Length); + byte[] keyDataLengthBytes = BitConverter.GetBytes(KeyDataLen); + + if (BitConverter.IsLittleEndian) + { + // these representations need to be big-endian + Array.Reverse(numOctetsEnc); + Array.Reverse(numOctetsApu); + Array.Reverse(numOctetsApv); + Array.Reverse(keyDataLengthBytes); + } + + append = Concat(numOctetsEnc, encBytes, numOctetsApu, apuBytes, numOctetsApv, apvBytes, keyDataLengthBytes); + } + + private void SetKeyDataLenAndEncryptionAlgorithm(string alg, string enc = null) + { + if (SecurityAlgorithms.EcdhEs.Equals(alg, StringComparison.InvariantCulture)) + { + _algorithmId = enc; + if (SecurityAlgorithms.Aes128Gcm.Equals(enc, StringComparison.InvariantCulture)) + KeyDataLen = 128; + else if (SecurityAlgorithms.Aes192Gcm.Equals(enc, StringComparison.InvariantCulture)) + KeyDataLen = 192; + else if (SecurityAlgorithms.Aes256Gcm.Equals(enc, StringComparison.InvariantCulture)) + KeyDataLen = 256; + else if (SecurityAlgorithms.Aes128CbcHmacSha256.Equals(enc, StringComparison.InvariantCulture)) + KeyDataLen = 128; + else if (SecurityAlgorithms.Aes192CbcHmacSha384.Equals(enc, StringComparison.InvariantCulture)) + KeyDataLen = 192; + else if (SecurityAlgorithms.Aes256CbcHmacSha512.Equals(enc, StringComparison.InvariantCulture)) + KeyDataLen = 256; + } + else + { + _algorithmId = alg; + + if (SecurityAlgorithms.EcdhEsA128kw.Equals(alg, StringComparison.InvariantCulture)) + KeyDataLen = 128; + else if (SecurityAlgorithms.EcdhEsA192kw.Equals(alg, StringComparison.InvariantCulture)) + KeyDataLen = 192; + else if (SecurityAlgorithms.EcdhEsA256kw.Equals(alg, StringComparison.InvariantCulture)) + KeyDataLen = 256; + } + } + + private static void ValidateAlgAndEnc(string alg, string enc) + { + if (string.IsNullOrEmpty(alg)) + throw LogHelper.LogArgumentNullException(alg); + if (string.IsNullOrEmpty(enc)) + throw LogHelper.LogArgumentNullException(enc); + + if (!SupportedAlgorithms.EcdsaWrapAlgorithms.Contains(alg) && !SecurityAlgorithms.EcdhEs.Equals(alg, StringComparison.InvariantCulture)) + throw LogHelper.LogExceptionMessage(new NotSupportedException(LogHelper.FormatInvariant(LogMessages.IDX10652, LogHelper.MarkAsNonPII(alg)))); + + if (!SupportedAlgorithms.SymmetricEncryptionAlgorithms.Contains(enc)) + throw LogHelper.LogExceptionMessage(new NotSupportedException(LogHelper.FormatInvariant(LogMessages.IDX10715, LogHelper.MarkAsNonPII(enc)))); + } + + private void ValidateCurves(string privateKeyArgName, string publicKeyArgName) + { + if (_ecParamsPrivate.Curve.Equals(_ecParamsPublic.Curve)) + { + throw LogHelper.LogArgumentException( + privateKeyArgName, + LogHelper.FormatInvariant( + LogMessages.IDX11000, + LogHelper.MarkAsNonPII(privateKeyArgName), + LogHelper.MarkAsNonPII(_ecParamsPrivate.Curve.ToString()), + LogHelper.MarkAsNonPII(publicKeyArgName), + LogHelper.MarkAsNonPII(_ecParamsPublic.Curve.ToString())) + ); + } + } + + private static ECParameters GetECParametersFromKey(SecurityKey key, bool isPrivate, string nameOfKey) + { + if (key is ECDsaSecurityKey ecdsaKey) + { + return ecdsaKey.ECDsa.ExportParameters(isPrivate); + } + else if (key is JsonWebKey jwk + && JsonWebKeyConverter.TryConvertToECDsaSecurityKey(jwk, out SecurityKey securityKey)) + { + return ((ECDsaSecurityKey)securityKey).ECDsa.ExportParameters(isPrivate); + } + else + { + throw LogHelper.LogArgumentException( + nameOfKey, + LogHelper.FormatInvariant(LogMessages.IDX11002, LogHelper.MarkAsNonPII(nameOfKey))); + } + } + + private static byte[] Concat(params byte[][] arrays) + { + int outputLength = 0; + foreach (byte[] arr in arrays) + outputLength += arr.Length; + + byte[] output = new byte[outputLength]; + int x = 0; + foreach (byte[] arr in arrays) + { + Array.Copy(arr, 0, output, x, arr.Length); + x += arr.Length; + } + + return output; + } + + internal string GetEncryptionAlgorithm() + { + if (_algorithmId.Equals(SecurityAlgorithms.EcdhEsA128kw, StringComparison.Ordinal)) + return SecurityAlgorithms.Aes128KW; + if (_algorithmId.Equals(SecurityAlgorithms.EcdhEsA192kw, StringComparison.Ordinal)) + return SecurityAlgorithms.Aes192KW; + if (_algorithmId.Equals(SecurityAlgorithms.EcdhEsA256kw, StringComparison.Ordinal)) + return SecurityAlgorithms.Aes256KW; + return _algorithmId; + } + } +#endif +} diff --git a/src/Microsoft.IdentityModel.Tokens/Encryption/SymmetricKeyWrapProvider.cs b/src/Microsoft.IdentityModel.Tokens/Encryption/SymmetricKeyWrapProvider.cs index a1ccc3f996..ff79d0c9b6 100644 --- a/src/Microsoft.IdentityModel.Tokens/Encryption/SymmetricKeyWrapProvider.cs +++ b/src/Microsoft.IdentityModel.Tokens/Encryption/SymmetricKeyWrapProvider.cs @@ -337,7 +337,7 @@ Return an error private void ValidateKeySize(byte[] key, string algorithm) { - if (SecurityAlgorithms.Aes128KW.Equals(algorithm, StringComparison.Ordinal) || SecurityAlgorithms.Aes128KeyWrap.Equals(algorithm, StringComparison.Ordinal)) + if (SecurityAlgorithms.Aes128KW.Equals(algorithm) || SecurityAlgorithms.Aes128KeyWrap.Equals(algorithm)) { if (key.Length != 16) throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), LogHelper.FormatInvariant(LogMessages.IDX10662, LogHelper.MarkAsNonPII(algorithm), LogHelper.MarkAsNonPII(128), Key.KeyId, LogHelper.MarkAsNonPII(key.Length << 3)))); @@ -345,7 +345,15 @@ private void ValidateKeySize(byte[] key, string algorithm) return; } - if (SecurityAlgorithms.Aes256KW.Equals(algorithm, StringComparison.Ordinal) || (SecurityAlgorithms.Aes256KeyWrap.Equals(algorithm, StringComparison.Ordinal))) + if (SecurityAlgorithms.Aes192KW.Equals(algorithm) || SecurityAlgorithms.Aes192KeyWrap.Equals(algorithm)) + { + if (key.Length != 24) + throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), LogHelper.FormatInvariant(LogMessages.IDX10662, LogHelper.MarkAsNonPII(algorithm), LogHelper.MarkAsNonPII(128), Key.KeyId, LogHelper.MarkAsNonPII(key.Length << 3)))); + + return; + } + + if (SecurityAlgorithms.Aes256KW.Equals(algorithm) || (SecurityAlgorithms.Aes256KeyWrap.Equals(algorithm))) { if (key.Length != 32) throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), LogHelper.FormatInvariant(LogMessages.IDX10662, LogHelper.MarkAsNonPII(algorithm), LogHelper.MarkAsNonPII(256), Key.KeyId, LogHelper.MarkAsNonPII(key.Length << 3)))); diff --git a/src/Microsoft.IdentityModel.Tokens/EventBasedLRUCache.cs b/src/Microsoft.IdentityModel.Tokens/EventBasedLRUCache.cs index 24a6e8b336..3ed42cec80 100644 --- a/src/Microsoft.IdentityModel.Tokens/EventBasedLRUCache.cs +++ b/src/Microsoft.IdentityModel.Tokens/EventBasedLRUCache.cs @@ -95,6 +95,10 @@ internal class EventBasedLRUCache private const int EventQueueTaskDoNotStop = 2; // force the task to continue even it has past the _eventQueueTaskStopTime, see StartEventQueueTaskIfNotRunning() for more details. private int _eventQueueTaskState = EventQueueTaskStopped; + private const int CompactionNotQueued = 0; // compaction action not in the event queue + private const int CompactionQueuedOrRunning = 1; // compaction action in the event queue or currently in progress + private int _compactionState = CompactionNotQueued; + // set to true when the AppDomain is to be unloaded or the default AppDomain process is ready to exit private bool _shouldStopImmediately = false; @@ -330,6 +334,9 @@ private void CompactLRU() _doubleLinkedList.RemoveLast(); } + + // reset _compactionState so the compaction action can be queued again when needed + _compactionState = CompactionNotQueued; } /// @@ -350,6 +357,9 @@ private void Compact() OnItemRemoved?.Invoke(cacheItem.Value); } } + + // reset _compactionState so the compaction action can be queued again when needed + _compactionState = CompactionNotQueued; } /// @@ -415,10 +425,13 @@ public bool SetValue(TKey key, TValue value, DateTime expirationTime) // if cache is at _maxCapacityPercentage, trim it by _compactionPercentage if ((double)_map.Count / _capacity >= _maxCapacityPercentage) { - if (_maintainLRU) - _eventQueue.Enqueue(CompactLRU); - else - _eventQueue.Enqueue(Compact); + if (Interlocked.CompareExchange(ref _compactionState, CompactionQueuedOrRunning, CompactionNotQueued) == CompactionNotQueued) + { + if (_maintainLRU) + AddActionToEventQueue(CompactLRU); + else + AddActionToEventQueue(Compact); + } } var newCacheItem = new LRUCacheItem(key, value, expirationTime); @@ -569,11 +582,6 @@ public bool TryRemove(TKey key, out TValue value) /// internal void WaitForProcessing() { - // The _eventQueue can be non-empty only if _maintainLRU = true. - // If _maintainLRU = false, neither the _doubleLinkedList nor _eventQueue will be used. - if (!_maintainLRU) - return; - while (!_eventQueue.IsEmpty); } diff --git a/src/Microsoft.IdentityModel.Tokens/Exceptions/SecurityTokenException.cs b/src/Microsoft.IdentityModel.Tokens/Exceptions/SecurityTokenException.cs index 2f19b51bc4..a886ba64eb 100644 --- a/src/Microsoft.IdentityModel.Tokens/Exceptions/SecurityTokenException.cs +++ b/src/Microsoft.IdentityModel.Tokens/Exceptions/SecurityTokenException.cs @@ -76,7 +76,7 @@ protected SecurityTokenException(SerializationInfo info, StreamingContext contex { } -#if NET472 || NETSTANDARD2_0 +#if NET472 || NETSTANDARD2_0 || NET6_0 /// /// When overridden in a derived class, sets the System.Runtime.Serialization.SerializationInfo /// with information about the exception. diff --git a/src/Microsoft.IdentityModel.Tokens/GlobalSuppressions.cs b/src/Microsoft.IdentityModel.Tokens/GlobalSuppressions.cs index f765eb3379..86381917d7 100644 --- a/src/Microsoft.IdentityModel.Tokens/GlobalSuppressions.cs +++ b/src/Microsoft.IdentityModel.Tokens/GlobalSuppressions.cs @@ -17,14 +17,13 @@ [assembly: SuppressMessage("Usage", "CA2207:Initialize value type static fields inline", Justification = "Vendored component", Scope = "namespaceanddescendants", Target = "Microsoft.IdentityModel.Json")] [assembly: SuppressMessage("Performance", "CA1810:Initialize reference type static fields inline", Justification = "Vendored component", Scope = "namespaceanddescendants", Target = "Microsoft.IdentityModel.Json")] [assembly: SuppressMessage("Performance", "CA1825:Avoid zero-length array allocations.", Justification = "vendored", Scope = "namespaceanddescendants", Target = "Microsoft.IdentityModel.Json")] -[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Vendored component", Scope = "namespaceanddescendants", Target = "Microsoft.IdentityModel.Json")] +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Vendored component", Scope = "module")] [assembly: SuppressMessage("Performance", "CA1820:Test for empty strings using string length", Justification = "Vendored component", Scope = "namespaceanddescendants", Target = "Microsoft.IdentityModel.Json")] [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Vendored component", Scope = "namespaceanddescendants", Target = "Microsoft.IdentityModel.Json")] [assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Breaking change", Scope = "member", Target = "~P:Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor.AdditionalHeaderClaims")] [assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Breaking change", Scope = "member", Target = "~P:Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor.Claims")] [assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Breaking change", Scope = "member", Target = "~P:Microsoft.IdentityModel.Tokens.JsonWebKey.Oth")] -[assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Breaking change", Scope = "member", Target = "~P:Microsoft.IdentityModel.Tokens.CallContext.PropertyBag")] [assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Breaking chnage", Scope = "member", Target = "~P:Microsoft.IdentityModel.Tokens.TokenValidationParameters.PropertyBag")] [assembly: SuppressMessage("Usage", "CA2214:Do not call overridable methods in constructors", Justification = "Current design", Scope = "member", Target = "~M:Microsoft.IdentityModel.Tokens.TokenValidationParameters.#ctor(Microsoft.IdentityModel.Tokens.TokenValidationParameters)")] [assembly: SuppressMessage("Usage", "CA2213:Disposable fields should be disposed", Justification = "Disposed through ReleaseSignatureProvider", Scope = "member", Target = "~F:Microsoft.IdentityModel.Tokens.AuthenticatedEncryptionProvider._symmetricSignatureProvider")] @@ -54,9 +53,12 @@ [assembly: SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "Not using Globalization", Scope = "member", Target = "~M:Microsoft.IdentityModel.Tokens.Interop.Kernel32.GetMessage(System.Int32,System.IntPtr)~System.String")] [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exception is written to a string", Scope = "member", Target = "~M:Microsoft.IdentityModel.Tokens.EventBasedLRUCache`2.EventQueueTaskAction")] [assembly: SuppressMessage("Design", "CA1001:Types That own disposable fields should be disposable", Justification = "Exceptions can occurr if disposed of", Scope = "type", Target = "~T:Microsoft.IdentityModel.Tokens.EventBasedLRUCache`2")] +[assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Consistency", Scope = "member", Target = "~P:Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor.AdditionalInnerHeaderClaims")] [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Used as validation", Scope = "member", Target = "~M:Microsoft.IdentityModel.Tokens.InternalValidators.ValidateLifetimeAndIssuerAfterSignatureNotValidatedJwt(Microsoft.IdentityModel.Tokens.SecurityToken,System.Nullable{System.DateTime},System.Nullable{System.DateTime},System.String,Microsoft.IdentityModel.Tokens.TokenValidationParameters,Microsoft.IdentityModel.Tokens.BaseConfiguration,System.Text.StringBuilder,System.Int32,System.Int32)")] -#if NET472 || NETSTANDARD2_0 +#if NET472 || NETSTANDARD2_0 || NET6_0 [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Used to determine appropriate code path to take.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Tokens.JsonWebKeyConverter.ConvertFromECDsaSecurityKey(Microsoft.IdentityModel.Tokens.ECDsaSecurityKey)~Microsoft.IdentityModel.Tokens.JsonWebKey")] +[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Used to determine appropriate code path to take.", Scope = "member", Target = "~P:Microsoft.IdentityModel.Tokens.EcdhSecurityKey.PrivateKeyStatus")] +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Adding StringComparison.Ordinal adds a performance penalty.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Tokens.EcdhKeyExchangeProvider.GenerateKdf(System.String,System.String)~Microsoft.IdentityModel.Tokens.SecurityKey")] #endif #if !NET472 [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Used as validation", Scope = "member", Target = "~M:Microsoft.IdentityModel.Tokens.ECDsaAdapter.SupportsECParameters~System.Boolean")] diff --git a/src/Microsoft.IdentityModel.Tokens/JsonWebKey.cs b/src/Microsoft.IdentityModel.Tokens/JsonWebKey.cs index be9a76307c..52a1628bba 100644 --- a/src/Microsoft.IdentityModel.Tokens/JsonWebKey.cs +++ b/src/Microsoft.IdentityModel.Tokens/JsonWebKey.cs @@ -349,11 +349,11 @@ public override bool CanComputeJwkThumbprint() if (string.IsNullOrEmpty(Kty)) return false; - if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.EllipticCurve, StringComparison.Ordinal)) + if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.EllipticCurve)) return CanComputeECThumbprint(); - else if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.RSA, StringComparison.Ordinal)) + else if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.RSA)) return CanComputeRsaThumbprint(); - else if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.Octet, StringComparison.Ordinal)) + else if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.Octet)) return CanComputeOctThumbprint(); else return false; @@ -369,11 +369,11 @@ public override byte[] ComputeJwkThumbprint() if (string.IsNullOrEmpty(Kty)) throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX10705, LogHelper.MarkAsNonPII(nameof(Kty))))); - if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.EllipticCurve, StringComparison.Ordinal)) + if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.EllipticCurve)) return ComputeECThumbprint(); - else if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.RSA, StringComparison.Ordinal)) + else if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.RSA)) return ComputeRsaThumbprint(); - else if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.Octet, StringComparison.Ordinal)) + else if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.Octet)) return ComputeOctThumbprint(); else throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX10706, LogHelper.MarkAsNonPII(nameof(Kty)), LogHelper.MarkAsNonPII(string.Join(", ", JsonWebAlgorithmsKeyTypes.EllipticCurve, JsonWebAlgorithmsKeyTypes.RSA, JsonWebAlgorithmsKeyTypes.Octet)), LogHelper.MarkAsNonPII(nameof(Kty))))); @@ -442,9 +442,9 @@ internal string RepresentAsAsymmetricPublicJwk() if (!string.IsNullOrEmpty(Kid)) jwk.Add(JsonWebKeyParameterNames.Kid, Kid); - if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.EllipticCurve, StringComparison.Ordinal)) + if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.EllipticCurve)) PopulateWithPublicEcParams(jwk); - else if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.RSA, StringComparison.Ordinal)) + else if (string.Equals(Kty, JsonWebAlgorithmsKeyTypes.RSA)) PopulateWithPublicRsaParams(jwk); else throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX10707, LogHelper.MarkAsNonPII(nameof(Kty)), LogHelper.MarkAsNonPII(string.Join(", ", JsonWebAlgorithmsKeyTypes.EllipticCurve, JsonWebAlgorithmsKeyTypes.RSA)), LogHelper.MarkAsNonPII(nameof(Kty))))); diff --git a/src/Microsoft.IdentityModel.Tokens/JsonWebKeyConverter.cs b/src/Microsoft.IdentityModel.Tokens/JsonWebKeyConverter.cs index 3f67041835..bea9c6769e 100644 --- a/src/Microsoft.IdentityModel.Tokens/JsonWebKeyConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/JsonWebKeyConverter.cs @@ -57,7 +57,7 @@ public static JsonWebKey ConvertFromSecurityKey(SecurityKey key) return ConvertFromSymmetricSecurityKey(symmetricKey); else if (key is X509SecurityKey x509Key) return ConvertFromX509SecurityKey(x509Key); -#if NET472 || NETSTANDARD2_0 +#if NET472 || NETSTANDARD2_0 || NET6_0 else if (key is ECDsaSecurityKey ecdsaSecurityKey) return ConvertFromECDsaSecurityKey(ecdsaSecurityKey); #endif @@ -181,7 +181,7 @@ public static JsonWebKey ConvertFromSymmetricSecurityKey(SymmetricSecurityKey ke }; } -#if NET472 || NETSTANDARD2_0 +#if NET472 || NETSTANDARD2_0 || NET6_0 /// /// Converts a into a /// @@ -233,7 +233,7 @@ internal static bool TryConvertToSecurityKey(JsonWebKey webKey, out SecurityKey key = null; try { - if (JsonWebAlgorithmsKeyTypes.RSA.Equals(webKey.Kty, StringComparison.Ordinal)) + if (JsonWebAlgorithmsKeyTypes.RSA.Equals(webKey.Kty)) { if (TryConvertToX509SecurityKey(webKey, out key)) return true; @@ -241,11 +241,11 @@ internal static bool TryConvertToSecurityKey(JsonWebKey webKey, out SecurityKey if (TryCreateToRsaSecurityKey(webKey, out key)) return true; } - else if (JsonWebAlgorithmsKeyTypes.EllipticCurve.Equals(webKey.Kty, StringComparison.Ordinal)) + else if (JsonWebAlgorithmsKeyTypes.EllipticCurve.Equals(webKey.Kty)) { return TryConvertToECDsaSecurityKey(webKey, out key); } - else if (JsonWebAlgorithmsKeyTypes.Octet.Equals(webKey.Kty, StringComparison.Ordinal)) + else if (JsonWebAlgorithmsKeyTypes.Octet.Equals(webKey.Kty)) { return TryConvertToSymmetricSecurityKey(webKey, out key); } diff --git a/src/Microsoft.IdentityModel.Tokens/JsonWebKeySet.cs b/src/Microsoft.IdentityModel.Tokens/JsonWebKeySet.cs index 21047bbaf1..b021382260 100644 --- a/src/Microsoft.IdentityModel.Tokens/JsonWebKeySet.cs +++ b/src/Microsoft.IdentityModel.Tokens/JsonWebKeySet.cs @@ -123,7 +123,7 @@ public IList GetSigningKeys() { // skip if "use" (Public Key Use) parameter is not empty or "sig". // https://datatracker.ietf.org/doc/html/rfc7517#section-4.2 - if (!string.IsNullOrEmpty(webKey.Use) && !webKey.Use.Equals(JsonWebKeyUseNames.Sig, StringComparison.Ordinal)) + if (!string.IsNullOrEmpty(webKey.Use) && !webKey.Use.Equals(JsonWebKeyUseNames.Sig)) { string convertKeyInfo = LogHelper.FormatInvariant(LogMessages.IDX10808, webKey, webKey.Use); webKey.ConvertKeyInfo = convertKeyInfo; @@ -134,7 +134,7 @@ public IList GetSigningKeys() continue; } - if (JsonWebAlgorithmsKeyTypes.RSA.Equals(webKey.Kty, StringComparison.Ordinal)) + if (JsonWebAlgorithmsKeyTypes.RSA.Equals(webKey.Kty)) { var rsaKeyResolved = true; @@ -167,7 +167,7 @@ public IList GetSigningKeys() if (!rsaKeyResolved && !SkipUnresolvedJsonWebKeys) signingKeys.Add(webKey); } - else if (JsonWebAlgorithmsKeyTypes.EllipticCurve.Equals(webKey.Kty, StringComparison.Ordinal)) + else if (JsonWebAlgorithmsKeyTypes.EllipticCurve.Equals(webKey.Kty)) { if (JsonWebKeyConverter.TryConvertToECDsaSecurityKey(webKey, out SecurityKey securityKey)) signingKeys.Add(securityKey); diff --git a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs index 96ae25e1e8..02cdc229e4 100644 --- a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs +++ b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs @@ -143,6 +143,7 @@ internal static class LogMessages public const string IDX10618 = "IDX10618: Key unwrap failed using decryption Keys: '{0}'.\nExceptions caught:\n '{1}'.\ntoken: '{2}'."; public const string IDX10619 = "IDX10619: Decryption failed. Algorithm: '{0}'. Either the Encryption Algorithm: '{1}' or none of the Security Keys are supported by the CryptoProviderFactory."; public const string IDX10620 = "IDX10620: Unable to obtain a CryptoProviderFactory, both EncryptingCredentials.CryptoProviderFactory and EncryptingCredentials.Key.CrypoProviderFactory are null."; + public const string IDX10903 = "IDX10903: Token decryption succeeded. With thumbprint: '{0}'."; // Formating public const string IDX10400 = "IDX10400: Unable to decode: '{0}' as Base64url encoded string."; @@ -260,6 +261,11 @@ internal static class LogMessages public const string IDX10900 = "IDX10900: EventBasedLRUCache._eventQueue encountered an error while processing a cache operation. Exception '{0}'."; public const string IDX10901 = "IDX10901: CryptoProviderCacheOptions.SizeLimit must be greater than 10. Value: '{0}'"; public const string IDX10902 = "IDX10902: Object disposed exception in '{0}': '{1}'"; + + // Crypto Errors + public const string IDX11000 = "IDX11000: Cannot create EcdhKeyExchangeProvider. '{0}'\'s Curve '{1}' does not match with '{2}'\'s curve '{3}'."; + public const string IDX11001 = "IDX11001: Cannot generate KDF. '{0}':'{1}' and '{2}':'{3}' must be different."; + public const string IDX11002 = "IDX11002: Cannot create the EcdhKeyExchangeProvider. Unable to obtain ECParameters from {0}. Verify the SecurityKey is an ECDsaSecurityKey or JsonWebKey and that properties Crv, X, Y, and D (if used for a private key) are contained in the provided SecurityKey."; #pragma warning restore 1591 } } diff --git a/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj b/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj index d54ff4ea3c..b3fabb4d3a 100644 --- a/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj +++ b/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj @@ -13,11 +13,15 @@ - $(DefineConstants);TRACE;DESKTOP;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY; + $(DefineConstants);TRACE;DESKTOP;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_REGEX_TIMEOUTS;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants) - $(DefineConstants);TRACE;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants) + $(DefineConstants);TRACE;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants) + + + + $(DefineConstants);HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_ASYNC_DISPOSABLE;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_REGEX_TIMEOUTS;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;HAVE_INDEXOF_STRING_COMPARISON;HAVE_REPLACE_STRING_COMPARISON;HAVE_REPLACE_STRING_COMPARISON;HAVE_GETHASHCODE_STRING_COMPARISON;HAVE_NULLABLE_ATTRIBUTES;HAVE_DYNAMIC_CODE_COMPILED;HAS_ARRAY_EMPTY;HAVE_DATE_ONLY;$(AdditionalConstants) @@ -30,7 +34,7 @@ - + diff --git a/src/Microsoft.IdentityModel.Tokens/RsaSecurityKey.cs b/src/Microsoft.IdentityModel.Tokens/RsaSecurityKey.cs index eacd408112..5a27d78107 100644 --- a/src/Microsoft.IdentityModel.Tokens/RsaSecurityKey.cs +++ b/src/Microsoft.IdentityModel.Tokens/RsaSecurityKey.cs @@ -100,7 +100,7 @@ public override bool HasPrivateKey { // imitate signing byte[] hash = new byte[20]; -#if NET461 || NET472 || NETSTANDARD2_0 +#if NET461 || NET472 || NETSTANDARD2_0 || NET6_0 Rsa.SignData(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); #else if (Rsa is RSACryptoServiceProvider rsaCryptoServiceProvider) diff --git a/src/Microsoft.IdentityModel.Tokens/SecurityAlgorithms.cs b/src/Microsoft.IdentityModel.Tokens/SecurityAlgorithms.cs index bdbafc8e04..25947ca389 100644 --- a/src/Microsoft.IdentityModel.Tokens/SecurityAlgorithms.cs +++ b/src/Microsoft.IdentityModel.Tokens/SecurityAlgorithms.cs @@ -51,6 +51,7 @@ public static class SecurityAlgorithms // See: https://datatracker.ietf.org/doc/html/rfc7518#section-4.1 public const string Aes128KW = "A128KW"; + public const string Aes192KW = "A192KW"; public const string Aes256KW = "A256KW"; public const string RsaPKCS1 = "RSA1_5"; public const string RsaOAEP = "RSA-OAEP"; @@ -119,6 +120,13 @@ public static class SecurityAlgorithms internal const string DefaultAsymmetricKeyWrapAlgorithm = RsaOaepKeyWrap; internal const string DefaultSymmetricEncryptionAlgorithm = Aes128CbcHmacSha256; + // See: https://datatracker.ietf.org/doc/html/rfc7518#section-4.6 + public const string EcdhEsA128kw = "ECDH-ES+A128KW"; + public const string EcdhEsA192kw = "ECDH-ES+A192KW"; + public const string EcdhEsA256kw = "ECDH-ES+A256KW"; + + // See: https://datatracker.ietf.org/doc/html/rfc7518#section-4.6 + public const string EcdhEs = "ECDH-ES"; #pragma warning restore 1591 } } diff --git a/src/Microsoft.IdentityModel.Tokens/SecurityTokenDescriptor.cs b/src/Microsoft.IdentityModel.Tokens/SecurityTokenDescriptor.cs index 483c7151fa..21fe63733a 100644 --- a/src/Microsoft.IdentityModel.Tokens/SecurityTokenDescriptor.cs +++ b/src/Microsoft.IdentityModel.Tokens/SecurityTokenDescriptor.cs @@ -96,6 +96,17 @@ public class SecurityTokenDescriptor /// public IDictionary AdditionalHeaderClaims { get; set; } + /// + /// Gets or sets the which contains any custom header claims that need to be added to the inner JWT token header. + /// The 'alg', 'kid', 'x5t', 'enc', and 'zip' claims are added by default based on the , + /// , and/or provided and SHOULD NOT be included in this dictionary as this + /// will result in an exception being thrown. + /// + /// For JsonWebTokenHandler, these claims are merged with while adding to the inner JWT header. + /// + /// + public IDictionary AdditionalInnerHeaderClaims { get; set; } + /// /// Gets or sets the used to create a security token. /// diff --git a/src/Microsoft.IdentityModel.Tokens/SupportedAlgorithms.cs b/src/Microsoft.IdentityModel.Tokens/SupportedAlgorithms.cs index 61d6b1d54e..88c9c6d9b5 100644 --- a/src/Microsoft.IdentityModel.Tokens/SupportedAlgorithms.cs +++ b/src/Microsoft.IdentityModel.Tokens/SupportedAlgorithms.cs @@ -38,6 +38,8 @@ namespace Microsoft.IdentityModel.Tokens /// internal static class SupportedAlgorithms { + private const int RsaMinKeySize = 2048; + internal static readonly ICollection EcdsaSigningAlgorithms = new Collection { SecurityAlgorithms.EcdsaSha256, @@ -100,8 +102,13 @@ internal static class SupportedAlgorithms { SecurityAlgorithms.Aes128KW, SecurityAlgorithms.Aes128KeyWrap, + SecurityAlgorithms.Aes192KW, + SecurityAlgorithms.Aes192KeyWrap, SecurityAlgorithms.Aes256KW, - SecurityAlgorithms.Aes256KeyWrap + SecurityAlgorithms.Aes256KeyWrap, + SecurityAlgorithms.EcdhEsA128kw, + SecurityAlgorithms.EcdhEsA192kw, + SecurityAlgorithms.EcdhEsA256kw }; internal static readonly ICollection SymmetricSigningAlgorithms = new Collection @@ -114,7 +121,14 @@ internal static class SupportedAlgorithms SecurityAlgorithms.HmacSha512Signature }; -#if NET461 || NET472 || NETSTANDARD2_0 + internal static readonly ICollection EcdsaWrapAlgorithms = new Collection + { + SecurityAlgorithms.EcdhEsA128kw, + SecurityAlgorithms.EcdhEsA192kw, + SecurityAlgorithms.EcdhEsA256kw + }; + +#if NET461 || NET472 || NETSTANDARD2_0 || NET6_0 /// /// Creating a Signature requires the use of a . /// This method returns the @@ -236,11 +250,11 @@ public static bool IsSupportedAlgorithm(string algorithm, SecurityKey key) if (key is JsonWebKey jsonWebKey) { - if (JsonWebAlgorithmsKeyTypes.RSA.Equals(jsonWebKey.Kty, StringComparison.Ordinal)) + if (JsonWebAlgorithmsKeyTypes.RSA.Equals(jsonWebKey.Kty)) return IsSupportedRsaAlgorithm(algorithm, key); - else if (JsonWebAlgorithmsKeyTypes.EllipticCurve.Equals(jsonWebKey.Kty, StringComparison.Ordinal)) + else if (JsonWebAlgorithmsKeyTypes.EllipticCurve.Equals(jsonWebKey.Kty)) return IsSupportedEcdsaAlgorithm(algorithm); - else if (JsonWebAlgorithmsKeyTypes.Octet.Equals(jsonWebKey.Kty, StringComparison.Ordinal)) + else if (JsonWebAlgorithmsKeyTypes.Octet.Equals(jsonWebKey.Kty)) return IsSupportedSymmetricAlgorithm(algorithm); return false; @@ -280,9 +294,9 @@ internal static bool IsAesGcm(string algorithm) if (string.IsNullOrEmpty(algorithm)) return false; - return algorithm.Equals(SecurityAlgorithms.Aes128Gcm, StringComparison.Ordinal) - || algorithm.Equals(SecurityAlgorithms.Aes192Gcm, StringComparison.Ordinal) - || algorithm.Equals(SecurityAlgorithms.Aes256Gcm, StringComparison.Ordinal); + return algorithm.Equals(SecurityAlgorithms.Aes128Gcm) + || algorithm.Equals(SecurityAlgorithms.Aes192Gcm) + || algorithm.Equals(SecurityAlgorithms.Aes256Gcm); } internal static bool IsAesCbc(string algorithm) @@ -290,9 +304,9 @@ internal static bool IsAesCbc(string algorithm) if (string.IsNullOrEmpty(algorithm)) return false; - return algorithm.Equals(SecurityAlgorithms.Aes128CbcHmacSha256, StringComparison.Ordinal) - || algorithm.Equals(SecurityAlgorithms.Aes192CbcHmacSha384, StringComparison.Ordinal) - || algorithm.Equals(SecurityAlgorithms.Aes256CbcHmacSha512, StringComparison.Ordinal); + return algorithm.Equals(SecurityAlgorithms.Aes128CbcHmacSha256) + || algorithm.Equals(SecurityAlgorithms.Aes192CbcHmacSha384) + || algorithm.Equals(SecurityAlgorithms.Aes256CbcHmacSha512); } private static bool IsSupportedEcdsaAlgorithm(string algorithm) @@ -317,7 +331,7 @@ internal static bool IsSupportedRsaKeyWrap(string algorithm, SecurityKey key) return false; if (key is RsaSecurityKey || key is X509SecurityKey || (key is JsonWebKey rsaJsonWebKey && rsaJsonWebKey.Kty == JsonWebAlgorithmsKeyTypes.RSA)) - return key.KeySize >= 2048; + return key.KeySize >= RsaMinKeySize; return false; } @@ -349,7 +363,7 @@ private static bool IsSupportedRsaPss(SecurityKey key) // RSA-PSS is not available on .NET 4.5 LogHelper.LogInformation(LogMessages.IDX10692); return false; -#elif NET461 || NET472 || NETSTANDARD2_0 +#elif NET461 || NET472 || NETSTANDARD2_0 || NET6_0 // RSACryptoServiceProvider doesn't support RSA-PSS if (key is RsaSecurityKey rsa && rsa.Rsa is RSACryptoServiceProvider) { diff --git a/src/Microsoft.IdentityModel.Tokens/TokenUtilities.cs b/src/Microsoft.IdentityModel.Tokens/TokenUtilities.cs index a4a8224df0..a5b54e3142 100644 --- a/src/Microsoft.IdentityModel.Tokens/TokenUtilities.cs +++ b/src/Microsoft.IdentityModel.Tokens/TokenUtilities.cs @@ -78,7 +78,7 @@ internal static IDictionary CreateDictionaryFromClaims(IEnumerab continue; string jsonClaimType = claim.Type; - object jsonClaimValue = claim.ValueType.Equals(ClaimValueTypes.String, StringComparison.Ordinal) ? claim.Value : GetClaimValueUsingValueType(claim); + object jsonClaimValue = claim.ValueType.Equals(ClaimValueTypes.String) ? claim.Value : GetClaimValueUsingValueType(claim); object existingValue; // If there is an existing value, append to it. @@ -244,7 +244,7 @@ internal static bool IsRecoverableConfiguration(TokenValidationParameters valida LogHelper.LogInformation(TokenLogMessages.IDX10263); return false; } - else + else currentConfiguration = validationParameters.ConfigurationManager.LastKnownGoodConfiguration; } diff --git a/src/Microsoft.IdentityModel.Tokens/Validators.cs b/src/Microsoft.IdentityModel.Tokens/Validators.cs index 2ed42e92a5..608da0bfbf 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validators.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validators.cs @@ -161,7 +161,7 @@ private static bool AudiencesMatch(TokenValidationParameters validationParameter { if (validAudience.Length == tokenAudience.Length) { - if (string.Equals(validAudience, tokenAudience, StringComparison.Ordinal)) + if (string.Equals(validAudience, tokenAudience)) return true; } else if (validationParameters.IgnoreTrailingSlashWhenValidatingAudience && AudiencesMatchIgnoringTrailingSlash(tokenAudience, validAudience)) @@ -236,7 +236,7 @@ internal static string ValidateIssuer(string issuer, SecurityToken securityToken if (!validationParameters.ValidateIssuer) { - LogHelper.LogInformation(LogMessages.IDX10235); + LogHelper.LogWarning(LogMessages.IDX10235); return issuer; } @@ -251,7 +251,7 @@ internal static string ValidateIssuer(string issuer, SecurityToken securityToken if (configuration != null) { - if (string.Equals(configuration.Issuer, issuer, StringComparison.Ordinal)) + if (string.Equals(configuration.Issuer, issuer)) { LogHelper.LogInformation(LogMessages.IDX10236, issuer); return issuer; @@ -262,7 +262,7 @@ internal static string ValidateIssuer(string issuer, SecurityToken securityToken { InvalidIssuer = issuer }); } - if (string.Equals(validationParameters.ValidIssuer, issuer, StringComparison.Ordinal)) + if (string.Equals(validationParameters.ValidIssuer, issuer)) { LogHelper.LogInformation(LogMessages.IDX10236, issuer); return issuer; @@ -278,7 +278,7 @@ internal static string ValidateIssuer(string issuer, SecurityToken securityToken continue; } - if (string.Equals(str, issuer, StringComparison.Ordinal)) + if (string.Equals(str, issuer)) { LogHelper.LogInformation(LogMessages.IDX10236, issuer); return issuer; @@ -338,7 +338,7 @@ internal static void ValidateIssuerSecurityKey(SecurityKey securityKey, Security if (!validationParameters.ValidateIssuerSigningKey) { - LogHelper.LogInformation(LogMessages.IDX10237); + LogHelper.LogVerbose(LogMessages.IDX10237); return; } @@ -455,7 +455,7 @@ public static void ValidateTokenReplay(DateTime? expirationTime, string security if (!validationParameters.ValidateTokenReplay) { - LogHelper.LogInformation(LogMessages.IDX10246); + LogHelper.LogVerbose(LogMessages.IDX10246); return; } @@ -514,7 +514,7 @@ public static string ValidateTokenType(string type, SecurityToken securityToken, if (validationParameters.TypeValidator == null && (validationParameters.ValidTypes == null || !validationParameters.ValidTypes.Any())) { - LogHelper.LogInformation(LogMessages.IDX10255); + LogHelper.LogVerbose(LogMessages.IDX10255); return type; } diff --git a/src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs b/src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs index c5eca70c76..5ff26c44d3 100644 --- a/src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs +++ b/src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs @@ -102,7 +102,7 @@ public AsymmetricAlgorithm PrivateKey { if (!_privateKeyAvailabilityDetermined) { -#if NET461 || NET472 || NETSTANDARD2_0 +#if NET461 || NET472 || NETSTANDARD2_0 || NET6_0 _privateKey = RSACertificateExtensions.GetRSAPrivateKey(Certificate); #else _privateKey = Certificate.PrivateKey; @@ -129,7 +129,7 @@ public AsymmetricAlgorithm PublicKey { if (_publicKey == null) { -#if NET461 || NET472 || NETSTANDARD2_0 +#if NET461 || NET472 || NETSTANDARD2_0 || NET6_0 _publicKey = RSACertificateExtensions.GetRSAPublicKey(Certificate); #else _publicKey = Certificate.PublicKey.Key; diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonBinaryType.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonBinaryType.cs index 4d26ac3303..4339a46b40 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonBinaryType.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonBinaryType.cs @@ -25,6 +25,8 @@ using System; +#nullable disable + namespace Microsoft.IdentityModel.Json.Bson { internal enum BsonBinaryType : byte @@ -41,4 +43,4 @@ internal enum BsonBinaryType : byte Md5 = 0x05, UserDefined = 0x80 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonBinaryWriter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonBinaryWriter.cs index 459d43517b..db528596c7 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonBinaryWriter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonBinaryWriter.cs @@ -29,6 +29,8 @@ using System.Text; using Microsoft.IdentityModel.Json.Utilities; +#nullable disable + namespace Microsoft.IdentityModel.Json.Bson { internal class BsonBinaryWriter @@ -325,4 +327,4 @@ private int CalculateSize(BsonToken t) } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonObjectId.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonObjectId.cs index 64f8bb8fcb..6ba12b3bca 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonObjectId.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonObjectId.cs @@ -26,6 +26,8 @@ using System; using Microsoft.IdentityModel.Json.Utilities; +#nullable disable + namespace Microsoft.IdentityModel.Json.Bson { /// @@ -55,4 +57,4 @@ public BsonObjectId(byte[] value) Value = value; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonReader.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonReader.cs index 3c1b2860bf..a69af510ea 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonReader.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonReader.cs @@ -32,6 +32,8 @@ using Microsoft.IdentityModel.Json.Utilities; using Microsoft.IdentityModel.Json.Linq; +#nullable disable + namespace Microsoft.IdentityModel.Json.Bson { /// @@ -831,4 +833,4 @@ private byte[] ReadBytes(int count) return _reader.ReadBytes(count); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonToken.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonToken.cs index a3ea597844..46baeed080 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonToken.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonToken.cs @@ -26,6 +26,8 @@ using System.Collections; using System.Collections.Generic; +#nullable disable + namespace Microsoft.IdentityModel.Json.Bson { internal abstract class BsonToken @@ -163,4 +165,4 @@ internal class BsonProperty public BsonString Name { get; set; } public BsonToken Value { get; set; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonType.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonType.cs index b204f90a11..9861a871cf 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonType.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonType.cs @@ -23,6 +23,8 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion +#nullable disable + namespace Microsoft.IdentityModel.Json.Bson { internal enum BsonType : sbyte @@ -48,4 +50,4 @@ internal enum BsonType : sbyte MinKey = -1, MaxKey = 127 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonWriter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonWriter.cs index 9f72ee7c41..279007125a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonWriter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Bson/BsonWriter.cs @@ -35,6 +35,8 @@ using Microsoft.IdentityModel.Json.Linq; using System.Globalization; +#nullable disable + namespace Microsoft.IdentityModel.Json.Bson { /// @@ -390,9 +392,7 @@ public override void WriteValue(char value) #if HAVE_CHAR_TO_STRING_WITH_CULTURE s = value.ToString(CultureInfo.InvariantCulture); #else -#pragma warning disable CA1305 // Specify IFormatProvider s = value.ToString(); -#pragma warning restore CA1305 // Specify IFormatProvider #endif AddToken(new BsonString(s, true)); } @@ -536,4 +536,4 @@ public void WriteRegex(string pattern, string options) AddToken(new BsonRegex(pattern, options)); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/ConstructorHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/ConstructorHandling.cs index 914691bff6..ab6635a09b 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/ConstructorHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/ConstructorHandling.cs @@ -40,4 +40,4 @@ internal enum ConstructorHandling /// AllowNonPublicDefaultConstructor = 1 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/BinaryConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/BinaryConverter.cs index ec24a6171b..2c4dba4054 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/BinaryConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/BinaryConverter.cs @@ -28,14 +28,14 @@ using System.Globalization; using Microsoft.IdentityModel.Json.Utilities; using System.Collections.Generic; -using System.Reflection; - +using System.Diagnostics; #if HAVE_ADO_NET using System.Data.SqlTypes; #endif namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts a binary value to and from a base 64 string value. /// @@ -44,7 +44,7 @@ internal class BinaryConverter : JsonConverter #if HAVE_LINQ private const string BinaryTypeName = "System.Data.Linq.Binary"; private const string BinaryToArrayName = "ToArray"; - private static ReflectionObject _reflectionObject; + private static ReflectionObject? _reflectionObject; #endif /// @@ -53,7 +53,7 @@ internal class BinaryConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -72,7 +72,9 @@ private byte[] GetByteArray(object value) if (value.GetType().FullName == BinaryTypeName) { EnsureReflectionObject(value.GetType()); - return (byte[])_reflectionObject.GetValue(value, BinaryToArrayName); + MiscellaneousUtils.Assert(_reflectionObject != null); + + return (byte[])_reflectionObject.GetValue(value, BinaryToArrayName)!; } #endif #if HAVE_ADO_NET @@ -103,7 +105,7 @@ private static void EnsureReflectionObject(Type t) /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -125,7 +127,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist { // current token is already at base64 string // unable to call ReadAsBytes so do it the old fashion way - string encodedData = reader.Value.ToString(); + string encodedData = reader.Value!.ToString()!; data = Convert.FromBase64String(encodedData); } else @@ -134,15 +136,16 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } Type t = (ReflectionUtils.IsNullableType(objectType)) - ? Nullable.GetUnderlyingType(objectType) + ? Nullable.GetUnderlyingType(objectType)! : objectType; #if HAVE_LINQ if (t.FullName == BinaryTypeName) { EnsureReflectionObject(t); + MiscellaneousUtils.Assert(_reflectionObject != null); - return _reflectionObject.Creator(data); + return _reflectionObject.Creator!(data); } #endif @@ -205,6 +208,7 @@ public override bool CanConvert(Type objectType) return false; } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/BsonObjectIdConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/BsonObjectIdConverter.cs index 6680627462..304fd28254 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/BsonObjectIdConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/BsonObjectIdConverter.cs @@ -88,4 +88,4 @@ public override bool CanConvert(Type objectType) return (objectType == typeof(BsonObjectId)); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/CustomCreationConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/CustomCreationConverter.cs index 3b40a4f96d..0fadd80d9f 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/CustomCreationConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/CustomCreationConverter.cs @@ -29,6 +29,7 @@ namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Creates a custom object. /// @@ -41,7 +42,7 @@ internal abstract class CustomCreationConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { throw new NotSupportedException("CustomCreationConverter should only be used while deserializing."); } @@ -54,7 +55,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -98,4 +99,5 @@ public override bool CanConvert(Type objectType) /// public override bool CanWrite => false; } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DataSetConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DataSetConverter.cs index a94c4beae4..08c57e8f80 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DataSetConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DataSetConverter.cs @@ -30,6 +30,7 @@ namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts a to and from JSON. /// @@ -41,7 +42,7 @@ internal class DataSetConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -50,7 +51,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s } DataSet dataSet = (DataSet)value; - DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver; + DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver; DataTableConverter converter = new DataTableConverter(); @@ -74,7 +75,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -84,7 +85,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist // handle typed datasets DataSet ds = (objectType == typeof(DataSet)) ? new DataSet() - : (DataSet)Activator.CreateInstance(objectType); + : (DataSet)Activator.CreateInstance(objectType)!; DataTableConverter converter = new DataTableConverter(); @@ -92,10 +93,10 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist while (reader.TokenType == JsonToken.PropertyName) { - DataTable dt = ds.Tables[(string)reader.Value]; + DataTable? dt = ds.Tables[(string)reader.Value!]; bool exists = (dt != null); - dt = (DataTable)converter.ReadJson(reader, typeof(DataTable), dt, serializer); + dt = (DataTable)converter.ReadJson(reader, typeof(DataTable), dt, serializer)!; if (!exists) { @@ -120,6 +121,7 @@ public override bool CanConvert(Type valueType) return typeof(DataSet).IsAssignableFrom(valueType); } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DataTableConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DataTableConverter.cs index 247994e293..47f0eda861 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DataTableConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DataTableConverter.cs @@ -34,6 +34,7 @@ namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts a to and from JSON. /// @@ -45,7 +46,7 @@ internal class DataTableConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -54,7 +55,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s } DataTable table = (DataTable)value; - DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver; + DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver; writer.WriteStartArray(); @@ -87,7 +88,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -99,14 +100,14 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist // handle typed datasets dt = (objectType == typeof(DataTable)) ? new DataTable() - : (DataTable)Activator.CreateInstance(objectType); + : (DataTable)Activator.CreateInstance(objectType)!; } // DataTable is inside a DataSet // populate the name from the property name if (reader.TokenType == JsonToken.PropertyName) { - dt.TableName = (string)reader.Value; + dt.TableName = (string)reader.Value!; reader.ReadAndAssert(); @@ -140,11 +141,11 @@ private static void CreateRow(JsonReader reader, DataTable dt, JsonSerializer se while (reader.TokenType == JsonToken.PropertyName) { - string columnName = (string)reader.Value; + string columnName = (string)reader.Value!; reader.ReadAndAssert(); - DataColumn column = dt.Columns[columnName]; + DataColumn? column = dt.Columns[columnName]; if (column == null) { Type columnType = GetColumnDataType(reader); @@ -177,7 +178,7 @@ private static void CreateRow(JsonReader reader, DataTable dt, JsonSerializer se reader.ReadAndAssert(); } - List o = new List(); + List o = new List(); while (reader.TokenType != JsonToken.EndArray) { @@ -185,7 +186,7 @@ private static void CreateRow(JsonReader reader, DataTable dt, JsonSerializer se reader.ReadAndAssert(); } - Array destinationArray = Array.CreateInstance(column.DataType.GetElementType(), o.Count); + Array destinationArray = Array.CreateInstance(column.DataType.GetElementType()!, o.Count); ((IList)o).CopyTo(destinationArray, 0); dr[columnName] = destinationArray; @@ -218,7 +219,7 @@ private static Type GetColumnDataType(JsonReader reader) case JsonToken.String: case JsonToken.Date: case JsonToken.Bytes: - return reader.ValueType; + return reader.ValueType!; case JsonToken.Null: case JsonToken.Undefined: case JsonToken.EndArray: @@ -249,6 +250,7 @@ public override bool CanConvert(Type valueType) return typeof(DataTable).IsAssignableFrom(valueType); } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DateTimeConverterBase.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DateTimeConverterBase.cs index 89a9137745..c504617f22 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DateTimeConverterBase.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DateTimeConverterBase.cs @@ -55,4 +55,4 @@ public override bool CanConvert(Type objectType) return false; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DiscriminatedUnionConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DiscriminatedUnionConverter.cs index ef0a6bc460..b54006602c 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DiscriminatedUnionConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/DiscriminatedUnionConverter.cs @@ -40,6 +40,7 @@ namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts a F# discriminated union type to and from JSON. /// @@ -48,17 +49,32 @@ internal class DiscriminatedUnionConverter : JsonConverter #region UnionDefinition internal class Union { - public List Cases; - public FSharpFunction TagReader { get; set; } + public readonly FSharpFunction TagReader; + public readonly List Cases; + + public Union(FSharpFunction tagReader, List cases) + { + TagReader = tagReader; + Cases = cases; + } } internal class UnionCase { - public int Tag; - public string Name; - public PropertyInfo[] Fields; - public FSharpFunction FieldReader; - public FSharpFunction Constructor; + public readonly int Tag; + public readonly string Name; + public readonly PropertyInfo[] Fields; + public readonly FSharpFunction FieldReader; + public readonly FSharpFunction Constructor; + + public UnionCase(int tag, string name, PropertyInfo[] fields, FSharpFunction fieldReader, FSharpFunction constructor) + { + Tag = tag; + Name = name; + Fields = fields; + FieldReader = fieldReader; + Constructor = constructor; + } } #endregion @@ -74,31 +90,28 @@ private static Type CreateUnionTypeLookup(Type t) // need to get declaring type to avoid duplicate Unions in cache // hacky but I can't find an API to get the declaring type without GetUnionCases - object[] cases = (object[])FSharpUtils.GetUnionCases(null, t, null); + object[] cases = (object[])FSharpUtils.Instance.GetUnionCases(null, t, null)!; object caseInfo = cases.First(); - Type unionType = (Type)FSharpUtils.GetUnionCaseInfoDeclaringType(caseInfo); + Type unionType = (Type)FSharpUtils.Instance.GetUnionCaseInfoDeclaringType(caseInfo)!; return unionType; } private static Union CreateUnion(Type t) { - Union u = new Union(); + Union u = new Union((FSharpFunction)FSharpUtils.Instance.PreComputeUnionTagReader(null, t, null), new List()); - u.TagReader = (FSharpFunction)FSharpUtils.PreComputeUnionTagReader(null, t, null); - u.Cases = new List(); - - object[] cases = (object[])FSharpUtils.GetUnionCases(null, t, null); + object[] cases = (object[])FSharpUtils.Instance.GetUnionCases(null, t, null)!; foreach (object unionCaseInfo in cases) { - UnionCase unionCase = new UnionCase(); - unionCase.Tag = (int)FSharpUtils.GetUnionCaseInfoTag(unionCaseInfo); - unionCase.Name = (string)FSharpUtils.GetUnionCaseInfoName(unionCaseInfo); - unionCase.Fields = (PropertyInfo[])FSharpUtils.GetUnionCaseInfoFields(unionCaseInfo); - unionCase.FieldReader = (FSharpFunction)FSharpUtils.PreComputeUnionReader(null, unionCaseInfo, null); - unionCase.Constructor = (FSharpFunction)FSharpUtils.PreComputeUnionConstructor(null, unionCaseInfo, null); + UnionCase unionCase = new UnionCase( + (int)FSharpUtils.Instance.GetUnionCaseInfoTag(unionCaseInfo), + (string)FSharpUtils.Instance.GetUnionCaseInfoName(unionCaseInfo), + (PropertyInfo[])FSharpUtils.Instance.GetUnionCaseInfoFields(unionCaseInfo)!, + (FSharpFunction)FSharpUtils.Instance.PreComputeUnionReader(null, unionCaseInfo, null), + (FSharpFunction)FSharpUtils.Instance.PreComputeUnionConstructor(null, unionCaseInfo, null)); u.Cases.Add(unionCase); } @@ -112,9 +125,15 @@ private static Union CreateUnion(Type t) /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { - DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver; + if (value == null) + { + writer.WriteNull(); + return; + } + + DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver; Type unionType = UnionTypeLookupCache.Get(value.GetType()); Union union = UnionCache.Get(unionType); @@ -127,7 +146,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s writer.WriteValue(caseInfo.Name); if (caseInfo.Fields != null && caseInfo.Fields.Length > 0) { - object[] fields = (object[])caseInfo.FieldReader.Invoke(value); + object[] fields = (object[])caseInfo.FieldReader.Invoke(value)!; writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(FieldsPropertyName) : FieldsPropertyName); writer.WriteStartArray(); @@ -148,30 +167,30 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { return null; } - UnionCase caseInfo = null; - string caseName = null; - JArray fields = null; + UnionCase? caseInfo = null; + string? caseName = null; + JArray? fields = null; // start object reader.ReadAndAssert(); while (reader.TokenType == JsonToken.PropertyName) { - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; if (string.Equals(propertyName, CasePropertyName, StringComparison.OrdinalIgnoreCase)) { reader.ReadAndAssert(); Union union = UnionCache.Get(objectType); - caseName = reader.Value.ToString(); + caseName = reader.Value!.ToString(); caseInfo = union.Cases.SingleOrDefault(c => c.Name == caseName); @@ -203,7 +222,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist throw JsonSerializationException.Create(reader, "No '{0}' property with union name found.".FormatWith(CultureInfo.InvariantCulture, CasePropertyName)); } - object[] typedFieldValues = new object[caseInfo.Fields.Length]; + object?[] typedFieldValues = new object?[caseInfo.Fields.Length]; if (caseInfo.Fields.Length > 0 && fields == null) { @@ -272,9 +291,10 @@ public override bool CanConvert(Type objectType) return false; } - return (bool)FSharpUtils.IsUnion(null, objectType, null); + return (bool)FSharpUtils.Instance.IsUnion(null, objectType, null); } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/EntityKeyMemberConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/EntityKeyMemberConverter.cs index 4403c87edb..b3e198323a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/EntityKeyMemberConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/EntityKeyMemberConverter.cs @@ -28,9 +28,11 @@ using Microsoft.IdentityModel.Json.Serialization; using System.Globalization; using Microsoft.IdentityModel.Json.Utilities; +using System.Diagnostics; namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts an Entity Framework to and from JSON. /// @@ -42,7 +44,7 @@ internal class EntityKeyMemberConverter : JsonConverter private const string TypePropertyName = "Type"; private const string ValuePropertyName = "Value"; - private static ReflectionObject _reflectionObject; + private static ReflectionObject? _reflectionObject; /// /// Writes the JSON representation of the object. @@ -50,16 +52,23 @@ internal class EntityKeyMemberConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { + if (value == null) + { + writer.WriteNull(); + return; + } + EnsureReflectionObject(value.GetType()); + MiscellaneousUtils.Assert(_reflectionObject != null); - DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver; + DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver; - string keyName = (string)_reflectionObject.GetValue(value, KeyPropertyName); - object keyValue = _reflectionObject.GetValue(value, ValuePropertyName); + string keyName = (string)_reflectionObject.GetValue(value, KeyPropertyName)!; + object? keyValue = _reflectionObject.GetValue(value, ValuePropertyName); - Type keyValueType = keyValue?.GetType(); + Type? keyValueType = keyValue?.GetType(); writer.WriteStartObject(); writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(KeyPropertyName) : KeyPropertyName); @@ -71,7 +80,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s if (keyValueType != null) { - if (JsonSerializerInternalWriter.TryConvertToString(keyValue, keyValueType, out string valueJson)) + if (JsonSerializerInternalWriter.TryConvertToString(keyValue!, keyValueType, out string? valueJson)) { writer.WriteValue(valueJson); } @@ -92,7 +101,7 @@ private static void ReadAndAssertProperty(JsonReader reader, string propertyName { reader.ReadAndAssert(); - if (reader.TokenType != JsonToken.PropertyName || !string.Equals(reader.Value.ToString(), propertyName, StringComparison.OrdinalIgnoreCase)) + if (reader.TokenType != JsonToken.PropertyName || !string.Equals(reader.Value?.ToString(), propertyName, StringComparison.OrdinalIgnoreCase)) { throw new JsonSerializationException("Expected JSON property '{0}'.".FormatWith(CultureInfo.InvariantCulture, propertyName)); } @@ -106,21 +115,22 @@ private static void ReadAndAssertProperty(JsonReader reader, string propertyName /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { EnsureReflectionObject(objectType); + MiscellaneousUtils.Assert(_reflectionObject != null); - object entityKeyMember = _reflectionObject.Creator(); + object entityKeyMember = _reflectionObject.Creator!(); ReadAndAssertProperty(reader, KeyPropertyName); reader.ReadAndAssert(); - _reflectionObject.SetValue(entityKeyMember, KeyPropertyName, reader.Value.ToString()); + _reflectionObject.SetValue(entityKeyMember, KeyPropertyName, reader.Value?.ToString()); ReadAndAssertProperty(reader, TypePropertyName); reader.ReadAndAssert(); - string type = reader.Value.ToString(); + string? type = reader.Value?.ToString(); - Type t = Type.GetType(type); + Type t = Type.GetType(type!)!; ReadAndAssertProperty(reader, ValuePropertyName); reader.ReadAndAssert(); @@ -151,6 +161,7 @@ public override bool CanConvert(Type objectType) return objectType.AssignableToTypeName(EntityKeyMemberFullTypeName, false); } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/ExpandoObjectConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/ExpandoObjectConverter.cs index b340b66036..aded7d79b1 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/ExpandoObjectConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/ExpandoObjectConverter.cs @@ -35,6 +35,7 @@ namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts an to and from JSON. /// @@ -46,7 +47,7 @@ internal class ExpandoObjectConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { // can write is set to false } @@ -59,12 +60,12 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { return ReadValue(reader); } - private object ReadValue(JsonReader reader) + private object? ReadValue(JsonReader reader) { if (!reader.MoveToContent()) { @@ -89,7 +90,7 @@ private object ReadValue(JsonReader reader) private object ReadList(JsonReader reader) { - IList list = new List(); + IList list = new List(); while (reader.Read()) { @@ -98,7 +99,7 @@ private object ReadList(JsonReader reader) case JsonToken.Comment: break; default: - object v = ReadValue(reader); + object? v = ReadValue(reader); list.Add(v); break; @@ -112,21 +113,21 @@ private object ReadList(JsonReader reader) private object ReadObject(JsonReader reader) { - IDictionary expandoObject = new ExpandoObject(); + IDictionary expandoObject = new ExpandoObject(); while (reader.Read()) { switch (reader.TokenType) { case JsonToken.PropertyName: - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; if (!reader.Read()) { throw JsonSerializationException.Create(reader, "Unexpected end when reading ExpandoObject."); } - object v = ReadValue(reader); + object? v = ReadValue(reader); expandoObject[propertyName] = v; break; @@ -160,6 +161,7 @@ public override bool CanConvert(Type objectType) /// public override bool CanWrite => false; } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/IsoDateTimeConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/IsoDateTimeConverter.cs index 3b69e60636..165d5a335c 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/IsoDateTimeConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/IsoDateTimeConverter.cs @@ -29,6 +29,7 @@ namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts a to and from the ISO 8601 date format (e.g. "2008-04-12T12:53Z"). /// @@ -37,8 +38,8 @@ internal class IsoDateTimeConverter : DateTimeConverterBase private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; private DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind; - private string _dateTimeFormat; - private CultureInfo _culture; + private string? _dateTimeFormat; + private CultureInfo? _culture; /// /// Gets or sets the date time styles used when converting a date to and from JSON. @@ -54,10 +55,10 @@ public DateTimeStyles DateTimeStyles /// Gets or sets the date time format used when converting a date to and from JSON. /// /// The date time format used when converting a date to and from JSON. - public string DateTimeFormat + public string? DateTimeFormat { get => _dateTimeFormat ?? string.Empty; - set => _dateTimeFormat = (string.IsNullOrEmpty(value)) ? null : value; + set => _dateTimeFormat = (StringUtils.IsNullOrEmpty(value)) ? null : value; } /// @@ -76,7 +77,7 @@ public CultureInfo Culture /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { string text; @@ -104,7 +105,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s #endif else { - throw new JsonSerializationException("Unexpected value when converting date. Expected DateTime or DateTimeOffset, got {0}.".FormatWith(CultureInfo.InvariantCulture, ReflectionUtils.GetObjectType(value))); + throw new JsonSerializationException("Unexpected value when converting date. Expected DateTime or DateTimeOffset, got {0}.".FormatWith(CultureInfo.InvariantCulture, ReflectionUtils.GetObjectType(value)!)); } writer.WriteValue(text); @@ -118,7 +119,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { bool nullable = ReflectionUtils.IsNullableType(objectType); if (reader.TokenType == JsonToken.Null) @@ -133,7 +134,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist #if HAVE_DATE_TIME_OFFSET Type t = (nullable) - ? Nullable.GetUnderlyingType(objectType) + ? Nullable.GetUnderlyingType(objectType)! : objectType; #endif @@ -142,7 +143,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist #if HAVE_DATE_TIME_OFFSET if (t == typeof(DateTimeOffset)) { - return (reader.Value is DateTimeOffset) ? reader.Value : new DateTimeOffset((DateTime)reader.Value); + return (reader.Value is DateTimeOffset) ? reader.Value : new DateTimeOffset((DateTime)reader.Value!); } // converter is expected to return a DateTime @@ -160,17 +161,19 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist throw JsonSerializationException.Create(reader, "Unexpected token parsing date. Expected String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - string dateText = reader.Value.ToString(); + string? dateText = reader.Value?.ToString(); - if (string.IsNullOrEmpty(dateText) && nullable) + if (StringUtils.IsNullOrEmpty(dateText) && nullable) { return null; } + MiscellaneousUtils.Assert(dateText != null); + #if HAVE_DATE_TIME_OFFSET if (t == typeof(DateTimeOffset)) { - if (!string.IsNullOrEmpty(_dateTimeFormat)) + if (!StringUtils.IsNullOrEmpty(_dateTimeFormat)) { return DateTimeOffset.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles); } @@ -181,7 +184,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } #endif - if (!string.IsNullOrEmpty(_dateTimeFormat)) + if (!StringUtils.IsNullOrEmpty(_dateTimeFormat)) { return DateTime.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles); } @@ -191,4 +194,5 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } } } +#nullable disable } diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/JavaScriptDateTimeConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/JavaScriptDateTimeConverter.cs index 5d137bc1d6..c2898984ca 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/JavaScriptDateTimeConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/JavaScriptDateTimeConverter.cs @@ -29,6 +29,7 @@ namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts a to and from a JavaScript Date constructor (e.g. new Date(52231943)). /// @@ -40,7 +41,7 @@ internal class JavaScriptDateTimeConverter : DateTimeConverterBase /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { long ticks; @@ -74,7 +75,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing property value of the JSON that is being converted. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -86,19 +87,19 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist return null; } - if (reader.TokenType != JsonToken.StartConstructor || !string.Equals(reader.Value.ToString(), "Date", StringComparison.Ordinal)) + if (reader.TokenType != JsonToken.StartConstructor || !string.Equals(reader.Value?.ToString(), "Date", StringComparison.Ordinal)) { throw JsonSerializationException.Create(reader, "Unexpected token or value when parsing date. Token: {0}, Value: {1}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType, reader.Value)); } - if (!JavaScriptUtils.TryGetDateFromConstructorJson(reader, out DateTime d, out string errorMessage)) + if (!JavaScriptUtils.TryGetDateFromConstructorJson(reader, out DateTime d, out string? errorMessage)) { throw JsonSerializationException.Create(reader, errorMessage); } #if HAVE_DATE_TIME_OFFSET Type t = (ReflectionUtils.IsNullableType(objectType)) - ? Nullable.GetUnderlyingType(objectType) + ? Nullable.GetUnderlyingType(objectType)! : objectType; if (t == typeof(DateTimeOffset)) { @@ -108,4 +109,5 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist return d; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/KeyValuePairConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/KeyValuePairConverter.cs index ec0ed20c9e..c182a14dd3 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/KeyValuePairConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/KeyValuePairConverter.cs @@ -31,6 +31,7 @@ namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts a to and from JSON. /// @@ -56,11 +57,17 @@ private static ReflectionObject InitializeReflectionObject(Type t) /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { + if (value == null) + { + writer.WriteNull(); + return; + } + ReflectionObject reflectionObject = ReflectionObjectPerType.Get(value.GetType()); - DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver; + DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver; writer.WriteStartObject(); writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(KeyName) : KeyName); @@ -78,7 +85,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -90,13 +97,13 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist return null; } - object key = null; - object value = null; + object? key = null; + object? value = null; reader.ReadAndAssert(); Type t = ReflectionUtils.IsNullableType(objectType) - ? Nullable.GetUnderlyingType(objectType) + ? Nullable.GetUnderlyingType(objectType)! : objectType; ReflectionObject reflectionObject = ReflectionObjectPerType.Get(t); @@ -105,7 +112,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist while (reader.TokenType == JsonToken.PropertyName) { - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; if (string.Equals(propertyName, KeyName, StringComparison.OrdinalIgnoreCase)) { reader.ReadForTypeAndAssert(keyContract, false); @@ -126,7 +133,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist reader.ReadAndAssert(); } - return reflectionObject.Creator(key, value); + return reflectionObject.Creator!(key, value); } /// @@ -139,7 +146,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist public override bool CanConvert(Type objectType) { Type t = (ReflectionUtils.IsNullableType(objectType)) - ? Nullable.GetUnderlyingType(objectType) + ? Nullable.GetUnderlyingType(objectType)! : objectType; if (t.IsValueType() && t.IsGenericType()) @@ -150,4 +157,5 @@ public override bool CanConvert(Type objectType) return false; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/RegexConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/RegexConverter.cs index 46f8d9dde1..75d5a5dfe2 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/RegexConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/RegexConverter.cs @@ -33,6 +33,7 @@ namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts a to and from JSON and BSON. /// @@ -47,7 +48,7 @@ internal class RegexConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -78,13 +79,13 @@ private bool HasFlag(RegexOptions options, RegexOptions flag) private void WriteBson(BsonWriter writer, Regex regex) { // Regular expression - The first cstring is the regex pattern, the second - // is the regex options string. Options are identified by characters, which - // must be stored in alphabetical order. Valid options are 'i' for case - // insensitive matching, 'm' for multiline matching, 'x' for verbose mode, - // 'l' to make \w, \W, etc. locale dependent, 's' for dotall mode + // is the regex options string. Options are identified by characters, which + // must be stored in alphabetical order. Valid options are 'i' for case + // insensitive matching, 'm' for multiline matching, 'x' for verbose mode, + // 'l' to make \w, \W, etc. locale dependent, 's' for dotall mode // ('.' matches everything), and 'u' to make \w, \W, etc. match unicode. - string options = null; + string? options = null; if (HasFlag(regex.Options, RegexOptions.IgnoreCase)) { @@ -114,7 +115,7 @@ private void WriteBson(BsonWriter writer, Regex regex) private void WriteJson(JsonWriter writer, Regex regex, JsonSerializer serializer) { - DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver; + DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver; writer.WriteStartObject(); writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(PatternName) : PatternName); @@ -132,7 +133,7 @@ private void WriteJson(JsonWriter writer, Regex regex, JsonSerializer serializer /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { switch (reader.TokenType) { @@ -149,7 +150,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist private object ReadRegexString(JsonReader reader) { - string regexText = (string)reader.Value; + string regexText = (string)reader.Value!; if (regexText.Length > 0 && regexText[0] == '/') { @@ -171,7 +172,7 @@ private object ReadRegexString(JsonReader reader) private Regex ReadRegexObject(JsonReader reader, JsonSerializer serializer) { - string pattern = null; + string? pattern = null; RegexOptions? options = null; while (reader.Read()) @@ -179,7 +180,7 @@ private Regex ReadRegexObject(JsonReader reader, JsonSerializer serializer) switch (reader.TokenType) { case JsonToken.PropertyName: - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; if (!reader.Read()) { @@ -188,7 +189,7 @@ private Regex ReadRegexObject(JsonReader reader, JsonSerializer serializer) if (string.Equals(propertyName, PatternName, StringComparison.OrdinalIgnoreCase)) { - pattern = (string)reader.Value; + pattern = (string?)reader.Value; } else if (string.Equals(propertyName, OptionsName, StringComparison.OrdinalIgnoreCase)) { @@ -232,4 +233,5 @@ private bool IsRegex(Type objectType) return (objectType == typeof(Regex)); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/StringEnumConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/StringEnumConverter.cs index fad2a7b9e5..2683ff0db8 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/StringEnumConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/StringEnumConverter.cs @@ -41,6 +41,7 @@ namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts an to and from its name string value. /// @@ -82,7 +83,7 @@ public bool CamelCaseText /// Gets or sets the naming strategy used to resolve how enum text is written. /// /// The naming strategy used to resolve how enum text is written. - public NamingStrategy NamingStrategy { get; set; } + public NamingStrategy? NamingStrategy { get; set; } /// /// Gets or sets a value indicating whether integer values are allowed when serializing and deserializing. @@ -175,7 +176,7 @@ public StringEnumConverter(Type namingStrategyType, object[] namingStrategyParam /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -185,7 +186,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s Enum e = (Enum)value; - if (!EnumUtils.TryToString(e.GetType(), value, NamingStrategy, out string enumName)) + if (!EnumUtils.TryToString(e.GetType(), value, NamingStrategy, out string? enumName)) { if (!AllowIntegerValues) { @@ -209,7 +210,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -222,20 +223,20 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } bool isNullable = ReflectionUtils.IsNullableType(objectType); - Type t = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType; + Type t = isNullable ? Nullable.GetUnderlyingType(objectType)! : objectType; try { if (reader.TokenType == JsonToken.String) { - string enumText = reader.Value.ToString(); + string? enumText = reader.Value?.ToString(); - if (enumText == string.Empty && isNullable) + if (StringUtils.IsNullOrEmpty(enumText) && isNullable) { return null; } - return EnumUtils.ParseEnum(t, NamingStrategy, enumText, !AllowIntegerValues); + return EnumUtils.ParseEnum(t, NamingStrategy, enumText!, !AllowIntegerValues); } if (reader.TokenType == JsonToken.Integer) @@ -267,10 +268,11 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist public override bool CanConvert(Type objectType) { Type t = (ReflectionUtils.IsNullableType(objectType)) - ? Nullable.GetUnderlyingType(objectType) + ? Nullable.GetUnderlyingType(objectType)! : objectType; return t.IsEnum(); } } +#nullable disable } diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/UnixDateTimeConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/UnixDateTimeConverter.cs index 07dc8cba6d..b7057e2327 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/UnixDateTimeConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/UnixDateTimeConverter.cs @@ -29,6 +29,7 @@ namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts a to and from Unix epoch time /// @@ -36,13 +37,44 @@ internal class UnixDateTimeConverter : DateTimeConverterBase { internal static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + /// + /// Gets or sets a value indicating whether the dates before Unix epoch + /// should converted to and from JSON. + /// + /// + /// true to allow converting dates before Unix epoch to and from JSON; + /// false to throw an exception when a date being converted to or from JSON + /// occurred before Unix epoch. The default value is false. + /// + public bool AllowPreEpoch { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public UnixDateTimeConverter() : this(false) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// true to allow converting dates before Unix epoch to and from JSON; + /// false to throw an exception when a date being converted to or from JSON + /// occurred before Unix epoch. The default value is false. + /// + public UnixDateTimeConverter(bool allowPreEpoch) + { + AllowPreEpoch = allowPreEpoch; + } + /// /// Writes the JSON representation of the object. /// /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { long seconds; @@ -61,7 +93,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s throw new JsonSerializationException("Expected date object value."); } - if (seconds < 0) + if (!AllowPreEpoch && seconds < 0) { throw new JsonSerializationException("Cannot convert date value that is before Unix epoch of 00:00:00 UTC on 1 January 1970."); } @@ -77,7 +109,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing property value of the JSON that is being converted. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { bool nullable = ReflectionUtils.IsNullable(objectType); if (reader.TokenType == JsonToken.Null) @@ -94,11 +126,11 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist if (reader.TokenType == JsonToken.Integer) { - seconds = (long)reader.Value; + seconds = (long)reader.Value!; } else if (reader.TokenType == JsonToken.String) { - if (!long.TryParse((string)reader.Value, out seconds)) + if (!long.TryParse((string)reader.Value!, out seconds)) { throw JsonSerializationException.Create(reader, "Cannot convert invalid value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType)); } @@ -108,12 +140,12 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist throw JsonSerializationException.Create(reader, "Unexpected token parsing date. Expected Integer or String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - if (seconds >= 0) + if (AllowPreEpoch || seconds >= 0) { DateTime d = UnixEpoch.AddSeconds(seconds); #if HAVE_DATE_TIME_OFFSET - Type t = (nullable) + Type? t = (nullable) ? Nullable.GetUnderlyingType(objectType) : objectType; if (t == typeof(DateTimeOffset)) @@ -129,4 +161,5 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/VersionConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/VersionConverter.cs index 2d94ad396a..8d8eb7a498 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/VersionConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/VersionConverter.cs @@ -29,6 +29,7 @@ namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable /// /// Converts a to and from a string (e.g. "1.2.3.4"). /// @@ -40,7 +41,7 @@ internal class VersionConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -64,7 +65,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing property value of the JSON that is being converted. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -76,7 +77,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist { try { - Version v = new Version((string)reader.Value); + Version v = new Version((string)reader.Value!); return v; } catch (Exception ex) @@ -103,4 +104,5 @@ public override bool CanConvert(Type objectType) return objectType == typeof(Version); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/XmlNodeConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/XmlNodeConverter.cs index b2bc66de14..2dfc79bd6c 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/XmlNodeConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Converters/XmlNodeConverter.cs @@ -38,9 +38,11 @@ #endif using Microsoft.IdentityModel.Json.Utilities; using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.IdentityModel.Json.Converters { +#nullable enable #region XmlNodeWrappers #if HAVE_XML_DOCUMENT internal class XmlDocumentWrapper : XmlNodeWrapper, IXmlDocument @@ -53,38 +55,38 @@ public XmlDocumentWrapper(XmlDocument document) _document = document; } - public IXmlNode CreateComment(string data) + public IXmlNode CreateComment(string? data) { return new XmlNodeWrapper(_document.CreateComment(data)); } - public IXmlNode CreateTextNode(string text) + public IXmlNode CreateTextNode(string? text) { return new XmlNodeWrapper(_document.CreateTextNode(text)); } - public IXmlNode CreateCDataSection(string data) + public IXmlNode CreateCDataSection(string? data) { return new XmlNodeWrapper(_document.CreateCDataSection(data)); } - public IXmlNode CreateWhitespace(string text) + public IXmlNode CreateWhitespace(string? text) { return new XmlNodeWrapper(_document.CreateWhitespace(text)); } - public IXmlNode CreateSignificantWhitespace(string text) + public IXmlNode CreateSignificantWhitespace(string? text) { return new XmlNodeWrapper(_document.CreateSignificantWhitespace(text)); } - public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone) + public IXmlNode CreateXmlDeclaration(string version, string? encoding, string? standalone) { return new XmlDeclarationWrapper(_document.CreateXmlDeclaration(version, encoding, standalone)); } #if HAVE_XML_DOCUMENT_TYPE - public IXmlNode CreateXmlDocumentType(string name, string publicId, string systemId, string internalSubset) + public IXmlNode CreateXmlDocumentType(string name, string? publicId, string? systemId, string? internalSubset) { return new XmlDocumentTypeWrapper(_document.CreateDocumentType(name, publicId, systemId, null)); } @@ -105,7 +107,7 @@ public IXmlElement CreateElement(string qualifiedName, string namespaceUri) return new XmlElementWrapper(_document.CreateElement(qualifiedName, namespaceUri)); } - public IXmlNode CreateAttribute(string name, string value) + public IXmlNode CreateAttribute(string name, string? value) { XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(name)); attribute.Value = value; @@ -113,7 +115,7 @@ public IXmlNode CreateAttribute(string name, string value) return attribute; } - public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value) + public IXmlNode CreateAttribute(string qualifiedName, string? namespaceUri, string? value) { XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(qualifiedName, namespaceUri)); attribute.Value = value; @@ -121,7 +123,7 @@ public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, strin return attribute; } - public IXmlElement DocumentElement + public IXmlElement? DocumentElement { get { @@ -149,10 +151,10 @@ public void SetAttributeNode(IXmlNode attribute) { XmlNodeWrapper xmlAttributeWrapper = (XmlNodeWrapper)attribute; - _element.SetAttributeNode((XmlAttribute)xmlAttributeWrapper.WrappedNode); + _element.SetAttributeNode((XmlAttribute)xmlAttributeWrapper.WrappedNode!); } - public string GetPrefixOfNamespace(string namespaceUri) + public string? GetPrefixOfNamespace(string namespaceUri) { return _element.GetPrefixOfNamespace(namespaceUri); } @@ -170,15 +172,15 @@ public XmlDeclarationWrapper(XmlDeclaration declaration) _declaration = declaration; } - public string Version => _declaration.Version; + public string? Version => _declaration.Version; - public string Encoding + public string? Encoding { get => _declaration.Encoding; set => _declaration.Encoding = value; } - public string Standalone + public string? Standalone { get => _declaration.Standalone; set => _declaration.Standalone = value; @@ -198,32 +200,32 @@ public XmlDocumentTypeWrapper(XmlDocumentType documentType) public string Name => _documentType.Name; - public string System => _documentType.SystemId; + public string? System => _documentType.SystemId; - public string Public => _documentType.PublicId; + public string? Public => _documentType.PublicId; - public string InternalSubset => _documentType.InternalSubset; + public string? InternalSubset => _documentType.InternalSubset; - public override string LocalName => "DOCTYPE"; + public override string? LocalName => "DOCTYPE"; } #endif internal class XmlNodeWrapper : IXmlNode { private readonly XmlNode _node; - private List _childNodes; - private List _attributes; + private List? _childNodes; + private List? _attributes; public XmlNodeWrapper(XmlNode node) { _node = node; } - public object WrappedNode => _node; + public object? WrappedNode => _node; public XmlNodeType NodeType => _node.NodeType; - public virtual string LocalName => _node.LocalName; + public virtual string? LocalName => _node.LocalName; public List ChildNodes { @@ -284,7 +286,7 @@ public List Attributes } else { - _attributes = new List(_node.Attributes.Count); + _attributes = new List(_node.Attributes!.Count); foreach (XmlAttribute attribute in _node.Attributes) { _attributes.Add(WrapNode(attribute)); @@ -309,11 +311,11 @@ private bool HasAttributes } } - public IXmlNode ParentNode + public IXmlNode? ParentNode { get { - XmlNode node = _node is XmlAttribute attribute ? attribute.OwnerElement : _node.ParentNode; + XmlNode? node = _node is XmlAttribute attribute ? attribute.OwnerElement : _node.ParentNode; if (node == null) { @@ -324,7 +326,7 @@ public IXmlNode ParentNode } } - public string Value + public string? Value { get => _node.Value; set => _node.Value = value; @@ -340,7 +342,7 @@ public IXmlNode AppendChild(IXmlNode newChild) return newChild; } - public string NamespaceUri => _node.NamespaceURI; + public string? NamespaceUri => _node.NamespaceURI; } #endif #endregion @@ -348,14 +350,14 @@ public IXmlNode AppendChild(IXmlNode newChild) #region Interfaces internal interface IXmlDocument : IXmlNode { - IXmlNode CreateComment(string text); - IXmlNode CreateTextNode(string text); - IXmlNode CreateCDataSection(string data); - IXmlNode CreateWhitespace(string text); - IXmlNode CreateSignificantWhitespace(string text); - IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone); + IXmlNode CreateComment(string? text); + IXmlNode CreateTextNode(string? text); + IXmlNode CreateCDataSection(string? data); + IXmlNode CreateWhitespace(string? text); + IXmlNode CreateSignificantWhitespace(string? text); + IXmlNode CreateXmlDeclaration(string version, string? encoding, string? standalone); #if HAVE_XML_DOCUMENT_TYPE - IXmlNode CreateXmlDocumentType(string name, string publicId, string systemId, string internalSubset); + IXmlNode CreateXmlDocumentType(string name, string? publicId, string? systemId, string? internalSubset); #endif IXmlNode CreateProcessingInstruction(string target, string data); IXmlElement CreateElement(string elementName); @@ -363,42 +365,42 @@ internal interface IXmlDocument : IXmlNode IXmlNode CreateAttribute(string name, string value); IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value); - IXmlElement DocumentElement { get; } + IXmlElement? DocumentElement { get; } } internal interface IXmlDeclaration : IXmlNode { - string Version { get; } - string Encoding { get; set; } - string Standalone { get; set; } + string? Version { get; } + string? Encoding { get; set; } + string? Standalone { get; set; } } internal interface IXmlDocumentType : IXmlNode { string Name { get; } - string System { get; } - string Public { get; } - string InternalSubset { get; } + string? System { get; } + string? Public { get; } + string? InternalSubset { get; } } internal interface IXmlElement : IXmlNode { void SetAttributeNode(IXmlNode attribute); - string GetPrefixOfNamespace(string namespaceUri); + string? GetPrefixOfNamespace(string namespaceUri); bool IsEmpty { get; } } internal interface IXmlNode { XmlNodeType NodeType { get; } - string LocalName { get; } + string? LocalName { get; } List ChildNodes { get; } List Attributes { get; } - IXmlNode ParentNode { get; } - string Value { get; set; } + IXmlNode? ParentNode { get; } + string? Value { get; set; } IXmlNode AppendChild(IXmlNode newChild); - string NamespaceUri { get; } - object WrappedNode { get; } + string? NamespaceUri { get; } + object? WrappedNode { get; } } #endregion @@ -416,15 +418,15 @@ public XDeclarationWrapper(XDeclaration declaration) public override XmlNodeType NodeType => XmlNodeType.XmlDeclaration; - public string Version => Declaration.Version; + public string? Version => Declaration.Version; - public string Encoding + public string? Encoding { get => Declaration.Encoding; set => Declaration.Encoding = value; } - public string Standalone + public string? Standalone { get => Declaration.Standalone; set => Declaration.Standalone = value; @@ -443,18 +445,18 @@ public XDocumentTypeWrapper(XDocumentType documentType) public string Name => _documentType.Name; - public string System => _documentType.SystemId; + public string? System => _documentType.SystemId; - public string Public => _documentType.PublicId; + public string? Public => _documentType.PublicId; - public string InternalSubset => _documentType.InternalSubset; + public string? InternalSubset => _documentType.InternalSubset; - public override string LocalName => "DOCTYPE"; + public override string? LocalName => "DOCTYPE"; } internal class XDocumentWrapper : XContainerWrapper, IXmlDocument { - private XDocument Document => (XDocument)WrappedNode; + private XDocument Document => (XDocument)WrappedNode!; public XDocumentWrapper(XDocument document) : base(document) @@ -488,37 +490,37 @@ protected override bool HasChildNodes } } - public IXmlNode CreateComment(string text) + public IXmlNode CreateComment(string? text) { - return new XObjectWrapper(new XComment(text)); + return new XObjectWrapper(new XComment(text!)); } - public IXmlNode CreateTextNode(string text) + public IXmlNode CreateTextNode(string? text) { - return new XObjectWrapper(new XText(text)); + return new XObjectWrapper(new XText(text!)); } - public IXmlNode CreateCDataSection(string data) + public IXmlNode CreateCDataSection(string? data) { - return new XObjectWrapper(new XCData(data)); + return new XObjectWrapper(new XCData(data!)); } - public IXmlNode CreateWhitespace(string text) + public IXmlNode CreateWhitespace(string? text) { - return new XObjectWrapper(new XText(text)); + return new XObjectWrapper(new XText(text!)); } - public IXmlNode CreateSignificantWhitespace(string text) + public IXmlNode CreateSignificantWhitespace(string? text) { - return new XObjectWrapper(new XText(text)); + return new XObjectWrapper(new XText(text!)); } - public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone) + public IXmlNode CreateXmlDeclaration(string version, string? encoding, string? standalone) { return new XDeclarationWrapper(new XDeclaration(version, encoding, standalone)); } - public IXmlNode CreateXmlDocumentType(string name, string publicId, string systemId, string internalSubset) + public IXmlNode CreateXmlDocumentType(string name, string? publicId, string? systemId, string? internalSubset) { return new XDocumentTypeWrapper(new XDocumentType(name, publicId, systemId, internalSubset)); } @@ -550,7 +552,7 @@ public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, strin return new XAttributeWrapper(new XAttribute(XName.Get(localName, namespaceUri), value)); } - public IXmlElement DocumentElement + public IXmlElement? DocumentElement { get { @@ -579,20 +581,20 @@ public override IXmlNode AppendChild(IXmlNode newChild) internal class XTextWrapper : XObjectWrapper { - private XText Text => (XText)WrappedNode; + private XText Text => (XText)WrappedNode!; public XTextWrapper(XText text) : base(text) { } - public override string Value + public override string? Value { get => Text.Value; - set => Text.Value = value; + set => Text.Value = value ?? string.Empty; } - public override IXmlNode ParentNode + public override IXmlNode? ParentNode { get { @@ -608,20 +610,20 @@ public override IXmlNode ParentNode internal class XCommentWrapper : XObjectWrapper { - private XComment Text => (XComment)WrappedNode; + private XComment Text => (XComment)WrappedNode!; public XCommentWrapper(XComment text) : base(text) { } - public override string Value + public override string? Value { get => Text.Value; - set => Text.Value = value; + set => Text.Value = value ?? string.Empty; } - public override IXmlNode ParentNode + public override IXmlNode? ParentNode { get { @@ -637,27 +639,27 @@ public override IXmlNode ParentNode internal class XProcessingInstructionWrapper : XObjectWrapper { - private XProcessingInstruction ProcessingInstruction => (XProcessingInstruction)WrappedNode; + private XProcessingInstruction ProcessingInstruction => (XProcessingInstruction)WrappedNode!; public XProcessingInstructionWrapper(XProcessingInstruction processingInstruction) : base(processingInstruction) { } - public override string LocalName => ProcessingInstruction.Target; + public override string? LocalName => ProcessingInstruction.Target; - public override string Value + public override string? Value { get => ProcessingInstruction.Data; - set => ProcessingInstruction.Data = value; + set => ProcessingInstruction.Data = value ?? string.Empty; } } internal class XContainerWrapper : XObjectWrapper { - private List _childNodes; + private List? _childNodes; - private XContainer Container => (XContainer)WrappedNode; + private XContainer Container => (XContainer)WrappedNode!; public XContainerWrapper(XContainer container) : base(container) @@ -692,7 +694,7 @@ public override List ChildNodes protected virtual bool HasChildNodes => Container.LastNode != null; - public override IXmlNode ParentNode + public override IXmlNode? ParentNode { get { @@ -761,26 +763,26 @@ public override IXmlNode AppendChild(IXmlNode newChild) internal class XObjectWrapper : IXmlNode { - private readonly XObject _xmlObject; + private readonly XObject? _xmlObject; - public XObjectWrapper(XObject xmlObject) + public XObjectWrapper(XObject? xmlObject) { _xmlObject = xmlObject; } - public object WrappedNode => _xmlObject; + public object? WrappedNode => _xmlObject; - public virtual XmlNodeType NodeType => _xmlObject.NodeType; + public virtual XmlNodeType NodeType => _xmlObject?.NodeType ?? XmlNodeType.None; - public virtual string LocalName => null; + public virtual string? LocalName => null; public virtual List ChildNodes => XmlNodeConverter.EmptyChildNodes; public virtual List Attributes => XmlNodeConverter.EmptyChildNodes; - public virtual IXmlNode ParentNode => null; + public virtual IXmlNode? ParentNode => null; - public virtual string Value + public virtual string? Value { get => null; set => throw new InvalidOperationException(); @@ -791,29 +793,29 @@ public virtual IXmlNode AppendChild(IXmlNode newChild) throw new InvalidOperationException(); } - public virtual string NamespaceUri => null; + public virtual string? NamespaceUri => null; } internal class XAttributeWrapper : XObjectWrapper { - private XAttribute Attribute => (XAttribute)WrappedNode; + private XAttribute Attribute => (XAttribute)WrappedNode!; public XAttributeWrapper(XAttribute attribute) : base(attribute) { } - public override string Value + public override string? Value { get => Attribute.Value; - set => Attribute.Value = value; + set => Attribute.Value = value ?? string.Empty; } - public override string LocalName => Attribute.Name.LocalName; + public override string? LocalName => Attribute.Name.LocalName; - public override string NamespaceUri => Attribute.Name.NamespaceName; + public override string? NamespaceUri => Attribute.Name.NamespaceName; - public override IXmlNode ParentNode + public override IXmlNode? ParentNode { get { @@ -829,9 +831,9 @@ public override IXmlNode ParentNode internal class XElementWrapper : XContainerWrapper, IXmlElement { - private List _attributes; + private List? _attributes; - private XElement Element => (XElement)WrappedNode; + private XElement Element => (XElement)WrappedNode!; public XElementWrapper(XElement element) : base(element) @@ -853,7 +855,7 @@ public override List Attributes // cache results to prevent multiple reads which kills perf in large documents if (_attributes == null) { - if (!Element.HasAttributes && !HasImplicitNamespaceAttribute(NamespaceUri)) + if (!Element.HasAttributes && !HasImplicitNamespaceAttribute(NamespaceUri!)) { _attributes = XmlNodeConverter.EmptyChildNodes; } @@ -867,7 +869,7 @@ public override List Attributes // ensure elements created with a namespace but no namespace attribute are converted correctly // e.g. new XElement("{http://example.com}MyElement"); - string namespaceUri = NamespaceUri; + string namespaceUri = NamespaceUri!; if (HasImplicitNamespaceAttribute(namespaceUri)) { _attributes.Insert(0, new XAttributeWrapper(new XAttribute("xmlns", namespaceUri))); @@ -881,9 +883,9 @@ public override List Attributes private bool HasImplicitNamespaceAttribute(string namespaceUri) { - if (!string.IsNullOrEmpty(namespaceUri) && namespaceUri != ParentNode?.NamespaceUri) + if (!StringUtils.IsNullOrEmpty(namespaceUri) && namespaceUri != ParentNode?.NamespaceUri) { - if (string.IsNullOrEmpty(GetPrefixOfNamespace(namespaceUri))) + if (StringUtils.IsNullOrEmpty(GetPrefixOfNamespace(namespaceUri))) { bool namespaceDeclared = false; @@ -891,7 +893,7 @@ private bool HasImplicitNamespaceAttribute(string namespaceUri) { foreach (XAttribute attribute in Element.Attributes()) { - if (attribute.Name.LocalName == "xmlns" && string.IsNullOrEmpty(attribute.Name.NamespaceName) && attribute.Value == namespaceUri) + if (attribute.Name.LocalName == "xmlns" && StringUtils.IsNullOrEmpty(attribute.Name.NamespaceName) && attribute.Value == namespaceUri) { namespaceDeclared = true; } @@ -915,17 +917,17 @@ public override IXmlNode AppendChild(IXmlNode newChild) return result; } - public override string Value + public override string? Value { get => Element.Value; - set => Element.Value = value; + set => Element.Value = value ?? string.Empty; } - public override string LocalName => Element.Name.LocalName; + public override string? LocalName => Element.Name.LocalName; - public override string NamespaceUri => Element.Name.NamespaceName; + public override string? NamespaceUri => Element.Name.NamespaceName; - public string GetPrefixOfNamespace(string namespaceUri) + public string? GetPrefixOfNamespace(string namespaceUri) { return Element.GetPrefixOfNamespace(namespaceUri); } @@ -954,7 +956,7 @@ internal class XmlNodeConverter : JsonConverter /// Gets or sets the name of the root element to insert when deserializing to XML if the JSON structure has produced multiple root elements. /// /// The name of the deserialized root element. - public string DeserializeRootElementName { get; set; } + public string? DeserializeRootElementName { get; set; } /// /// Gets or sets a value to indicate whether to write the Json.NET array attribute. @@ -985,7 +987,7 @@ internal class XmlNodeConverter : JsonConverter /// The to write to. /// The calling serializer. /// The value. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -1031,9 +1033,9 @@ private IXmlNode WrapXml(object value) private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager) { - List parentElements = null; + List? parentElements = null; - IXmlNode parent = node; + IXmlNode? parent = node; while ((parent = parent.ParentNode) != null) { if (parent.NodeType == XmlNodeType.Element) @@ -1058,7 +1060,7 @@ private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager) { if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/" && attribute.LocalName != "xmlns") { - manager.AddNamespace(attribute.LocalName, attribute.Value); + manager.AddNamespace(attribute.LocalName!, attribute.Value!); } } } @@ -1067,17 +1069,17 @@ private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager) private string ResolveFullName(IXmlNode node, XmlNamespaceManager manager) { - string prefix = (node.NamespaceUri == null || (node.LocalName == "xmlns" && node.NamespaceUri == "http://www.w3.org/2000/xmlns/")) + string? prefix = (node.NamespaceUri == null || (node.LocalName == "xmlns" && node.NamespaceUri == "http://www.w3.org/2000/xmlns/")) ? null : manager.LookupPrefix(node.NamespaceUri); - if (!string.IsNullOrEmpty(prefix)) + if (!StringUtils.IsNullOrEmpty(prefix)) { return prefix + ":" + XmlConvert.DecodeName(node.LocalName); } else { - return XmlConvert.DecodeName(node.LocalName); + return XmlConvert.DecodeName(node.LocalName)!; } } @@ -1130,7 +1132,7 @@ private bool IsArray(IXmlNode node) { if (attribute.LocalName == "Array" && attribute.NamespaceUri == JsonNamespaceUri) { - return XmlConvert.ToBoolean(attribute.Value); + return XmlConvert.ToBoolean(attribute.Value!); } } @@ -1160,9 +1162,9 @@ private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespac // value of dictionary will be a single IXmlNode when there is one for a name, // or a List when there are multiple - Dictionary nodesGroupedByName = null; + Dictionary? nodesGroupedByName = null; - string nodeName = null; + string? nodeName = null; for (int i = 0; i < node.ChildNodes.Count; i++) { @@ -1200,7 +1202,7 @@ private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespac } else { - if (!nodesGroupedByName.TryGetValue(currentNodeName, out object value)) + if (!nodesGroupedByName.TryGetValue(currentNodeName, out object? value)) { nodesGroupedByName.Add(currentNodeName, childNode); } @@ -1208,7 +1210,7 @@ private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespac { if (!(value is List nodes)) { - nodes = new List {(IXmlNode)value}; + nodes = new List {(IXmlNode)value!}; nodesGroupedByName[currentNodeName] = nodes; } @@ -1219,7 +1221,7 @@ private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespac if (nodesGroupedByName == null) { - WriteGroupedNodes(writer, manager, writePropertyName, node.ChildNodes, nodeName); + WriteGroupedNodes(writer, manager, writePropertyName, node.ChildNodes, nodeName!); } else { @@ -1313,9 +1315,13 @@ private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/") { string namespacePrefix = (attribute.LocalName != "xmlns") - ? XmlConvert.DecodeName(attribute.LocalName) + ? XmlConvert.DecodeName(attribute.LocalName)! : string.Empty; - string namespaceUri = attribute.Value; + string? namespaceUri = attribute.Value; + if (namespaceUri == null) + { + throw new JsonSerializationException("Namespace attribute must have a value."); + } manager.AddNamespace(namespacePrefix, namespaceUri); } @@ -1400,17 +1406,17 @@ private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager writer.WritePropertyName(GetPropertyName(node, manager)); writer.WriteStartObject(); - if (!string.IsNullOrEmpty(declaration.Version)) + if (!StringUtils.IsNullOrEmpty(declaration.Version)) { writer.WritePropertyName("@version"); writer.WriteValue(declaration.Version); } - if (!string.IsNullOrEmpty(declaration.Encoding)) + if (!StringUtils.IsNullOrEmpty(declaration.Encoding)) { writer.WritePropertyName("@encoding"); writer.WriteValue(declaration.Encoding); } - if (!string.IsNullOrEmpty(declaration.Standalone)) + if (!StringUtils.IsNullOrEmpty(declaration.Standalone)) { writer.WritePropertyName("@standalone"); writer.WriteValue(declaration.Standalone); @@ -1423,22 +1429,22 @@ private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager writer.WritePropertyName(GetPropertyName(node, manager)); writer.WriteStartObject(); - if (!string.IsNullOrEmpty(documentType.Name)) + if (!StringUtils.IsNullOrEmpty(documentType.Name)) { writer.WritePropertyName("@name"); writer.WriteValue(documentType.Name); } - if (!string.IsNullOrEmpty(documentType.Public)) + if (!StringUtils.IsNullOrEmpty(documentType.Public)) { writer.WritePropertyName("@public"); writer.WriteValue(documentType.Public); } - if (!string.IsNullOrEmpty(documentType.System)) + if (!StringUtils.IsNullOrEmpty(documentType.System)) { writer.WritePropertyName("@system"); writer.WriteValue(documentType.System); } - if (!string.IsNullOrEmpty(documentType.InternalSubset)) + if (!StringUtils.IsNullOrEmpty(documentType.InternalSubset)) { writer.WritePropertyName("@internalSubset"); writer.WriteValue(documentType.InternalSubset); @@ -1473,7 +1479,7 @@ private static bool AllSameName(IXmlNode node) /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { switch (reader.TokenType) { @@ -1486,8 +1492,8 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable()); - IXmlDocument document = null; - IXmlNode rootNode = null; + IXmlDocument? document = null; + IXmlNode? rootNode = null; #if HAVE_XLINQ if (typeof(XObject).IsAssignableFrom(objectType)) @@ -1532,7 +1538,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist throw JsonSerializationException.Create(reader, "Unexpected type when converting XML: " + objectType); } - if (!string.IsNullOrEmpty(DeserializeRootElementName)) + if (!StringUtils.IsNullOrEmpty(DeserializeRootElementName)) { ReadElement(reader, document, rootNode, DeserializeRootElementName, manager); } @@ -1545,7 +1551,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist #if HAVE_XLINQ if (objectType == typeof(XElement)) { - XElement element = (XElement)document.DocumentElement.WrappedNode; + XElement element = (XElement)document.DocumentElement!.WrappedNode!; element.Remove(); return element; @@ -1554,7 +1560,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist #if HAVE_XML_DOCUMENT if (objectType == typeof(XmlElement)) { - return document.DocumentElement.WrappedNode; + return document.DocumentElement!.WrappedNode; } #endif @@ -1581,7 +1587,7 @@ private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNames return; default: // processing instructions and the xml declaration start with ? - if (!string.IsNullOrEmpty(propertyName) && propertyName[0] == '?') + if (!StringUtils.IsNullOrEmpty(propertyName) && propertyName[0] == '?') { CreateInstruction(reader, document, currentNode, propertyName); return; @@ -1611,13 +1617,13 @@ private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNames private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager) { - if (string.IsNullOrEmpty(propertyName)) + if (StringUtils.IsNullOrEmpty(propertyName)) { throw JsonSerializationException.Create(reader, "XmlNodeConverter cannot convert JSON with an empty property name to XML."); } - Dictionary attributeNameValues = null; - string elementPrefix = null; + Dictionary? attributeNameValues = null; + string? elementPrefix = null; if (!EncodeSpecialCharacters) { @@ -1629,7 +1635,7 @@ private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode curr if (propertyName.StartsWith('@')) { string attributeName = propertyName.Substring(1); - string attributePrefix = MiscellaneousUtils.GetPrefix(attributeName); + string? attributePrefix = MiscellaneousUtils.GetPrefix(attributeName); AddAttribute(reader, document, currentNode, propertyName, attributeName, manager, attributePrefix); return; @@ -1649,7 +1655,7 @@ private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode curr case JsonTypeReflector.TypePropertyName: case JsonTypeReflector.ValuePropertyName: string attributeName = propertyName.Substring(1); - string attributePrefix = manager.LookupPrefix(JsonNamespaceUri); + string? attributePrefix = manager.LookupPrefix(JsonNamespaceUri); AddAttribute(reader, document, currentNode, propertyName, attributeName, manager, attributePrefix); return; } @@ -1666,7 +1672,7 @@ private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode curr CreateElement(reader, document, currentNode, propertyName, manager, elementPrefix, attributeNameValues); } - private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string elementName, XmlNamespaceManager manager, string elementPrefix, Dictionary attributeNameValues) + private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string elementName, XmlNamespaceManager manager, string? elementPrefix, Dictionary? attributeNameValues) { IXmlElement element = CreateElement(elementName, document, elementPrefix, manager); @@ -1675,12 +1681,14 @@ private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode cu if (attributeNameValues != null) { // add attributes to newly created element - foreach (KeyValuePair nameValue in attributeNameValues) + foreach (KeyValuePair nameValue in attributeNameValues) { string encodedName = XmlConvert.EncodeName(nameValue.Key); - string attributePrefix = MiscellaneousUtils.GetPrefix(nameValue.Key); + string? attributePrefix = MiscellaneousUtils.GetPrefix(nameValue.Key); - IXmlNode attribute = (!string.IsNullOrEmpty(attributePrefix)) ? document.CreateAttribute(encodedName, manager.LookupNamespace(attributePrefix) ?? string.Empty, nameValue.Value) : document.CreateAttribute(encodedName, nameValue.Value); + IXmlNode attribute = (!StringUtils.IsNullOrEmpty(attributePrefix)) + ? document.CreateAttribute(encodedName, manager.LookupNamespace(attributePrefix) ?? string.Empty, nameValue.Value!) + : document.CreateAttribute(encodedName, nameValue.Value!); element.SetAttributeNode(attribute); } @@ -1694,7 +1702,7 @@ private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode cu case JsonToken.Boolean: case JsonToken.Date: case JsonToken.Bytes: - string text = ConvertTokenToXmlValue(reader); + string? text = ConvertTokenToXmlValue(reader); if (text != null) { element.AppendChild(document.CreateTextNode(text)); @@ -1718,7 +1726,7 @@ private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode cu } } - private static void AddAttribute(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, string attributeName, XmlNamespaceManager manager, string attributePrefix) + private static void AddAttribute(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, string attributeName, XmlNamespaceManager manager, string? attributePrefix) { if (currentNode.NodeType == XmlNodeType.Document) { @@ -1726,16 +1734,16 @@ private static void AddAttribute(JsonReader reader, IXmlDocument document, IXmlN } string encodedName = XmlConvert.EncodeName(attributeName); - string attributeValue = ConvertTokenToXmlValue(reader); + string attributeValue = ConvertTokenToXmlValue(reader)!; - IXmlNode attribute = (!string.IsNullOrEmpty(attributePrefix)) - ? document.CreateAttribute(encodedName, manager.LookupNamespace(attributePrefix), attributeValue) + IXmlNode attribute = (!StringUtils.IsNullOrEmpty(attributePrefix)) + ? document.CreateAttribute(encodedName, manager.LookupNamespace(attributePrefix)!, attributeValue) : document.CreateAttribute(encodedName, attributeValue); ((IXmlElement)currentNode).SetAttributeNode(attribute); } - private static string ConvertTokenToXmlValue(JsonReader reader) + private static string? ConvertTokenToXmlValue(JsonReader reader) { switch (reader.TokenType) { @@ -1782,7 +1790,7 @@ private static string ConvertTokenToXmlValue(JsonReader reader) #endif } case JsonToken.Bytes: - return Convert.ToBase64String((byte[])reader.Value); + return Convert.ToBase64String((byte[])reader.Value!); case JsonToken.Null: return null; default: @@ -1792,7 +1800,7 @@ private static string ConvertTokenToXmlValue(JsonReader reader) private void ReadArrayElements(JsonReader reader, IXmlDocument document, string propertyName, IXmlNode currentNode, XmlNamespaceManager manager) { - string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName); + string? elementPrefix = MiscellaneousUtils.GetPrefix(propertyName); IXmlElement nestedArrayElement = CreateElement(propertyName, document, elementPrefix, manager); @@ -1858,9 +1866,9 @@ private bool ShouldReadInto(JsonReader reader) return true; } - private Dictionary ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager) + private Dictionary? ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager) { - Dictionary attributeNameValues = null; + Dictionary? attributeNameValues = null; bool finished = false; // read properties until first non-attribute is encountered @@ -1869,19 +1877,19 @@ private Dictionary ReadAttributeElements(JsonReader reader, XmlN switch (reader.TokenType) { case JsonToken.PropertyName: - string attributeName = reader.Value.ToString(); + string attributeName = reader.Value!.ToString()!; - if (!string.IsNullOrEmpty(attributeName)) + if (!StringUtils.IsNullOrEmpty(attributeName)) { char firstChar = attributeName[0]; - string attributeValue; + string? attributeValue; switch (firstChar) { case '@': if (attributeNameValues == null) { - attributeNameValues = new Dictionary(); + attributeNameValues = new Dictionary(); } attributeName = attributeName.Substring(1); @@ -1889,9 +1897,9 @@ private Dictionary ReadAttributeElements(JsonReader reader, XmlN attributeValue = ConvertTokenToXmlValue(reader); attributeNameValues.Add(attributeName, attributeValue); - if (IsNamespaceAttribute(attributeName, out string namespacePrefix)) + if (IsNamespaceAttribute(attributeName, out string? namespacePrefix)) { - manager.AddNamespace(namespacePrefix, attributeValue); + manager.AddNamespace(namespacePrefix, attributeValue!); } break; case '$': @@ -1904,12 +1912,12 @@ private Dictionary ReadAttributeElements(JsonReader reader, XmlN case JsonTypeReflector.ValuePropertyName: // check that JsonNamespaceUri is in scope // if it isn't then add it to document and namespace manager - string jsonPrefix = manager.LookupPrefix(JsonNamespaceUri); + string? jsonPrefix = manager.LookupPrefix(JsonNamespaceUri); if (jsonPrefix == null) { if (attributeNameValues == null) { - attributeNameValues = new Dictionary(); + attributeNameValues = new Dictionary(); } // ensure that the prefix used is free @@ -1941,7 +1949,7 @@ private Dictionary ReadAttributeElements(JsonReader reader, XmlN if (attributeNameValues == null) { - attributeNameValues = new Dictionary(); + attributeNameValues = new Dictionary(); } attributeValue = reader.Value?.ToString(); @@ -1979,12 +1987,12 @@ private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNod { if (propertyName == DeclarationName) { - string version = null; - string encoding = null; - string standalone = null; + string? version = null; + string? encoding = null; + string? standalone = null; while (reader.Read() && reader.TokenType != JsonToken.EndObject) { - switch (reader.Value.ToString()) + switch (reader.Value?.ToString()) { case "@version": reader.ReadAndAssert(); @@ -2003,12 +2011,17 @@ private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNod } } + if (version == null) + { + throw JsonSerializationException.Create(reader, "Version not specified for XML declaration."); + } + IXmlNode declaration = document.CreateXmlDeclaration(version, encoding, standalone); currentNode.AppendChild(declaration); } else { - IXmlNode instruction = document.CreateProcessingInstruction(propertyName.Substring(1), ConvertTokenToXmlValue(reader)); + IXmlNode instruction = document.CreateProcessingInstruction(propertyName.Substring(1), ConvertTokenToXmlValue(reader)!); currentNode.AppendChild(instruction); } } @@ -2016,13 +2029,13 @@ private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNod #if HAVE_XML_DOCUMENT_TYPE private void CreateDocumentType(JsonReader reader, IXmlDocument document, IXmlNode currentNode) { - string name = null; - string publicId = null; - string systemId = null; - string internalSubset = null; + string? name = null; + string? publicId = null; + string? systemId = null; + string? internalSubset = null; while (reader.Read() && reader.TokenType != JsonToken.EndObject) { - switch (reader.Value.ToString()) + switch (reader.Value?.ToString()) { case "@name": reader.ReadAndAssert(); @@ -2045,17 +2058,22 @@ private void CreateDocumentType(JsonReader reader, IXmlDocument document, IXmlNo } } + if (name == null) + { + throw JsonSerializationException.Create(reader, "Name not specified for XML document type."); + } + IXmlNode documentType = document.CreateXmlDocumentType(name, publicId, systemId, internalSubset); currentNode.AppendChild(documentType); } #endif - private IXmlElement CreateElement(string elementName, IXmlDocument document, string elementPrefix, XmlNamespaceManager manager) + private IXmlElement CreateElement(string elementName, IXmlDocument document, string? elementPrefix, XmlNamespaceManager manager) { string encodeName = EncodeSpecialCharacters ? XmlConvert.EncodeLocalName(elementName) : XmlConvert.EncodeName(elementName); - string ns = string.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix); + string? ns = StringUtils.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix); - IXmlElement element = (!string.IsNullOrEmpty(ns)) ? document.CreateElement(encodeName, ns) : document.CreateElement(encodeName); + IXmlElement element = (!StringUtils.IsNullOrEmpty(ns)) ? document.CreateElement(encodeName, ns) : document.CreateElement(encodeName); return element; } @@ -2072,7 +2090,7 @@ private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamesp throw JsonSerializationException.Create(reader, "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifying a DeserializeRootElementName."); } - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; reader.ReadAndAssert(); if (reader.TokenType == JsonToken.StartArray) @@ -2086,8 +2104,8 @@ private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamesp if (count == 1 && WriteArrayAttribute) { - MiscellaneousUtils.GetQualifiedNameParts(propertyName, out string elementPrefix, out string localName); - string ns = string.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix); + MiscellaneousUtils.GetQualifiedNameParts(propertyName, out string? elementPrefix, out string localName); + string? ns = StringUtils.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix); foreach (IXmlNode childNode in currentNode.ChildNodes) { @@ -2105,7 +2123,7 @@ private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamesp } continue; case JsonToken.StartConstructor: - string constructorName = reader.Value.ToString(); + string constructorName = reader.Value!.ToString()!; while (reader.Read() && reader.TokenType != JsonToken.EndConstructor) { @@ -2113,7 +2131,7 @@ private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamesp } break; case JsonToken.Comment: - currentNode.AppendChild(document.CreateComment((string)reader.Value)); + currentNode.AppendChild(document.CreateComment((string)reader.Value!)); break; case JsonToken.EndObject: case JsonToken.EndArray: @@ -2131,7 +2149,7 @@ private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamesp /// Attribute name to test. /// The attribute name prefix if it has one, otherwise an empty string. /// true if attribute name is for a namespace attribute, otherwise false. - private bool IsNamespaceAttribute(string attributeName, out string prefix) + private bool IsNamespaceAttribute(string attributeName, [NotNullWhen(true)]out string? prefix) { if (attributeName.StartsWith("xmlns", StringComparison.Ordinal)) { @@ -2212,6 +2230,7 @@ private bool IsXmlNode(Type valueType) } #endif } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/DateFormatHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/DateFormatHandling.cs index 0d24f7efcb..f8038dce34 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/DateFormatHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/DateFormatHandling.cs @@ -40,4 +40,4 @@ internal enum DateFormatHandling /// MicrosoftDateFormat } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/DateParseHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/DateParseHandling.cs index 4c2e068c3a..669c22b38a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/DateParseHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/DateParseHandling.cs @@ -36,14 +36,14 @@ internal enum DateParseHandling None = 0, /// - /// Date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z", are parsed to . + /// Date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z", are parsed to . /// DateTime = 1, #if HAVE_DATE_TIME_OFFSET /// - /// Date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z", are parsed to . + /// Date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z", are parsed to . /// DateTimeOffset = 2 #endif } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/DateTimeZoneHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/DateTimeZoneHandling.cs index 80f7479da2..90faf8bed8 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/DateTimeZoneHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/DateTimeZoneHandling.cs @@ -53,4 +53,4 @@ internal enum DateTimeZoneHandling /// RoundtripKind = 3 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/DefaultJsonNameTable.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/DefaultJsonNameTable.cs index 8b46018a91..8fc616a90e 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/DefaultJsonNameTable.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/DefaultJsonNameTable.cs @@ -24,9 +24,11 @@ #endregion using System; +using System.Threading; namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// The default JSON name table implementation. /// @@ -53,12 +55,13 @@ public DefaultJsonNameTable() } /// - /// Gets the string containing the same characters as the specified range of characters in the given array. + /// Gets a string containing the same characters as the specified range of characters in the given array. /// /// The character array containing the name to find. /// The zero-based index into the array specifying the first character of the name. /// The number of characters in the name. - public override string Get(char[] key, int start, int length) + /// A string containing the same characters as the specified range of characters in the given array. + public override string? Get(char[] key, int start, int length) { if (length == 0) { @@ -77,7 +80,8 @@ public override string Get(char[] key, int start, int length) hashCode -= hashCode >> 5; // make sure index is evaluated before accessing _entries, otherwise potential race condition causing IndexOutOfRangeException - var index = hashCode & _mask; + int mask = Volatile.Read(ref _mask); + var index = hashCode & mask; var entries = _entries; for (Entry entry = entries[index]; entry != null; entry = entry.Next) @@ -96,6 +100,7 @@ public override string Get(char[] key, int start, int length) /// /// The string to add. /// This method is not thread-safe. + /// The resolved string. public string Add(string key) { if (key == null) @@ -119,7 +124,7 @@ public string Add(string key) hashCode -= hashCode >> 5; for (Entry entry = _entries[hashCode & _mask]; entry != null; entry = entry.Next) { - if (entry.HashCode == hashCode && entry.Value.Equals(key)) + if (entry.HashCode == hashCode && entry.Value.Equals(key, StringComparison.Ordinal)) { return entry.Value; } @@ -158,7 +163,12 @@ private void Grow() } } _entries = newEntries; - _mask = newMask; + +#if NET20 || NET35 || NET40 + Thread.VolatileWrite(ref _mask, newMask); +#else + Volatile.Write(ref _mask, newMask); +#endif } private static bool TextEquals(string str1, char[] str2, int str2Start, int str2Length) @@ -192,4 +202,5 @@ internal Entry(string value, int hashCode, Entry next) } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/DefaultValueHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/DefaultValueHandling.cs index 5eae7a7ce5..b1e96a1947 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/DefaultValueHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/DefaultValueHandling.cs @@ -38,13 +38,11 @@ namespace Microsoft.IdentityModel.Json [Flags] internal enum DefaultValueHandling { -#pragma warning disable CA1008 // Enums should have zero value - /// - /// Include members where the member value is the same as the member's default value when serializing objects. - /// Included members are written to JSON. Has no effect when deserializing. - /// + /// + /// Include members where the member value is the same as the member's default value when serializing objects. + /// Included members are written to JSON. Has no effect when deserializing. + /// Include = 0, -#pragma warning restore CA1008 // Enums should have zero value /// /// Ignore members where the member value is the same as the member's default value when serializing objects @@ -66,4 +64,4 @@ internal enum DefaultValueHandling /// IgnoreAndPopulate = Ignore | Populate } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Dynamic.snk b/src/Microsoft.IdentityModel.Tokens/opensource/json/Dynamic.snk new file mode 100644 index 0000000000..2225208ac0 Binary files /dev/null and b/src/Microsoft.IdentityModel.Tokens/opensource/json/Dynamic.snk differ diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/FloatFormatHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/FloatFormatHandling.cs index af6f83d9d1..c0922604a1 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/FloatFormatHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/FloatFormatHandling.cs @@ -49,4 +49,4 @@ internal enum FloatFormatHandling /// DefaultValue = 2 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/FloatParseHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/FloatParseHandling.cs index 751d778c35..4cf55a85da 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/FloatParseHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/FloatParseHandling.cs @@ -40,4 +40,4 @@ internal enum FloatParseHandling /// Decimal = 1 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/FormatterAssemblyStyle.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/FormatterAssemblyStyle.cs index b3ba268508..4504af98ba 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/FormatterAssemblyStyle.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/FormatterAssemblyStyle.cs @@ -21,4 +21,4 @@ internal enum FormatterAssemblyStyle } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Formatting.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Formatting.cs index b637fcd1b9..5d86facdfe 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Formatting.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Formatting.cs @@ -40,4 +40,4 @@ internal enum Formatting /// Indented = 1 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/IArrayPool.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/IArrayPool.cs index c27b800b21..acaf2eec5b 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/IArrayPool.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/IArrayPool.cs @@ -1,5 +1,6 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// Provides an interface for using pooled arrays. /// @@ -17,6 +18,7 @@ internal interface IArrayPool /// Return an array to the pool. /// /// The array that is being returned. - void Return(T[] array); + void Return(T[]? array); } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/IJsonLineInfo.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/IJsonLineInfo.cs index e75650bd91..158c82c5ae 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/IJsonLineInfo.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/IJsonLineInfo.cs @@ -50,4 +50,4 @@ internal interface IJsonLineInfo /// The current line position or 0 if no line information is available (for example, when returns false). int LinePosition { get; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonArrayAttribute.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonArrayAttribute.cs index 1a9b5ba33d..4278754b46 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonArrayAttribute.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonArrayAttribute.cs @@ -70,4 +70,4 @@ public JsonArrayAttribute(string id) { } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConstructorAttribute.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConstructorAttribute.cs index 68a61733e8..1e9c91d1c8 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConstructorAttribute.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConstructorAttribute.cs @@ -34,4 +34,4 @@ namespace Microsoft.IdentityModel.Json internal sealed class JsonConstructorAttribute : Attribute { } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonContainerAttribute.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonContainerAttribute.cs index a3d3a67eff..06b23e7500 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonContainerAttribute.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonContainerAttribute.cs @@ -28,6 +28,7 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// Instructs the how to serialize the object. /// @@ -38,25 +39,25 @@ internal abstract class JsonContainerAttribute : Attribute /// Gets or sets the id. /// /// The id. - public string Id { get; set; } + public string? Id { get; set; } /// /// Gets or sets the title. /// /// The title. - public string Title { get; set; } + public string? Title { get; set; } /// /// Gets or sets the description. /// /// The description. - public string Description { get; set; } + public string? Description { get; set; } /// /// Gets or sets the collection's items converter. /// /// The collection's items converter. - public Type ItemConverterType { get; set; } + public Type? ItemConverterType { get; set; } /// /// The parameter list to use when constructing the described by . @@ -69,13 +70,13 @@ internal abstract class JsonContainerAttribute : Attribute /// [JsonContainer(ItemConverterType = typeof(MyContainerConverter), ItemConverterParameters = new object[] { 123, "Four" })] /// /// - public object[] ItemConverterParameters { get; set; } + public object[]? ItemConverterParameters { get; set; } /// /// Gets or sets the of the . /// /// The of the . - public Type NamingStrategyType + public Type? NamingStrategyType { get => _namingStrategyType; set @@ -96,7 +97,7 @@ public Type NamingStrategyType /// [JsonContainer(NamingStrategyType = typeof(MyNamingStrategy), NamingStrategyParameters = new object[] { 123, "Four" })] /// /// - public object[] NamingStrategyParameters + public object[]? NamingStrategyParameters { get => _namingStrategyParameters; set @@ -106,7 +107,7 @@ public object[] NamingStrategyParameters } } - internal NamingStrategy NamingStrategyInstance { get; set; } + internal NamingStrategy? NamingStrategyInstance { get; set; } // yuck. can't set nullable properties on an attribute in C# // have to use this approach to get an unset default state @@ -114,8 +115,8 @@ public object[] NamingStrategyParameters internal bool? _itemIsReference; internal ReferenceLoopHandling? _itemReferenceLoopHandling; internal TypeNameHandling? _itemTypeNameHandling; - private Type _namingStrategyType; - private object[] _namingStrategyParameters; + private Type? _namingStrategyType; + private object[]? _namingStrategyParameters; /// /// Gets or sets a value that indicates whether to preserve object references. @@ -177,4 +178,5 @@ protected JsonContainerAttribute(string id) Id = id; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConvert.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConvert.cs index da2582d9fa..97ef41fda9 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConvert.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConvert.cs @@ -36,13 +36,16 @@ using Microsoft.IdentityModel.Json.Serialization; using System.Text; using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if HAVE_XLINQ using System.Xml.Linq; - #endif namespace Microsoft.IdentityModel.Json { +#nullable enable +#pragma warning disable CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly /// /// Provides methods for converting between .NET types and JSON types. /// @@ -58,7 +61,7 @@ internal static class JsonConvert /// To serialize without using any default settings create a with /// . /// - public static Func DefaultSettings { get; set; } + public static Func? DefaultSettings { get; set; } /// /// Represents JavaScript's boolean value true as a string. This field is read-only. @@ -209,7 +212,7 @@ public static string ToString(short value) /// /// The value to convert. /// A JSON string representation of the . - // [ClsCompliant(false)] + [CLSCompliant(false)] public static string ToString(ushort value) { return value.ToString(null, CultureInfo.InvariantCulture); @@ -220,7 +223,7 @@ public static string ToString(ushort value) /// /// The value to convert. /// A JSON string representation of the . - // [ClsCompliant(false)] + [CLSCompliant(false)] public static string ToString(uint value) { return value.ToString(null, CultureInfo.InvariantCulture); @@ -248,7 +251,7 @@ private static string ToStringInternal(BigInteger value) /// /// The value to convert. /// A JSON string representation of the . - // [ClsCompliant(false)] + [CLSCompliant(false)] public static string ToString(ulong value) { return value.ToString(null, CultureInfo.InvariantCulture); @@ -301,7 +304,7 @@ internal static string ToString(double value, FloatFormatHandling floatFormatHan private static string EnsureDecimalPlace(double value, string text) { - if (double.IsNaN(value) || double.IsInfinity(value) || text.IndexOf('.') != -1 || text.IndexOf('E') != -1 || text.IndexOf('e') != -1) + if (double.IsNaN(value) || double.IsInfinity(value) || StringUtils.IndexOf(text, '.') != -1 || StringUtils.IndexOf(text, 'E') != -1 || StringUtils.IndexOf(text, 'e') != -1) { return text; } @@ -311,7 +314,7 @@ private static string EnsureDecimalPlace(double value, string text) private static string EnsureDecimalPlace(string text) { - if (text.IndexOf('.') != -1) + if (StringUtils.IndexOf(text, '.') != -1) { return text; } @@ -334,7 +337,7 @@ public static string ToString(byte value) /// /// The value to convert. /// A JSON string representation of the . - // [ClsCompliant(false)] + [CLSCompliant(false)] public static string ToString(sbyte value) { return value.ToString(null, CultureInfo.InvariantCulture); @@ -344,7 +347,7 @@ public static string ToString(sbyte value) /// Converts the to its JSON string representation. /// /// The value to convert. - /// A JSON string representation of the . + /// A JSON string representation of the . public static string ToString(decimal value) { return EnsureDecimalPlace(value.ToString(null, CultureInfo.InvariantCulture)); @@ -368,10 +371,8 @@ internal static string ToString(Guid value, char quoteChar) text = value.ToString("D", CultureInfo.InvariantCulture); qc = quoteChar.ToString(CultureInfo.InvariantCulture); #else -#pragma warning disable CA1305 // Specify IFormatProvider text = value.ToString("D"); qc = quoteChar.ToString(); -#pragma warning restore CA1305 // Specify IFormatProvider #endif return qc + text + qc; @@ -397,7 +398,7 @@ internal static string ToString(TimeSpan value, char quoteChar) /// /// The value to convert. /// A JSON string representation of the . - public static string ToString(Uri value) + public static string ToString(Uri? value) { if (value == null) { @@ -417,7 +418,7 @@ internal static string ToString(Uri value, char quoteChar) /// /// The value to convert. /// A JSON string representation of the . - public static string ToString(string value) + public static string ToString(string? value) { return ToString(value, '"'); } @@ -428,7 +429,7 @@ public static string ToString(string value) /// The value to convert. /// The string delimiter character. /// A JSON string representation of the . - public static string ToString(string value, char delimiter) + public static string ToString(string? value, char delimiter) { return ToString(value, delimiter, StringEscapeHandling.Default); } @@ -440,7 +441,7 @@ public static string ToString(string value, char delimiter) /// The string delimiter character. /// The string escape handling. /// A JSON string representation of the . - public static string ToString(string value, char delimiter, StringEscapeHandling stringEscapeHandling) + public static string ToString(string? value, char delimiter, StringEscapeHandling stringEscapeHandling) { if (delimiter != '"' && delimiter != '\'') { @@ -455,7 +456,7 @@ public static string ToString(string value, char delimiter, StringEscapeHandling /// /// The value to convert. /// A JSON string representation of the . - public static string ToString(object value) + public static string ToString(object? value) { if (value == null) { @@ -526,9 +527,9 @@ public static string ToString(object value) /// The object to serialize. /// A JSON string representation of the object. [DebuggerStepThrough] - public static string SerializeObject(object value) + public static string SerializeObject(object? value) { - return SerializeObject(value, null, (JsonSerializerSettings)null); + return SerializeObject(value, null, (JsonSerializerSettings?)null); } /// @@ -540,9 +541,9 @@ public static string SerializeObject(object value) /// A JSON string representation of the object. /// [DebuggerStepThrough] - public static string SerializeObject(object value, Formatting formatting) + public static string SerializeObject(object? value, Formatting formatting) { - return SerializeObject(value, formatting, (JsonSerializerSettings)null); + return SerializeObject(value, formatting, (JsonSerializerSettings?)null); } /// @@ -552,9 +553,9 @@ public static string SerializeObject(object value, Formatting formatting) /// A collection of converters used while serializing. /// A JSON string representation of the object. [DebuggerStepThrough] - public static string SerializeObject(object value, params JsonConverter[] converters) + public static string SerializeObject(object? value, params JsonConverter[] converters) { - JsonSerializerSettings settings = (converters != null && converters.Length > 0) + JsonSerializerSettings? settings = (converters != null && converters.Length > 0) ? new JsonSerializerSettings { Converters = converters } : null; @@ -569,9 +570,9 @@ public static string SerializeObject(object value, params JsonConverter[] conver /// A collection of converters used while serializing. /// A JSON string representation of the object. [DebuggerStepThrough] - public static string SerializeObject(object value, Formatting formatting, params JsonConverter[] converters) + public static string SerializeObject(object? value, Formatting formatting, params JsonConverter[] converters) { - JsonSerializerSettings settings = (converters != null && converters.Length > 0) + JsonSerializerSettings? settings = (converters != null && converters.Length > 0) ? new JsonSerializerSettings { Converters = converters } : null; @@ -588,7 +589,7 @@ public static string SerializeObject(object value, Formatting formatting, params /// A JSON string representation of the object. /// [DebuggerStepThrough] - public static string SerializeObject(object value, JsonSerializerSettings settings) + public static string SerializeObject(object? value, JsonSerializerSettings? settings) { return SerializeObject(value, null, settings); } @@ -608,7 +609,7 @@ public static string SerializeObject(object value, JsonSerializerSettings settin /// A JSON string representation of the object. /// [DebuggerStepThrough] - public static string SerializeObject(object value, Type type, JsonSerializerSettings settings) + public static string SerializeObject(object? value, Type? type, JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings); @@ -626,7 +627,7 @@ public static string SerializeObject(object value, Type type, JsonSerializerSett /// A JSON string representation of the object. /// [DebuggerStepThrough] - public static string SerializeObject(object value, Formatting formatting, JsonSerializerSettings settings) + public static string SerializeObject(object? value, Formatting formatting, JsonSerializerSettings? settings) { return SerializeObject(value, null, formatting, settings); } @@ -647,7 +648,7 @@ public static string SerializeObject(object value, Formatting formatting, JsonSe /// A JSON string representation of the object. /// [DebuggerStepThrough] - public static string SerializeObject(object value, Type type, Formatting formatting, JsonSerializerSettings settings) + public static string SerializeObject(object? value, Type? type, Formatting formatting, JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings); jsonSerializer.Formatting = formatting; @@ -655,7 +656,7 @@ public static string SerializeObject(object value, Type type, Formatting formatt return SerializeObjectInternal(value, type, jsonSerializer); } - private static string SerializeObjectInternal(object value, Type type, JsonSerializer jsonSerializer) + private static string SerializeObjectInternal(object? value, Type? type, JsonSerializer jsonSerializer) { StringBuilder sb = new StringBuilder(256); StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture); @@ -677,9 +678,9 @@ private static string SerializeObjectInternal(object value, Type type, JsonSeria /// The JSON to deserialize. /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static object DeserializeObject(string value) + public static object? DeserializeObject(string value) { - return DeserializeObject(value, null, (JsonSerializerSettings)null); + return DeserializeObject(value, null, (JsonSerializerSettings?)null); } /// @@ -692,7 +693,7 @@ public static object DeserializeObject(string value) /// /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static object DeserializeObject(string value, JsonSerializerSettings settings) + public static object? DeserializeObject(string value, JsonSerializerSettings settings) { return DeserializeObject(value, null, settings); } @@ -704,9 +705,9 @@ public static object DeserializeObject(string value, JsonSerializerSettings sett /// The of object being deserialized. /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static object DeserializeObject(string value, Type type) + public static object? DeserializeObject(string value, Type type) { - return DeserializeObject(value, type, (JsonSerializerSettings)null); + return DeserializeObject(value, type, (JsonSerializerSettings?)null); } /// @@ -716,9 +717,9 @@ public static object DeserializeObject(string value, Type type) /// The JSON to deserialize. /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static T DeserializeObject(string value) + public static T? DeserializeObject(string value) { - return DeserializeObject(value, (JsonSerializerSettings)null); + return DeserializeObject(value, (JsonSerializerSettings?)null); } /// @@ -733,7 +734,7 @@ public static T DeserializeObject(string value) /// The anonymous type object. /// The deserialized anonymous type from the JSON string. [DebuggerStepThrough] - public static T DeserializeAnonymousType(string value, T anonymousTypeObject) + public static T? DeserializeAnonymousType(string value, T anonymousTypeObject) { return DeserializeObject(value); } @@ -754,7 +755,7 @@ public static T DeserializeAnonymousType(string value, T anonymousTypeObject) /// /// The deserialized anonymous type from the JSON string. [DebuggerStepThrough] - public static T DeserializeAnonymousType(string value, T anonymousTypeObject, JsonSerializerSettings settings) + public static T? DeserializeAnonymousType(string value, T anonymousTypeObject, JsonSerializerSettings settings) { return DeserializeObject(value, settings); } @@ -767,9 +768,9 @@ public static T DeserializeAnonymousType(string value, T anonymousTypeObject, /// Converters to use while deserializing. /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static T DeserializeObject(string value, params JsonConverter[] converters) + public static T? DeserializeObject(string value, params JsonConverter[] converters) { - return (T)DeserializeObject(value, typeof(T), converters); + return (T?)DeserializeObject(value, typeof(T), converters); } /// @@ -783,9 +784,9 @@ public static T DeserializeObject(string value, params JsonConverter[] conver /// /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static T DeserializeObject(string value, JsonSerializerSettings settings) + public static T? DeserializeObject(string value, JsonSerializerSettings? settings) { - return (T)DeserializeObject(value, typeof(T), settings); + return (T?)DeserializeObject(value, typeof(T), settings); } /// @@ -796,9 +797,9 @@ public static T DeserializeObject(string value, JsonSerializerSettings settin /// Converters to use while deserializing. /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static object DeserializeObject(string value, Type type, params JsonConverter[] converters) + public static object? DeserializeObject(string value, Type type, params JsonConverter[] converters) { - JsonSerializerSettings settings = (converters != null && converters.Length > 0) + JsonSerializerSettings? settings = (converters != null && converters.Length > 0) ? new JsonSerializerSettings { Converters = converters } : null; @@ -815,7 +816,7 @@ public static object DeserializeObject(string value, Type type, params JsonConve /// If this is null, default serialization settings will be used. /// /// The deserialized object from the JSON string. - public static object DeserializeObject(string value, Type type, JsonSerializerSettings settings) + public static object? DeserializeObject(string value, Type? type, JsonSerializerSettings? settings) { ValidationUtils.ArgumentNotNull(value, nameof(value)); @@ -855,7 +856,7 @@ public static void PopulateObject(string value, object target) /// The used to deserialize the object. /// If this is null, default serialization settings will be used. /// - public static void PopulateObject(string value, object target, JsonSerializerSettings settings) + public static void PopulateObject(string value, object target, JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings); @@ -884,7 +885,7 @@ public static void PopulateObject(string value, object target, JsonSerializerSet /// /// The node to serialize. /// A JSON string of the . - public static string SerializeXmlNode(XmlNode node) + public static string SerializeXmlNode(XmlNode? node) { return SerializeXmlNode(node, Formatting.None); } @@ -895,7 +896,7 @@ public static string SerializeXmlNode(XmlNode node) /// The node to serialize. /// Indicates how the output should be formatted. /// A JSON string of the . - public static string SerializeXmlNode(XmlNode node, Formatting formatting) + public static string SerializeXmlNode(XmlNode? node, Formatting formatting) { XmlNodeConverter converter = new XmlNodeConverter(); @@ -909,7 +910,7 @@ public static string SerializeXmlNode(XmlNode node, Formatting formatting) /// Indicates how the output should be formatted. /// Omits writing the root object. /// A JSON string of the . - public static string SerializeXmlNode(XmlNode node, Formatting formatting, bool omitRootObject) + public static string SerializeXmlNode(XmlNode? node, Formatting formatting, bool omitRootObject) { XmlNodeConverter converter = new XmlNodeConverter { OmitRootObject = omitRootObject }; @@ -921,7 +922,7 @@ public static string SerializeXmlNode(XmlNode node, Formatting formatting, bool /// /// The JSON string. /// The deserialized . - public static XmlDocument DeserializeXmlNode(string value) + public static XmlDocument? DeserializeXmlNode(string value) { return DeserializeXmlNode(value, null); } @@ -932,7 +933,7 @@ public static XmlDocument DeserializeXmlNode(string value) /// The JSON string. /// The name of the root element to append when deserializing. /// The deserialized . - public static XmlDocument DeserializeXmlNode(string value, string deserializeRootElementName) + public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName) { return DeserializeXmlNode(value, deserializeRootElementName, false); } @@ -948,7 +949,7 @@ public static XmlDocument DeserializeXmlNode(string value, string deserializeRoo /// This attribute helps preserve arrays when converting the written XML back to JSON. /// /// The deserialized . - public static XmlDocument DeserializeXmlNode(string value, string deserializeRootElementName, bool writeArrayAttribute) + public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute) { return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute, false); } @@ -970,14 +971,14 @@ public static XmlDocument DeserializeXmlNode(string value, string deserializeRoo /// as part of the XML element name. /// /// The deserialized . - public static XmlDocument DeserializeXmlNode(string value, string deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters) + public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters) { XmlNodeConverter converter = new XmlNodeConverter(); converter.DeserializeRootElementName = deserializeRootElementName; converter.WriteArrayAttribute = writeArrayAttribute; converter.EncodeSpecialCharacters = encodeSpecialCharacters; - return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), converter); + return (XmlDocument?)DeserializeObject(value, typeof(XmlDocument), converter); } #endif @@ -987,7 +988,7 @@ public static XmlDocument DeserializeXmlNode(string value, string deserializeRoo /// /// The node to convert to JSON. /// A JSON string of the . - public static string SerializeXNode(XObject node) + public static string SerializeXNode(XObject? node) { return SerializeXNode(node, Formatting.None); } @@ -998,7 +999,7 @@ public static string SerializeXNode(XObject node) /// The node to convert to JSON. /// Indicates how the output should be formatted. /// A JSON string of the . - public static string SerializeXNode(XObject node, Formatting formatting) + public static string SerializeXNode(XObject? node, Formatting formatting) { return SerializeXNode(node, formatting, false); } @@ -1010,7 +1011,7 @@ public static string SerializeXNode(XObject node, Formatting formatting) /// Indicates how the output should be formatted. /// Omits writing the root object. /// A JSON string of the . - public static string SerializeXNode(XObject node, Formatting formatting, bool omitRootObject) + public static string SerializeXNode(XObject? node, Formatting formatting, bool omitRootObject) { XmlNodeConverter converter = new XmlNodeConverter { OmitRootObject = omitRootObject }; @@ -1022,7 +1023,7 @@ public static string SerializeXNode(XObject node, Formatting formatting, bool om /// /// The JSON string. /// The deserialized . - public static XDocument DeserializeXNode(string value) + public static XDocument? DeserializeXNode(string value) { return DeserializeXNode(value, null); } @@ -1033,7 +1034,7 @@ public static XDocument DeserializeXNode(string value) /// The JSON string. /// The name of the root element to append when deserializing. /// The deserialized . - public static XDocument DeserializeXNode(string value, string deserializeRootElementName) + public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName) { return DeserializeXNode(value, deserializeRootElementName, false); } @@ -1049,7 +1050,7 @@ public static XDocument DeserializeXNode(string value, string deserializeRootEle /// This attribute helps preserve arrays when converting the written XML back to JSON. /// /// The deserialized . - public static XDocument DeserializeXNode(string value, string deserializeRootElementName, bool writeArrayAttribute) + public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute) { return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute, false); } @@ -1071,16 +1072,18 @@ public static XDocument DeserializeXNode(string value, string deserializeRootEle /// as part of the XML element name. /// /// The deserialized . - public static XDocument DeserializeXNode(string value, string deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters) + public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters) { XmlNodeConverter converter = new XmlNodeConverter(); converter.DeserializeRootElementName = deserializeRootElementName; converter.WriteArrayAttribute = writeArrayAttribute; converter.EncodeSpecialCharacters = encodeSpecialCharacters; - return (XDocument)DeserializeObject(value, typeof(XDocument), converter); + return (XDocument?)DeserializeObject(value, typeof(XDocument), converter); } #endif #endregion } -} \ No newline at end of file +#nullable disable +#pragma warning restore CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConverter.cs index 3258f419d5..e4498b65d3 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConverter.cs @@ -26,10 +26,12 @@ using System; using Microsoft.IdentityModel.Json.Utilities; using System.Globalization; -using System.Reflection; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// Converts an object to and from JSON. /// @@ -41,7 +43,7 @@ internal abstract class JsonConverter /// The to write to. /// The value. /// The calling serializer. - public abstract void WriteJson(JsonWriter writer, object value, JsonSerializer serializer); + public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer); /// /// Reads the JSON representation of the object. @@ -51,7 +53,7 @@ internal abstract class JsonConverter /// The existing value of object being read. /// The calling serializer. /// The object value. - public abstract object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer); + public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer); /// /// Determines whether this instance can convert the specified object type. @@ -87,13 +89,13 @@ internal abstract class JsonConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public sealed override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (!(value != null ? value is T : ReflectionUtils.IsNullable(typeof(T)))) { throw new JsonSerializationException("Converter cannot write specified value to JSON. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T))); } - WriteJson(writer, (T)value, serializer); + WriteJson(writer, (T?)value, serializer); } /// @@ -102,7 +104,7 @@ public sealed override void WriteJson(JsonWriter writer, object value, JsonSeria /// The to write to. /// The value. /// The calling serializer. - public abstract void WriteJson(JsonWriter writer, T value, JsonSerializer serializer); + public abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer); /// /// Reads the JSON representation of the object. @@ -112,14 +114,14 @@ public sealed override void WriteJson(JsonWriter writer, object value, JsonSeria /// The existing value of object being read. /// The calling serializer. /// The object value. - public sealed override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { bool existingIsNull = existingValue == null; if (!(existingIsNull || existingValue is T)) { throw new JsonSerializationException("Converter cannot read JSON with the specified existing value. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T))); } - return ReadJson(reader, objectType, existingIsNull ? default : (T)existingValue, !existingIsNull, serializer); + return ReadJson(reader, objectType, existingIsNull ? default : (T?)existingValue, !existingIsNull, serializer); } /// @@ -131,7 +133,7 @@ public sealed override object ReadJson(JsonReader reader, Type objectType, objec /// The existing value has a value. /// The calling serializer. /// The object value. - public abstract T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer); + public abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer); /// /// Determines whether this instance can convert the specified object type. @@ -145,4 +147,5 @@ public sealed override bool CanConvert(Type objectType) return typeof(T).IsAssignableFrom(objectType); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConverterAttribute.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConverterAttribute.cs index 8e705cc284..9530ffa741 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConverterAttribute.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConverterAttribute.cs @@ -29,6 +29,7 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// Instructs the to use the specified when serializing the member or class. /// @@ -47,7 +48,7 @@ internal sealed class JsonConverterAttribute : Attribute /// The parameter list to use when constructing the described by . /// If null, the default constructor is used. /// - public object[] ConverterParameters { get; } + public object[]? ConverterParameters { get; } /// /// Initializes a new instance of the class. @@ -74,4 +75,5 @@ public JsonConverterAttribute(Type converterType, params object[] converterParam ConverterParameters = converterParameters; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConverterCollection.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConverterCollection.cs index d18bb835e5..7815db6279 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConverterCollection.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonConverterCollection.cs @@ -36,4 +36,4 @@ namespace Microsoft.IdentityModel.Json internal class JsonConverterCollection : Collection { } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonDictionaryAttribute.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonDictionaryAttribute.cs index 0506804545..482815ae7a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonDictionaryAttribute.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonDictionaryAttribute.cs @@ -49,4 +49,4 @@ public JsonDictionaryAttribute(string id) { } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonException.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonException.cs index 99aea061e9..20f23dc9e7 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonException.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonException.cs @@ -32,6 +32,7 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// The exception thrown when an error occurs during JSON serialization or deserialization. /// @@ -63,7 +64,7 @@ public JsonException(string message) /// /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception, or null if no inner exception is specified. - public JsonException(string message, Exception innerException) + public JsonException(string message, Exception? innerException) : base(message, innerException) { } @@ -89,4 +90,5 @@ internal static JsonException Create(IJsonLineInfo lineInfo, string path, string return new JsonException(message); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonExtensionDataAttribute.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonExtensionDataAttribute.cs index a5cf6431ec..6b9fe37b20 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonExtensionDataAttribute.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonExtensionDataAttribute.cs @@ -34,4 +34,4 @@ public JsonExtensionDataAttribute() ReadData = true; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonIgnoreAttribute.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonIgnoreAttribute.cs index 69b8258e53..f64b35c209 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonIgnoreAttribute.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonIgnoreAttribute.cs @@ -36,4 +36,4 @@ namespace Microsoft.IdentityModel.Json internal sealed class JsonIgnoreAttribute : Attribute { } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonNameTable.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonNameTable.cs index d291237aaf..083e0b5083 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonNameTable.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonNameTable.cs @@ -1,16 +1,19 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// Base class for a table of atomized string objects. /// internal abstract class JsonNameTable { /// - /// Gets the string containing the same characters as the specified range of characters in the given array. + /// Gets a string containing the same characters as the specified range of characters in the given array. /// /// The character array containing the name to find. /// The zero-based index into the array specifying the first character of the name. /// The number of characters in the name. - public abstract string Get(char[] key, int start, int length); + /// A string containing the same characters as the specified range of characters in the given array. + public abstract string? Get(char[] key, int start, int length); } +#nullable disable } diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonObjectAttribute.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonObjectAttribute.cs index 09b2c6b42a..b0911e28f1 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonObjectAttribute.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonObjectAttribute.cs @@ -34,6 +34,7 @@ namespace Microsoft.IdentityModel.Json internal sealed class JsonObjectAttribute : JsonContainerAttribute { private MemberSerialization _memberSerialization = MemberSerialization.OptOut; + internal MissingMemberHandling? _missingMemberHandling; // yuck. can't set nullable properties on an attribute in C# // have to use this approach to get an unset default state @@ -50,6 +51,16 @@ public MemberSerialization MemberSerialization set => _memberSerialization = value; } + /// + /// Gets or sets the missing member handling used when deserializing this object. + /// + /// The missing member handling. + public MissingMemberHandling MissingMemberHandling + { + get => _missingMemberHandling ?? default; + set => _missingMemberHandling = value; + } + /// /// Gets or sets how the object's properties with null values are handled during serialization and deserialization. /// @@ -97,4 +108,4 @@ public JsonObjectAttribute(string id) { } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonPosition.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonPosition.cs index efa9e2bd44..69454760f5 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonPosition.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonPosition.cs @@ -32,6 +32,7 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable internal enum JsonContainerType { None = 0, @@ -46,7 +47,7 @@ internal struct JsonPosition internal JsonContainerType Type; internal int Position; - internal string PropertyName; + internal string? PropertyName; internal bool HasIndex; public JsonPosition(JsonContainerType type) @@ -62,7 +63,7 @@ internal int CalculateLength() switch (Type) { case JsonContainerType.Object: - return PropertyName.Length + 5; + return PropertyName!.Length + 5; case JsonContainerType.Array: case JsonContainerType.Constructor: return MathUtils.IntLength((ulong)Position) + 2; @@ -71,12 +72,12 @@ internal int CalculateLength() } } - internal void WriteTo(StringBuilder sb, ref StringWriter writer, ref char[] buffer) + internal void WriteTo(StringBuilder sb, ref StringWriter? writer, ref char[]? buffer) { switch (Type) { case JsonContainerType.Object: - string propertyName = PropertyName; + string propertyName = PropertyName!; if (propertyName.IndexOfAny(SpecialCharacters) != -1) { sb.Append(@"['"); @@ -130,8 +131,8 @@ internal static string BuildPath(List positions, JsonPosition? cur } StringBuilder sb = new StringBuilder(capacity); - StringWriter writer = null; - char[] buffer = null; + StringWriter? writer = null; + char[]? buffer = null; if (positions != null) { foreach (JsonPosition state in positions) @@ -147,7 +148,7 @@ internal static string BuildPath(List positions, JsonPosition? cur return sb.ToString(); } - internal static string FormatMessage(IJsonLineInfo lineInfo, string path, string message) + internal static string FormatMessage(IJsonLineInfo? lineInfo, string path, string message) { // don't add a fullstop and space when message ends with a new line if (!message.EndsWith(Environment.NewLine, StringComparison.Ordinal)) @@ -174,4 +175,5 @@ internal static string FormatMessage(IJsonLineInfo lineInfo, string path, string return message; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonPropertyAttribute.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonPropertyAttribute.cs index 6771badb22..837a5c0d1d 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonPropertyAttribute.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonPropertyAttribute.cs @@ -28,6 +28,7 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// Instructs the to always serialize the member with the specified name. /// @@ -52,7 +53,7 @@ internal sealed class JsonPropertyAttribute : Attribute /// Gets or sets the type used when serializing the property's collection items. /// /// The collection's items type. - public Type ItemConverterType { get; set; } + public Type? ItemConverterType { get; set; } /// /// The parameter list to use when constructing the described by . @@ -65,13 +66,13 @@ internal sealed class JsonPropertyAttribute : Attribute /// [JsonProperty(ItemConverterType = typeof(MyContainerConverter), ItemConverterParameters = new object[] { 123, "Four" })] /// /// - public object[] ItemConverterParameters { get; set; } + public object[]? ItemConverterParameters { get; set; } /// /// Gets or sets the of the . /// /// The of the . - public Type NamingStrategyType { get; set; } + public Type? NamingStrategyType { get; set; } /// /// The parameter list to use when constructing the described by . @@ -84,7 +85,7 @@ internal sealed class JsonPropertyAttribute : Attribute /// [JsonProperty(NamingStrategyType = typeof(MyNamingStrategy), NamingStrategyParameters = new object[] { 123, "Four" })] /// /// - public object[] NamingStrategyParameters { get; set; } + public object[]? NamingStrategyParameters { get; set; } /// /// Gets or sets the null value handling used when serializing this property. @@ -172,7 +173,7 @@ public Required Required /// Gets or sets the name of the property. /// /// The name of the property. - public string PropertyName { get; set; } + public string? PropertyName { get; set; } /// /// Gets or sets the reference loop handling used when serializing the property's collection items. @@ -220,4 +221,5 @@ public JsonPropertyAttribute(string propertyName) PropertyName = propertyName; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonReader.Async.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonReader.Async.cs index c6c29c42ab..8e7780e379 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonReader.Async.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonReader.Async.cs @@ -33,8 +33,27 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable internal abstract partial class JsonReader +#if HAVE_ASYNC_DISPOABLE + : IAsyncDisposable +#endif { +#if HAVE_ASYNC_DISPOABLE + ValueTask IAsyncDisposable.DisposeAsync() + { + try + { + Dispose(true); + return default; + } + catch (Exception exc) + { + return ValueTask.FromException(exc); + } + } +#endif + /// /// Asynchronously reads the next JSON token from the source. /// @@ -101,12 +120,12 @@ internal async Task ReaderReadAndAssertAsync(CancellationToken cancellationToken /// property returns the []. This result will be null at the end of an array. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task ReadAsBytesAsync(CancellationToken cancellationToken = default) + public virtual Task ReadAsBytesAsync(CancellationToken cancellationToken = default) { - return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsBytes()); + return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsBytes()); } - internal async Task ReadArrayIntoByteArrayAsync(CancellationToken cancellationToken) + internal async Task ReadArrayIntoByteArrayAsync(CancellationToken cancellationToken) { List buffer = new List(); @@ -199,9 +218,9 @@ internal async Task ReadArrayIntoByteArrayAsync(CancellationToken cancel /// property returns the . This result will be null at the end of an array. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task ReadAsStringAsync(CancellationToken cancellationToken = default) + public virtual Task ReadAsStringAsync(CancellationToken cancellationToken = default) { - return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsString()); + return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsString()); } internal async Task ReadAndMoveToContentAsync(CancellationToken cancellationToken) @@ -241,6 +260,7 @@ private async Task MoveToContentFromNonContentAsync(CancellationToken canc } } } +#nullable disable } #endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonReader.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonReader.cs index 68a31cbd9a..7ea341c3cb 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonReader.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonReader.cs @@ -35,6 +35,7 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// Represents a reader that provides fast, non-cached, forward-only access to serialized JSON data. /// @@ -113,18 +114,18 @@ protected internal enum State // current Token data private JsonToken _tokenType; - private object _value; + private object? _value; internal char _quoteChar; internal State _currentState; private JsonPosition _currentPosition; - private CultureInfo _culture; + private CultureInfo? _culture; private DateTimeZoneHandling _dateTimeZoneHandling; private int? _maxDepth; private bool _hasExceededMaxDepth; internal DateParseHandling _dateParseHandling; internal FloatParseHandling _floatParseHandling; - private string _dateFormatString; - private List _stack; + private string? _dateFormatString; + private List? _stack; /// /// Gets the current reader state. @@ -219,7 +220,7 @@ public FloatParseHandling FloatParseHandling /// /// Gets or sets how custom date formatted strings are parsed when reading JSON. /// - public string DateFormatString + public string? DateFormatString { get => _dateFormatString; set => _dateFormatString = value; @@ -227,6 +228,8 @@ public string DateFormatString /// /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a . + /// A null value means there is no maximum. + /// The default value is 64. /// public int? MaxDepth { @@ -243,19 +246,19 @@ public int? MaxDepth } /// - /// Gets the type of the current JSON token. + /// Gets the type of the current JSON token. /// public virtual JsonToken TokenType => _tokenType; /// /// Gets the text value of the current JSON token. /// - public virtual object Value => _value; + public virtual object? Value => _value; /// /// Gets the .NET type for the current JSON token. /// - public virtual Type ValueType => _value?.GetType(); + public virtual Type? ValueType => _value?.GetType(); /// /// Gets the depth of the current token in the JSON document. @@ -278,7 +281,7 @@ public virtual int Depth } /// - /// Gets the path of the current JSON token. + /// Gets the path of the current JSON token. /// public virtual string Path { @@ -295,7 +298,7 @@ public virtual string Path JsonPosition? current = insideContainer ? (JsonPosition?)_currentPosition : null; - return JsonPosition.BuildPath(_stack, current); + return JsonPosition.BuildPath(_stack!, current); } } @@ -327,6 +330,7 @@ protected JsonReader() _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; _dateParseHandling = DateParseHandling.DateTime; _floatParseHandling = FloatParseHandling.Double; + _maxDepth = 64; CloseInput = true; } @@ -408,7 +412,7 @@ private JsonContainerType Peek() return null; case JsonToken.Integer: case JsonToken.Float: - object v = Value; + object v = Value!; if (v is int i) { return i; @@ -436,16 +440,16 @@ private JsonContainerType Peek() SetToken(JsonToken.Integer, i, false); return i; case JsonToken.String: - string s = (string)Value; + string? s = (string?)Value; return ReadInt32String(s); } throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } - internal int? ReadInt32String(string s) + internal int? ReadInt32String(string? s) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, false); return null; @@ -467,7 +471,7 @@ private JsonContainerType Peek() /// Reads the next JSON token from the source as a . /// /// A . This method will return null at the end of an array. - public virtual string ReadAsString() + public virtual string? ReadAsString() { JsonToken t = GetContentToken(); @@ -478,12 +482,12 @@ public virtual string ReadAsString() case JsonToken.EndArray: return null; case JsonToken.String: - return (string)Value; + return (string?)Value; } if (JsonTokenUtils.IsPrimitiveToken(t)) { - object v = Value; + object? v = Value; if (v != null) { string s; @@ -493,7 +497,7 @@ public virtual string ReadAsString() } else { - s = v is Uri uri ? uri.OriginalString : v.ToString(); + s = v is Uri uri ? uri.OriginalString : v.ToString()!; } SetToken(JsonToken.String, s, false); @@ -508,7 +512,7 @@ public virtual string ReadAsString() /// Reads the next JSON token from the source as a []. /// /// A [] or null if the next JSON token is null. This method will return null at the end of an array. - public virtual byte[] ReadAsBytes() + public virtual byte[]? ReadAsBytes() { JsonToken t = GetContentToken(); @@ -518,7 +522,7 @@ public virtual byte[] ReadAsBytes() { ReadIntoWrappedTypeObject(); - byte[] data = ReadAsBytes(); + byte[]? data = ReadAsBytes(); ReaderReadAndAssert(); if (TokenType != JsonToken.EndObject) @@ -533,7 +537,7 @@ public virtual byte[] ReadAsBytes() { // attempt to convert possible base 64 or GUID string to bytes // GUID has to have format 00000000-0000-0000-0000-000000000000 - string s = (string)Value; + string s = (string)Value!; byte[] data; @@ -565,7 +569,7 @@ public virtual byte[] ReadAsBytes() return data; } - return (byte[])Value; + return (byte[]?)Value; case JsonToken.StartArray: return ReadArrayIntoByteArray(); } @@ -627,7 +631,7 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) return null; case JsonToken.Integer: case JsonToken.Float: - object v = Value; + object v = Value!; if (v is double d) { return d; @@ -648,15 +652,15 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) return (double)d; case JsonToken.String: - return ReadDoubleString((string)Value); + return ReadDoubleString((string?)Value); } throw JsonReaderException.Create(this, "Error reading double. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } - internal double? ReadDoubleString(string s) + internal double? ReadDoubleString(string? s) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, false); return null; @@ -705,17 +709,17 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) SetToken(JsonToken.Boolean, b, false); return b; case JsonToken.String: - return ReadBooleanString((string)Value); + return ReadBooleanString((string?)Value); case JsonToken.Boolean: - return (bool)Value; + return (bool)Value!; } throw JsonReaderException.Create(this, "Error reading boolean. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } - internal bool? ReadBooleanString(string s) + internal bool? ReadBooleanString(string? s) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, false); return null; @@ -749,8 +753,8 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) return null; case JsonToken.Integer: case JsonToken.Float: - object v = Value; - + object v = Value!; + if (v is decimal d) { return d; @@ -778,15 +782,15 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) SetToken(JsonToken.Float, d, false); return d; case JsonToken.String: - return ReadDecimalString((string)Value); + return ReadDecimalString((string?)Value); } throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } - internal decimal? ReadDecimalString(string s) + internal decimal? ReadDecimalString(string? s) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, false); return null; @@ -830,18 +834,17 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) } #endif - return (DateTime)Value; + return (DateTime)Value!; case JsonToken.String: - string s = (string)Value; - return ReadDateTimeString(s); + return ReadDateTimeString((string?)Value); } throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } - internal DateTime? ReadDateTimeString(string s) + internal DateTime? ReadDateTimeString(string? s) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, false); return null; @@ -885,18 +888,18 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) SetToken(JsonToken.Date, new DateTimeOffset(time), false); } - return (DateTimeOffset)Value; + return (DateTimeOffset)Value!; case JsonToken.String: - string s = (string)Value; + string? s = (string?)Value; return ReadDateTimeOffsetString(s); default: throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } } - internal DateTimeOffset? ReadDateTimeOffsetString(string s) + internal DateTimeOffset? ReadDateTimeOffsetString(string? s) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, false); return null; @@ -938,7 +941,7 @@ internal void ReadIntoWrappedTypeObject() if (Value != null && Value.ToString() == JsonTypeReflector.TypePropertyName) { ReaderReadAndAssert(); - if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal)) + if (Value != null && Value.ToString()!.StartsWith("System.Byte[]", StringComparison.Ordinal)) { ReaderReadAndAssert(); if (Value.ToString() == JsonTypeReflector.ValuePropertyName) @@ -985,7 +988,7 @@ protected void SetToken(JsonToken newToken) /// /// The new token. /// The value. - protected void SetToken(JsonToken newToken, object value) + protected void SetToken(JsonToken newToken, object? value) { SetToken(newToken, value, true); } @@ -996,7 +999,7 @@ protected void SetToken(JsonToken newToken, object value) /// The new token. /// The value. /// A flag indicating whether the position index inside an array should be updated. - protected void SetToken(JsonToken newToken, object value, bool updateIndex) + protected void SetToken(JsonToken newToken, object? value, bool updateIndex) { _tokenType = newToken; _value = value; @@ -1027,7 +1030,7 @@ protected void SetToken(JsonToken newToken, object value, bool updateIndex) case JsonToken.PropertyName: _currentState = State.Property; - _currentPosition.PropertyName = (string)value; + _currentPosition.PropertyName = (string)value!; break; case JsonToken.Undefined: case JsonToken.Integer: @@ -1133,7 +1136,9 @@ private JsonContainerType GetTypeForCloseToken(JsonToken token) } } +#pragma warning disable CA1063 // Implement IDisposable Correctly void IDisposable.Dispose() +#pragma warning restore CA1063 // Implement IDisposable Correctly { Dispose(true); GC.SuppressFinalize(this); @@ -1170,7 +1175,7 @@ internal void ReadAndAssert() } } - internal void ReadForTypeAndAssert(JsonContract contract, bool hasConverter) + internal void ReadForTypeAndAssert(JsonContract? contract, bool hasConverter) { if (!ReadForType(contract, hasConverter)) { @@ -1178,7 +1183,7 @@ internal void ReadForTypeAndAssert(JsonContract contract, bool hasConverter) } } - internal bool ReadForType(JsonContract contract, bool hasConverter) + internal bool ReadForType(JsonContract? contract, bool hasConverter) { // don't read properties with converters as a specific value // the value might be a string which will then get converted which will error if read as date for example @@ -1273,4 +1278,5 @@ private JsonToken GetContentToken() return t; } } +#nullable disable } diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonReaderException.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonReaderException.cs index 7cc8b9785e..a48fbf1ed8 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonReaderException.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonReaderException.cs @@ -30,6 +30,7 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// The exception thrown when an error occurs while reading JSON text. /// @@ -54,7 +55,7 @@ internal class JsonReaderException : JsonException /// Gets the path to the JSON where the error occurred. /// /// The path to the JSON where the error occurred. - public string Path { get; } + public string? Path { get; } /// /// Initializes a new instance of the class. @@ -107,7 +108,7 @@ public JsonReaderException(SerializationInfo info, StreamingContext context) /// The line number indicating where the error occurred. /// The line position indicating where the error occurred. /// The exception that is the cause of the current exception, or null if no inner exception is specified. - public JsonReaderException(string message, string path, int lineNumber, int linePosition, Exception innerException) + public JsonReaderException(string message, string path, int lineNumber, int linePosition, Exception? innerException) : base(message, innerException) { Path = path; @@ -120,12 +121,12 @@ internal static JsonReaderException Create(JsonReader reader, string message) return Create(reader, message, null); } - internal static JsonReaderException Create(JsonReader reader, string message, Exception ex) + internal static JsonReaderException Create(JsonReader reader, string message, Exception? ex) { return Create(reader as IJsonLineInfo, reader.Path, message, ex); } - internal static JsonReaderException Create(IJsonLineInfo lineInfo, string path, string message, Exception ex) + internal static JsonReaderException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex) { message = JsonPosition.FormatMessage(lineInfo, path, message); @@ -145,4 +146,5 @@ internal static JsonReaderException Create(IJsonLineInfo lineInfo, string path, return new JsonReaderException(message, path, lineNumber, linePosition, ex); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonRequiredAttribute.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonRequiredAttribute.cs index 07d97acb11..e78a57e372 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonRequiredAttribute.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonRequiredAttribute.cs @@ -36,4 +36,4 @@ namespace Microsoft.IdentityModel.Json internal sealed class JsonRequiredAttribute : Attribute { } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonSerializationException.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonSerializationException.cs index 36dab27f22..ba6645be20 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonSerializationException.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonSerializationException.cs @@ -30,6 +30,7 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// The exception thrown when an error occurs during JSON serialization or deserialization. /// @@ -54,7 +55,7 @@ internal class JsonSerializationException : JsonException /// Gets the path to the JSON where the error occurred. /// /// The path to the JSON where the error occurred. - public string Path { get; } + public string? Path { get; } /// /// Initializes a new instance of the class. @@ -107,7 +108,7 @@ public JsonSerializationException(SerializationInfo info, StreamingContext conte /// The line number indicating where the error occurred. /// The line position indicating where the error occurred. /// The exception that is the cause of the current exception, or null if no inner exception is specified. - public JsonSerializationException(string message, string path, int lineNumber, int linePosition, Exception innerException) + public JsonSerializationException(string message, string path, int lineNumber, int linePosition, Exception? innerException) : base(message, innerException) { Path = path; @@ -120,12 +121,12 @@ internal static JsonSerializationException Create(JsonReader reader, string mess return Create(reader, message, null); } - internal static JsonSerializationException Create(JsonReader reader, string message, Exception ex) + internal static JsonSerializationException Create(JsonReader reader, string message, Exception? ex) { return Create(reader as IJsonLineInfo, reader.Path, message, ex); } - internal static JsonSerializationException Create(IJsonLineInfo lineInfo, string path, string message, Exception ex) + internal static JsonSerializationException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex) { message = JsonPosition.FormatMessage(lineInfo, path, message); @@ -145,4 +146,5 @@ internal static JsonSerializationException Create(IJsonLineInfo lineInfo, string return new JsonSerializationException(message, path, lineNumber, linePosition, ex); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonSerializer.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonSerializer.cs index 0767b97824..b15f47c954 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonSerializer.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonSerializer.cs @@ -35,9 +35,12 @@ using Microsoft.IdentityModel.Json.Utilities; using System.Runtime.Serialization; using ErrorEventArgs = Microsoft.IdentityModel.Json.Serialization.ErrorEventArgs; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// Serializes and deserializes objects into and from the JSON format. /// The enables you to control how objects are encoded into JSON. @@ -54,13 +57,13 @@ internal class JsonSerializer internal DefaultValueHandling _defaultValueHandling; internal ConstructorHandling _constructorHandling; internal MetadataPropertyHandling _metadataPropertyHandling; - internal JsonConverterCollection _converters; + internal JsonConverterCollection? _converters; internal IContractResolver _contractResolver; - internal ITraceWriter _traceWriter; - internal IEqualityComparer _equalityComparer; + internal ITraceWriter? _traceWriter; + internal IEqualityComparer? _equalityComparer; internal ISerializationBinder _serializationBinder; internal StreamingContext _context; - private IReferenceResolver _referenceResolver; + private IReferenceResolver? _referenceResolver; private Formatting? _formatting; private DateFormatHandling? _dateFormatHandling; @@ -73,18 +76,18 @@ internal class JsonSerializer private int? _maxDepth; private bool _maxDepthSet; private bool? _checkAdditionalContent; - private string _dateFormatString; + private string? _dateFormatString; private bool _dateFormatStringSet; /// /// Occurs when the errors during serialization and deserialization. /// - public virtual event EventHandler Error; + public virtual event EventHandler? Error; /// /// Gets or sets the used by the serializer when resolving references. /// - public virtual IReferenceResolver ReferenceResolver + public virtual IReferenceResolver? ReferenceResolver { get => GetReferenceResolver(); set @@ -98,41 +101,36 @@ public virtual IReferenceResolver ReferenceResolver } } - ///// - ///// Gets or sets the used by the serializer when resolving type names. - ///// - //[Obsolete("Binder is obsolete. Use SerializationBinder instead.")] - //public virtual SerializationBinder Binder - //{ - // get - // { - // if (_serializationBinder == null) - // { - // return null; - // } - - // if (_serializationBinder is SerializationBinder legacySerializationBinder) - // { - // return legacySerializationBinder; - // } - - // if (_serializationBinder is SerializationBinderAdapter adapter) - // { - // return adapter.SerializationBinder; - // } - - // throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set."); - // } - // set - // { - // if (value == null) - // { - // throw new ArgumentNullException(nameof(value), "Serialization binder cannot be null."); - // } - - // _serializationBinder = value as ISerializationBinder ?? new SerializationBinderAdapter(value); - // } - //} + /// + /// Gets or sets the used by the serializer when resolving type names. + /// + [Obsolete("Binder is obsolete. Use SerializationBinder instead.")] + public virtual SerializationBinder Binder + { + get + { + if (_serializationBinder is SerializationBinder legacySerializationBinder) + { + return legacySerializationBinder; + } + + if (_serializationBinder is SerializationBinderAdapter adapter) + { + return adapter.SerializationBinder; + } + + throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set."); + } + set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value), "Serialization binder cannot be null."); + } + + _serializationBinder = value as ISerializationBinder ?? new SerializationBinderAdapter(value); + } + } /// /// Gets or sets the used by the serializer when resolving type names. @@ -155,7 +153,7 @@ public virtual ISerializationBinder SerializationBinder /// Gets or sets the used by the serializer when writing trace messages. /// /// The trace writer. - public virtual ITraceWriter TraceWriter + public virtual ITraceWriter? TraceWriter { get => _traceWriter; set => _traceWriter = value; @@ -165,7 +163,7 @@ public virtual ITraceWriter TraceWriter /// Gets or sets the equality comparer used by the serializer when comparing references. /// /// The equality comparer. - public virtual IEqualityComparer EqualityComparer + public virtual IEqualityComparer? EqualityComparer { get => _equalityComparer; set => _equalityComparer = value; @@ -517,7 +515,7 @@ public virtual CultureInfo Culture /// /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a . /// A null value means there is no maximum. - /// The default value is null. + /// The default value is 64. /// public virtual int? MaxDepth { @@ -575,12 +573,12 @@ public JsonSerializer() /// /// Creates a new instance. - /// The will not use default settings + /// The will not use default settings /// from . /// /// /// A new instance. - /// The will not use default settings + /// The will not use default settings /// from . /// public static JsonSerializer Create() @@ -590,16 +588,16 @@ public static JsonSerializer Create() /// /// Creates a new instance using the specified . - /// The will not use default settings + /// The will not use default settings /// from . /// /// The settings to be applied to the . /// /// A new instance using the specified . - /// The will not use default settings + /// The will not use default settings /// from . /// - public static JsonSerializer Create(JsonSerializerSettings settings) + public static JsonSerializer Create(JsonSerializerSettings? settings) { JsonSerializer serializer = Create(); @@ -613,34 +611,34 @@ public static JsonSerializer Create(JsonSerializerSettings settings) /// /// Creates a new instance. - /// The will use default settings + /// The will use default settings /// from . /// /// /// A new instance. - /// The will use default settings + /// The will use default settings /// from . /// public static JsonSerializer CreateDefault() { // copy static to local variable to avoid concurrency issues - JsonSerializerSettings defaultSettings = JsonConvert.DefaultSettings?.Invoke(); + JsonSerializerSettings? defaultSettings = JsonConvert.DefaultSettings?.Invoke(); return Create(defaultSettings); } /// /// Creates a new instance using the specified . - /// The will use default settings + /// The will use default settings /// from as well as the specified . /// /// The settings to be applied to the . /// /// A new instance using the specified . - /// The will use default settings + /// The will use default settings /// from as well as the specified . /// - public static JsonSerializer CreateDefault(JsonSerializerSettings settings) + public static JsonSerializer CreateDefault(JsonSerializerSettings? settings) { JsonSerializer serializer = CreateDefault(); if (settings != null) @@ -814,14 +812,14 @@ internal virtual void PopulateInternal(JsonReader reader, object target) SetupReader( reader, - out CultureInfo previousCulture, + out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, - out string previousDateFormatString); + out string? previousDateFormatString); - TraceJsonReader traceJsonReader = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) + TraceJsonReader? traceJsonReader = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null; @@ -830,7 +828,7 @@ internal virtual void PopulateInternal(JsonReader reader, object target) if (traceJsonReader != null) { - TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null); + TraceWriter!.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null); } ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString); @@ -842,20 +840,20 @@ internal virtual void PopulateInternal(JsonReader reader, object target) /// The that contains the JSON structure to deserialize. /// The being deserialized. [DebuggerStepThrough] - public object Deserialize(JsonReader reader) + public object? Deserialize(JsonReader reader) { return Deserialize(reader, null); } /// - /// Deserializes the JSON structure contained by the specified + /// Deserializes the JSON structure contained by the specified /// into an instance of the specified type. /// /// The containing the object. /// The of object being deserialized. /// The instance of being deserialized. [DebuggerStepThrough] - public object Deserialize(TextReader reader, Type objectType) + public object? Deserialize(TextReader reader, Type objectType) { return Deserialize(new JsonTextReader(reader), objectType); } @@ -868,9 +866,9 @@ public object Deserialize(TextReader reader, Type objectType) /// The type of the object to deserialize. /// The instance of being deserialized. [DebuggerStepThrough] - public T Deserialize(JsonReader reader) + public T? Deserialize(JsonReader reader) { - return (T)Deserialize(reader, typeof(T)); + return (T?)Deserialize(reader, typeof(T)); } /// @@ -881,34 +879,34 @@ public T Deserialize(JsonReader reader) /// The of object being deserialized. /// The instance of being deserialized. [DebuggerStepThrough] - public object Deserialize(JsonReader reader, Type objectType) + public object? Deserialize(JsonReader reader, Type? objectType) { return DeserializeInternal(reader, objectType); } - internal virtual object DeserializeInternal(JsonReader reader, Type objectType) + internal virtual object? DeserializeInternal(JsonReader reader, Type? objectType) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); SetupReader( reader, - out CultureInfo previousCulture, + out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, - out string previousDateFormatString); + out string? previousDateFormatString); - TraceJsonReader traceJsonReader = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) + TraceJsonReader? traceJsonReader = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null; JsonSerializerInternalReader serializerReader = new JsonSerializerInternalReader(this); - object value = serializerReader.Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent); + object? value = serializerReader.Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent); if (traceJsonReader != null) { - TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null); + TraceWriter!.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null); } ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString); @@ -916,7 +914,7 @@ internal virtual object DeserializeInternal(JsonReader reader, Type objectType) return value; } - private void SetupReader(JsonReader reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString) + internal void SetupReader(JsonReader reader, out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string? previousDateFormatString) { if (_culture != null && !_culture.Equals(reader.Culture)) { @@ -987,7 +985,7 @@ private void SetupReader(JsonReader reader, out CultureInfo previousCulture, out } } - private void ResetReader(JsonReader reader, CultureInfo previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string previousDateFormatString) + private void ResetReader(JsonReader reader, CultureInfo? previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string? previousDateFormatString) { // reset reader back to previous options if (previousCulture != null) @@ -1028,7 +1026,7 @@ private void ResetReader(JsonReader reader, CultureInfo previousCulture, DateTim /// /// The used to write the JSON structure. /// The to serialize. - public void Serialize(TextWriter textWriter, object value) + public void Serialize(TextWriter textWriter, object? value) { Serialize(new JsonTextWriter(textWriter), value); } @@ -1044,7 +1042,7 @@ public void Serialize(TextWriter textWriter, object value) /// This parameter is used when is to write out the type name if the type of the value does not match. /// Specifying the type is optional. /// - public void Serialize(JsonWriter jsonWriter, object value, Type objectType) + public void Serialize(JsonWriter jsonWriter, object? value, Type? objectType) { SerializeInternal(jsonWriter, value, objectType); } @@ -1060,7 +1058,7 @@ public void Serialize(JsonWriter jsonWriter, object value, Type objectType) /// This parameter is used when is Auto to write out the type name if the type of the value does not match. /// Specifying the type is optional. /// - public void Serialize(TextWriter textWriter, object value, Type objectType) + public void Serialize(TextWriter textWriter, object? value, Type objectType) { Serialize(new JsonTextWriter(textWriter), value, objectType); } @@ -1071,7 +1069,7 @@ public void Serialize(TextWriter textWriter, object value, Type objectType) /// /// The used to write the JSON structure. /// The to serialize. - public void Serialize(JsonWriter jsonWriter, object value) + public void Serialize(JsonWriter jsonWriter, object? value) { SerializeInternal(jsonWriter, value, null); } @@ -1087,7 +1085,7 @@ private TraceJsonReader CreateTraceJsonReader(JsonReader reader) return traceReader; } - internal virtual void SerializeInternal(JsonWriter jsonWriter, object value, Type objectType) + internal virtual void SerializeInternal(JsonWriter jsonWriter, object? value, Type? objectType) { ValidationUtils.ArgumentNotNull(jsonWriter, nameof(jsonWriter)); @@ -1127,21 +1125,21 @@ internal virtual void SerializeInternal(JsonWriter jsonWriter, object value, Typ jsonWriter.StringEscapeHandling = _stringEscapeHandling.GetValueOrDefault(); } - CultureInfo previousCulture = null; + CultureInfo? previousCulture = null; if (_culture != null && !_culture.Equals(jsonWriter.Culture)) { previousCulture = jsonWriter.Culture; jsonWriter.Culture = _culture; } - string previousDateFormatString = null; + string? previousDateFormatString = null; if (_dateFormatStringSet && jsonWriter.DateFormatString != _dateFormatString) { previousDateFormatString = jsonWriter.DateFormatString; jsonWriter.DateFormatString = _dateFormatString; } - TraceJsonWriter traceJsonWriter = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) + TraceJsonWriter? traceJsonWriter = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? new TraceJsonWriter(jsonWriter) : null; @@ -1150,7 +1148,7 @@ internal virtual void SerializeInternal(JsonWriter jsonWriter, object value, Typ if (traceJsonWriter != null) { - TraceWriter.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null); + TraceWriter!.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null); } // reset writer back to previous options @@ -1194,12 +1192,12 @@ internal IReferenceResolver GetReferenceResolver() return _referenceResolver; } - internal JsonConverter GetMatchingConverter(Type type) + internal JsonConverter? GetMatchingConverter(Type type) { return GetMatchingConverter(_converters, type); } - internal static JsonConverter GetMatchingConverter(IList converters, Type objectType) + internal static JsonConverter? GetMatchingConverter(IList? converters, Type objectType) { #if DEBUG ValidationUtils.ArgumentNotNull(objectType, nameof(objectType)); @@ -1226,4 +1224,5 @@ internal void OnError(ErrorEventArgs e) Error?.Invoke(this, e); } } +#nullable disable } diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonSerializerSettings.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonSerializerSettings.cs index b8907cc390..8486499e64 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonSerializerSettings.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonSerializerSettings.cs @@ -31,9 +31,16 @@ using Microsoft.IdentityModel.Json.Serialization; using System.Runtime.Serialization; using System.Diagnostics; +using System.Runtime; +#if !HAVE_LINQ +using Microsoft.IdentityModel.Json.Utilities.LinqBridge; +#else +using System.Linq; +#endif namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// Specifies the settings on a object. /// @@ -61,6 +68,7 @@ internal class JsonSerializerSettings internal static readonly CultureInfo DefaultCulture; internal const bool DefaultCheckAdditionalContent = false; internal const string DefaultDateFormatString = @"yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; + internal const int DefaultMaxDepth = 64; internal Formatting? _formatting; internal DateFormatHandling? _dateFormatHandling; @@ -69,11 +77,11 @@ internal class JsonSerializerSettings internal FloatFormatHandling? _floatFormatHandling; internal FloatParseHandling? _floatParseHandling; internal StringEscapeHandling? _stringEscapeHandling; - internal CultureInfo _culture; + internal CultureInfo? _culture; internal bool? _checkAdditionalContent; internal int? _maxDepth; internal bool _maxDepthSet; - internal string _dateFormatString; + internal string? _dateFormatString; internal bool _dateFormatStringSet; internal TypeNameAssemblyFormatHandling? _typeNameAssemblyFormatHandling; internal DefaultValueHandling? _defaultValueHandling; @@ -225,27 +233,27 @@ public ConstructorHandling ConstructorHandling /// serializing .NET objects to JSON and vice versa. /// /// The contract resolver. - public IContractResolver ContractResolver { get; set; } + public IContractResolver? ContractResolver { get; set; } /// /// Gets or sets the equality comparer used by the serializer when comparing references. /// /// The equality comparer. - public IEqualityComparer EqualityComparer { get; set; } + public IEqualityComparer? EqualityComparer { get; set; } /// /// Gets or sets the used by the serializer when resolving references. /// /// The reference resolver. [Obsolete("ReferenceResolver property is obsolete. Use the ReferenceResolverProvider property to set the IReferenceResolver: settings.ReferenceResolverProvider = () => resolver")] - public IReferenceResolver ReferenceResolver + public IReferenceResolver? ReferenceResolver { get => ReferenceResolverProvider?.Invoke(); set { ReferenceResolverProvider = (value != null) ? () => value - : (Func)null; + : (Func?)null; } } @@ -253,49 +261,49 @@ public IReferenceResolver ReferenceResolver /// Gets or sets a function that creates the used by the serializer when resolving references. /// /// A function that creates the used by the serializer when resolving references. - public Func ReferenceResolverProvider { get; set; } + public Func? ReferenceResolverProvider { get; set; } /// /// Gets or sets the used by the serializer when writing trace messages. /// /// The trace writer. - public ITraceWriter TraceWriter { get; set; } - - ///// - ///// Gets or sets the used by the serializer when resolving type names. - ///// - ///// The binder. - //[Obsolete("Binder is obsolete. Use SerializationBinder instead.")] - //public SerializationBinder Binder - //{ - // get - // { - // if (SerializationBinder == null) - // { - // return null; - // } - - // if (SerializationBinder is SerializationBinderAdapter adapter) - // { - // return adapter.SerializationBinder; - // } - - // throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set."); - // } - // set => SerializationBinder = value == null ? null : new SerializationBinderAdapter(value); - //} + public ITraceWriter? TraceWriter { get; set; } + + /// + /// Gets or sets the used by the serializer when resolving type names. + /// + /// The binder. + [Obsolete("Binder is obsolete. Use SerializationBinder instead.")] + public SerializationBinder? Binder + { + get + { + if (SerializationBinder == null) + { + return null; + } + + if (SerializationBinder is SerializationBinderAdapter adapter) + { + return adapter.SerializationBinder; + } + + throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set."); + } + set => SerializationBinder = value == null ? null : new SerializationBinderAdapter(value); + } /// /// Gets or sets the used by the serializer when resolving type names. /// /// The binder. - public ISerializationBinder SerializationBinder { get; set; } + public ISerializationBinder? SerializationBinder { get; set; } /// /// Gets or sets the error handler called during serialization and deserialization. /// /// The error handler called during serialization and deserialization. - public EventHandler Error { get; set; } + public EventHandler? Error { get; set; } /// /// Gets or sets the used by the serializer when invoking serialization callback methods. @@ -325,11 +333,11 @@ public string DateFormatString /// /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a . /// A null value means there is no maximum. - /// The default value is null. + /// The default value is 64. /// public int? MaxDepth { - get => _maxDepth; + get => _maxDepthSet ? _maxDepth : DefaultMaxDepth; set { if (value <= 0) @@ -451,5 +459,45 @@ public JsonSerializerSettings() { Converters = new List(); } + + /// + /// Initializes a new instance of the class + /// using values copied from the passed in . + /// + public JsonSerializerSettings(JsonSerializerSettings original) + { + _floatParseHandling = original._floatParseHandling; + _floatFormatHandling = original._floatFormatHandling; + _dateParseHandling = original._dateParseHandling; + _dateTimeZoneHandling = original._dateTimeZoneHandling; + _dateFormatHandling = original._dateFormatHandling; + _formatting = original._formatting; + _maxDepth = original._maxDepth; + _maxDepthSet = original._maxDepthSet; + _dateFormatString = original._dateFormatString; + _dateFormatStringSet = original._dateFormatStringSet; + _context = original._context; + Error = original.Error; + SerializationBinder = original.SerializationBinder; + TraceWriter = original.TraceWriter; + _culture = original._culture; + ReferenceResolverProvider = original.ReferenceResolverProvider; + EqualityComparer = original.EqualityComparer; + ContractResolver = original.ContractResolver; + _constructorHandling = original._constructorHandling; + _typeNameAssemblyFormatHandling = original._typeNameAssemblyFormatHandling; + _metadataPropertyHandling = original._metadataPropertyHandling; + _typeNameHandling = original._typeNameHandling; + _preserveReferencesHandling = original._preserveReferencesHandling; + Converters = original.Converters.ToList(); + _defaultValueHandling = original._defaultValueHandling; + _nullValueHandling = original._nullValueHandling; + _objectCreationHandling = original._objectCreationHandling; + _missingMemberHandling = original._missingMemberHandling; + _referenceLoopHandling = original._referenceLoopHandling; + _checkAdditionalContent = original._checkAdditionalContent; + _stringEscapeHandling = original._stringEscapeHandling; + } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextReader.Async.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextReader.Async.cs index 88915c4bd9..7fd16d2fcc 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextReader.Async.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextReader.Async.cs @@ -34,9 +34,11 @@ using System.Threading.Tasks; using Microsoft.IdentityModel.Json.Serialization; using Microsoft.IdentityModel.Json.Utilities; +using System.Diagnostics; namespace Microsoft.IdentityModel.Json { +#nullable enable internal partial class JsonTextReader { // It's not safe to perform the async methods here in a derived class as if the synchronous equivalent @@ -78,7 +80,7 @@ internal Task DoReadAsync(CancellationToken cancellationToken) return ParseObjectAsync(cancellationToken); case State.PostValue: Task task = ParsePostValueAsync(false, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { if (task.Result) { @@ -110,6 +112,8 @@ private async Task DoReadAsync(Task task, CancellationToken cancella private async Task ParsePostValueAsync(bool ignoreComments, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -193,6 +197,8 @@ private async Task ParsePostValueAsync(bool ignoreComments, CancellationTo private async Task ReadFromFinishedAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + if (await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false)) { await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false); @@ -222,6 +228,8 @@ private Task ReadDataAsync(bool append, CancellationToken cancellationToken private async Task ReadDataAsync(bool append, int charsRequired, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + if (_isEndOfFile) { return 0; @@ -244,6 +252,8 @@ private async Task ReadDataAsync(bool append, int charsRequired, Cancellati private async Task ParseValueAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -373,6 +383,8 @@ private async Task ParseValueAsync(CancellationToken cancellationToken) private async Task ReadStringIntoBufferAsync(char quote, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + int charPos = _charPos; int initialPosition = _charPos; int lastWritePosition = _charPos; @@ -531,7 +543,7 @@ private Task ProcessCarriageReturnAsync(bool append, CancellationToken cancellat _charPos++; Task task = EnsureCharsAsync(1, append, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { SetNewLine(task.Result); return AsyncUtils.CompletedTask; @@ -589,6 +601,8 @@ private async Task ReadCharsAsync(int relativePosition, bool append, Cance private async Task ParseObjectAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -646,6 +660,8 @@ private async Task ParseObjectAsync(CancellationToken cancellationToken) private async Task ParseCommentAsync(bool setToken, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + // should have already parsed / character before reaching this method _charPos++; @@ -742,6 +758,8 @@ private async Task ParseCommentAsync(bool setToken, CancellationToken cancellati private async Task EatWhitespaceAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -798,6 +816,8 @@ private async Task MatchValueAsync(string value, CancellationToken cancell private async Task MatchValueWithTrailingSeparatorAsync(string value, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + // will match value and then move to the next character, checking that it is a separator character if (!await MatchValueAsync(value, cancellationToken).ConfigureAwait(false)) { @@ -812,7 +832,7 @@ private async Task MatchValueWithTrailingSeparatorAsync(string value, Canc return IsSeparator(_chars[_charPos]) || _chars[_charPos] == '\0'; } - private async Task MatchAndSetAsync(string value, JsonToken newToken, object tokenValue, CancellationToken cancellationToken) + private async Task MatchAndSetAsync(string value, JsonToken newToken, object? tokenValue, CancellationToken cancellationToken) { if (await MatchValueWithTrailingSeparatorAsync(value, cancellationToken).ConfigureAwait(false)) { @@ -841,6 +861,8 @@ private Task ParseNullAsync(CancellationToken cancellationToken) private async Task ParseConstructorAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + if (await MatchValueWithTrailingSeparatorAsync("new", cancellationToken).ConfigureAwait(false)) { await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false); @@ -939,6 +961,8 @@ private async Task ParseNumberNegativeInfinityAsync(ReadType readType, C private async Task ParseNumberAsync(ReadType readType, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + ShiftBufferIfNeeded(); char firstChar = _chars[_charPos]; @@ -956,6 +980,8 @@ private Task ParseUndefinedAsync(CancellationToken cancellationToken) private async Task ParsePropertyAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + char firstChar = _chars[_charPos]; char quoteChar; @@ -1008,6 +1034,8 @@ private async Task ParsePropertyAsync(CancellationToken cancellationToken) private async Task ReadNumberIntoBufferAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + int charPos = _charPos; while (true) @@ -1042,6 +1070,8 @@ private async Task ReadNumberIntoBufferAsync(CancellationToken cancellationToken private async Task ParseUnquotedPropertyAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + int initialPosition = _charPos; // parse unquoted property name until whitespace or colon @@ -1091,6 +1121,8 @@ private async Task ReadNullCharAsync(CancellationToken cancellationToken) private async Task HandleNullAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false)) { if (_chars[_charPos + 1] == 'u') @@ -1109,6 +1141,8 @@ private async Task HandleNullAsync(CancellationToken cancellationToken) private async Task ReadFinishedAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + if (await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false)) { await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false); @@ -1131,9 +1165,10 @@ private async Task ReadFinishedAsync(CancellationToken cancellationToken) SetToken(JsonToken.None); } - private async Task ReadStringValueAsync(ReadType readType, CancellationToken cancellationToken) + private async Task ReadStringValueAsync(ReadType readType, CancellationToken cancellationToken) { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); switch (_currentState) { @@ -1266,9 +1301,10 @@ private async Task ReadStringValueAsync(ReadType readType, CancellationT } } - private async Task ReadNumberValueAsync(ReadType readType, CancellationToken cancellationToken) + private async Task ReadNumberValueAsync(ReadType readType, CancellationToken cancellationToken) { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); switch (_currentState) { @@ -1395,6 +1431,7 @@ private async Task ReadNumberValueAsync(ReadType readType, CancellationT internal async Task DoReadAsBooleanAsync(CancellationToken cancellationToken) { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); switch (_currentState) { @@ -1522,14 +1559,16 @@ private async Task ReadNumberValueAsync(ReadType readType, CancellationT /// property returns the []. This result will be null at the end of an array. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task ReadAsBytesAsync(CancellationToken cancellationToken = default) + public override Task ReadAsBytesAsync(CancellationToken cancellationToken = default) { return _safeAsync ? DoReadAsBytesAsync(cancellationToken) : base.ReadAsBytesAsync(cancellationToken); } - internal async Task DoReadAsBytesAsync(CancellationToken cancellationToken) + internal async Task DoReadAsBytesAsync(CancellationToken cancellationToken) { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); + bool isWrapped = false; switch (_currentState) @@ -1563,7 +1602,7 @@ internal async Task DoReadAsBytesAsync(CancellationToken cancellationTok case '"': case '\'': await ParseStringAsync(currentChar, ReadType.ReadAsBytes, cancellationToken).ConfigureAwait(false); - byte[] data = (byte[])Value; + byte[]? data = (byte[]?)Value; if (isWrapped) { await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false); @@ -1642,7 +1681,7 @@ private async Task ReadIntoWrappedTypeObjectAsync(CancellationToken cancellation if (Value != null && Value.ToString() == JsonTypeReflector.TypePropertyName) { await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false); - if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal)) + if (Value != null && Value.ToString()!.StartsWith("System.Byte[]", StringComparison.Ordinal)) { await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false); if (Value.ToString() == JsonTypeReflector.ValuePropertyName) @@ -1753,16 +1792,17 @@ private async Task ReadIntoWrappedTypeObjectAsync(CancellationToken cancellation /// property returns the . This result will be null at the end of an array. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task ReadAsStringAsync(CancellationToken cancellationToken = default) + public override Task ReadAsStringAsync(CancellationToken cancellationToken = default) { return _safeAsync ? DoReadAsStringAsync(cancellationToken) : base.ReadAsStringAsync(cancellationToken); } - internal async Task DoReadAsStringAsync(CancellationToken cancellationToken) + internal async Task DoReadAsStringAsync(CancellationToken cancellationToken) { - return (string)await ReadStringValueAsync(ReadType.ReadAsString, cancellationToken).ConfigureAwait(false); + return (string?)await ReadStringValueAsync(ReadType.ReadAsString, cancellationToken).ConfigureAwait(false); } } +#nullable disable } #endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextReader.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextReader.cs index e84f607a86..ffd90de265 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextReader.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextReader.cs @@ -27,6 +27,7 @@ using System.Runtime.CompilerServices; using System.IO; using System.Globalization; +using System.Diagnostics; #if HAVE_BIG_INTEGER using System.Numerics; #endif @@ -34,6 +35,7 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable internal enum ReadType { Read, @@ -56,8 +58,9 @@ internal enum ReadType internal partial class JsonTextReader : JsonReader, IJsonLineInfo { private const char UnicodeReplacementChar = '\uFFFD'; +#if HAVE_BIG_INTEGER private const int MaximumJavascriptIntegerCharacterLength = 380; - +#endif #if DEBUG internal int LargeBufferLength { get; set; } = int.MaxValue / 2; #else @@ -65,7 +68,7 @@ internal partial class JsonTextReader : JsonReader, IJsonLineInfo #endif private readonly TextReader _reader; - private char[] _chars; + private char[]? _chars; private int _charsUsed; private int _charPos; private int _lineStartPos; @@ -73,7 +76,7 @@ internal partial class JsonTextReader : JsonReader, IJsonLineInfo private bool _isEndOfFile; private StringBuffer _stringBuffer; private StringReference _stringReference; - private IArrayPool _arrayPool; + private IArrayPool? _arrayPool; /// /// Initializes a new instance of the class with the specified . @@ -95,7 +98,7 @@ public JsonTextReader(TextReader reader) } #if DEBUG - internal char[] CharBuffer + internal char[]? CharBuffer { get => _chars; set => _chars = value; @@ -107,12 +110,12 @@ internal char[] CharBuffer /// /// Gets or sets the reader's property name table. /// - public JsonNameTable PropertyNameTable { get; set; } + public JsonNameTable? PropertyNameTable { get; set; } /// /// Gets or sets the reader's character buffer pool. /// - public IArrayPool ArrayPool + public IArrayPool? ArrayPool { get => _arrayPool; set @@ -136,6 +139,8 @@ private void EnsureBufferNotEmpty() private void SetNewLine(bool hasNextChar) { + MiscellaneousUtils.Assert(_chars != null); + if (hasNextChar && _chars[_charPos] == StringUtils.LineFeed) { _charPos++; @@ -160,7 +165,7 @@ private void ParseString(char quote, ReadType readType) } private void ParseReadString(char quote, ReadType readType) - { + { SetPostValueState(true); switch (readType) @@ -248,6 +253,8 @@ private static void BlockCopyChars(char[] src, int srcOffset, char[] dst, int ds private void ShiftBufferIfNeeded() { + MiscellaneousUtils.Assert(_chars != null); + // once in the last 10% of the buffer, or buffer is already very large then // shift the remaining content to the start to avoid unnecessarily increasing // the buffer size when reading numbers/strings @@ -274,6 +281,8 @@ private int ReadData(bool append) private void PrepareBufferForReadData(bool append, int charsRequired) { + MiscellaneousUtils.Assert(_chars != null); + // char buffer is full if (_charsUsed + charsRequired >= _chars.Length - 1) { @@ -337,6 +346,7 @@ private int ReadData(bool append, int charsRequired) } PrepareBufferForReadData(append, charsRequired); + MiscellaneousUtils.Assert(_chars != null); int attemptCharReadCount = _chars.Length - _charsUsed - 1; @@ -405,6 +415,7 @@ private bool ReadChars(int relativePosition, bool append) public override bool Read() { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); while (true) { @@ -475,18 +486,20 @@ public override bool Read() /// Reads the next JSON token from the underlying as a . /// /// A . This method will return null at the end of an array. - public override string ReadAsString() + public override string? ReadAsString() { - return (string)ReadStringValue(ReadType.ReadAsString); + return (string?)ReadStringValue(ReadType.ReadAsString); } /// /// Reads the next JSON token from the underlying as a []. /// /// A [] or null if the next JSON token is null. This method will return null at the end of an array. - public override byte[] ReadAsBytes() + public override byte[]? ReadAsBytes() { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); + bool isWrapped = false; switch (_currentState) @@ -519,7 +532,7 @@ public override byte[] ReadAsBytes() case '"': case '\'': ParseString(currentChar, ReadType.ReadAsBytes); - byte[] data = (byte[])Value; + byte[]? data = (byte[]?)Value; if (isWrapped) { ReaderReadAndAssert(); @@ -588,9 +601,10 @@ public override byte[] ReadAsBytes() } } - private object ReadStringValue(ReadType readType) + private object? ReadStringValue(ReadType readType) { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); switch (_currentState) { @@ -717,7 +731,7 @@ private object ReadStringValue(ReadType readType) } } - private object FinishReadQuotedStringValue(ReadType readType) + private object? FinishReadQuotedStringValue(ReadType readType) { switch (readType) { @@ -730,7 +744,7 @@ private object FinishReadQuotedStringValue(ReadType readType) return time; } - return ReadDateTimeString((string)Value); + return ReadDateTimeString((string?)Value); #if HAVE_DATE_TIME_OFFSET case ReadType.ReadAsDateTimeOffset: if (Value is DateTimeOffset offset) @@ -738,7 +752,7 @@ private object FinishReadQuotedStringValue(ReadType readType) return offset; } - return ReadDateTimeOffsetString((string)Value); + return ReadDateTimeOffsetString((string?)Value); #endif default: throw new ArgumentOutOfRangeException(nameof(readType)); @@ -757,6 +771,7 @@ private JsonReaderException CreateUnexpectedCharacterException(char c) public override bool? ReadAsBoolean() { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); switch (_currentState) { @@ -827,7 +842,7 @@ private JsonReaderException CreateUnexpectedCharacterException(char c) { throw CreateUnexpectedCharacterException(_chars[_charPos]); } - SetToken(JsonToken.Boolean, isTrue); + SetToken(JsonToken.Boolean, BoxedPrimitives.Get(isTrue)); return isTrue; case '/': ParseComment(false); @@ -891,9 +906,10 @@ private void ProcessValueComma() SetStateBasedOnCurrent(); } - private object ReadNumberValue(ReadType readType) + private object? ReadNumberValue(ReadType readType) { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); switch (_currentState) { @@ -1001,7 +1017,7 @@ private object ReadNumberValue(ReadType readType) } } - private object FinishReadQuotedNumber(ReadType readType) + private object? FinishReadQuotedNumber(ReadType readType) { switch (readType) { @@ -1047,6 +1063,8 @@ private object FinishReadQuotedNumber(ReadType readType) private void HandleNull() { + MiscellaneousUtils.Assert(_chars != null); + if (EnsureChars(1, true)) { char next = _chars[_charPos + 1]; @@ -1067,6 +1085,8 @@ private void HandleNull() private void ReadFinished() { + MiscellaneousUtils.Assert(_chars != null); + if (EnsureChars(0, false)) { EatWhitespace(); @@ -1116,6 +1136,8 @@ private void EnsureBuffer() private void ReadStringIntoBuffer(char quote) { + MiscellaneousUtils.Assert(_chars != null); + int charPos = _charPos; int initialPosition = _charPos; int lastWritePosition = _charPos; @@ -1269,6 +1291,8 @@ private void ReadStringIntoBuffer(char quote) private void FinishReadStringIntoBuffer(int charPos, int initialPosition, int lastWritePosition) { + MiscellaneousUtils.Assert(_chars != null); + if (initialPosition == lastWritePosition) { _stringReference = new StringReference(_chars, initialPosition, charPos - initialPosition); @@ -1282,7 +1306,7 @@ private void FinishReadStringIntoBuffer(int charPos, int initialPosition, int la _stringBuffer.Append(_arrayPool, _chars, lastWritePosition, charPos - lastWritePosition); } - _stringReference = new StringReference(_stringBuffer.InternalBuffer, 0, _stringBuffer.Position); + _stringReference = new StringReference(_stringBuffer.InternalBuffer!, 0, _stringBuffer.Position); } _charPos = charPos + 1; @@ -1290,6 +1314,8 @@ private void FinishReadStringIntoBuffer(int charPos, int initialPosition, int la private void WriteCharToBuffer(char writeChar, int lastWritePosition, int writeToPosition) { + MiscellaneousUtils.Assert(_chars != null); + if (writeToPosition > lastWritePosition) { _stringBuffer.Append(_arrayPool, _chars, lastWritePosition, writeToPosition - lastWritePosition); @@ -1300,6 +1326,8 @@ private void WriteCharToBuffer(char writeChar, int lastWritePosition, int writeT private char ConvertUnicode(bool enoughChars) { + MiscellaneousUtils.Assert(_chars != null); + if (enoughChars) { if (ConvertUtils.TryHexTextToInt(_chars, _charPos, _charPos + 4, out int value)) @@ -1326,6 +1354,8 @@ private char ParseUnicode() private void ReadNumberIntoBuffer() { + MiscellaneousUtils.Assert(_chars != null); + int charPos = _charPos; while (true) @@ -1410,6 +1440,8 @@ private void ClearRecentString() private bool ParsePostValue(bool ignoreComments) { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -1490,6 +1522,8 @@ private bool ParsePostValue(bool ignoreComments) private bool ParseObject() { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -1544,6 +1578,8 @@ private bool ParseObject() private bool ParseProperty() { + MiscellaneousUtils.Assert(_chars != null); + char firstChar = _chars[_charPos]; char quoteChar; @@ -1565,7 +1601,7 @@ private bool ParseProperty() throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); } - string propertyName; + string? propertyName; if (PropertyNameTable != null) { @@ -1605,6 +1641,8 @@ private bool ValidIdentifierChar(char value) private void ParseUnquotedProperty() { + MiscellaneousUtils.Assert(_chars != null); + int initialPosition = _charPos; // parse unquoted property name until whitespace or colon @@ -1636,6 +1674,8 @@ private void ParseUnquotedProperty() private bool ReadUnquotedPropertyReportIfDone(char currentChar, int initialPosition) { + MiscellaneousUtils.Assert(_chars != null); + if (ValidIdentifierChar(currentChar)) { _charPos++; @@ -1653,6 +1693,8 @@ private bool ReadUnquotedPropertyReportIfDone(char currentChar, int initialPosit private bool ParseValue() { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -1793,6 +1835,8 @@ private void ProcessCarriageReturn(bool append) private void EatWhitespace() { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -1834,6 +1878,8 @@ private void EatWhitespace() private void ParseConstructor() { + MiscellaneousUtils.Assert(_chars != null); + if (MatchValueWithTrailingSeparator("new")) { EatWhitespace(); @@ -1918,6 +1964,7 @@ private void ParseConstructor() private void ParseNumber(ReadType readType) { ShiftBufferIfNeeded(); + MiscellaneousUtils.Assert(_chars != null); char firstChar = _chars[_charPos]; int initialPosition = _charPos; @@ -1929,6 +1976,8 @@ private void ParseNumber(ReadType readType) private void ParseReadNumber(ReadType readType, char firstChar, int initialPosition) { + MiscellaneousUtils.Assert(_chars != null); + // set state to PostValue now so that if there is an error parsing the number then the reader can continue SetPostValueState(true); @@ -1982,7 +2031,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit if (singleDigit) { // digit char values start at 48 - numberValue = firstChar - 48; + numberValue = BoxedPrimitives.Get(firstChar - 48); } else if (nonBase10) { @@ -1992,7 +2041,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit { int integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt32(number, 16) : Convert.ToInt32(number, 8); - numberValue = integer; + numberValue = BoxedPrimitives.Get(integer); } catch (Exception ex) { @@ -2004,7 +2053,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit ParseResult parseResult = ConvertUtils.Int32TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out int value); if (parseResult == ParseResult.Success) { - numberValue = value; + numberValue = BoxedPrimitives.Get(value); } else if (parseResult == ParseResult.Overflow) { @@ -2024,7 +2073,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit if (singleDigit) { // digit char values start at 48 - numberValue = (decimal)firstChar - 48; + numberValue = BoxedPrimitives.Get((decimal)firstChar - 48); } else if (nonBase10) { @@ -2035,7 +2084,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit // decimal.Parse doesn't support parsing hexadecimal values long integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8); - numberValue = Convert.ToDecimal(integer); + numberValue = BoxedPrimitives.Get(Convert.ToDecimal(integer)); } catch (Exception ex) { @@ -2047,7 +2096,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit ParseResult parseResult = ConvertUtils.DecimalTryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out decimal value); if (parseResult == ParseResult.Success) { - numberValue = value; + numberValue = BoxedPrimitives.Get(value); } else { @@ -2063,7 +2112,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit if (singleDigit) { // digit char values start at 48 - numberValue = (double)firstChar - 48; + numberValue = BoxedPrimitives.Get((double)firstChar - 48); } else if (nonBase10) { @@ -2074,7 +2123,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit // double.Parse doesn't support parsing hexadecimal values long integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8); - numberValue = Convert.ToDouble(integer); + numberValue = BoxedPrimitives.Get(Convert.ToDouble(integer)); } catch (Exception ex) { @@ -2087,7 +2136,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit if (double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out double value)) { - numberValue = value; + numberValue = BoxedPrimitives.Get(value); } else { @@ -2104,7 +2153,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit if (singleDigit) { // digit char values start at 48 - numberValue = (long)firstChar - 48; + numberValue = BoxedPrimitives.Get((long)firstChar - 48); numberType = JsonToken.Integer; } else if (nonBase10) @@ -2113,7 +2162,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit try { - numberValue = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8); + numberValue = BoxedPrimitives.Get(number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8)); } catch (Exception ex) { @@ -2127,7 +2176,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit ParseResult parseResult = ConvertUtils.Int64TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out long value); if (parseResult == ParseResult.Success) { - numberValue = value; + numberValue = BoxedPrimitives.Get(value); numberType = JsonToken.Integer; } else if (parseResult == ParseResult.Overflow) @@ -2153,7 +2202,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit parseResult = ConvertUtils.DecimalTryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out decimal d); if (parseResult == ParseResult.Success) { - numberValue = d; + numberValue = BoxedPrimitives.Get(d); } else { @@ -2166,7 +2215,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit if (double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out double d)) { - numberValue = d; + numberValue = BoxedPrimitives.Get(d); } else { @@ -2189,7 +2238,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit SetToken(numberType, numberValue, false); } - private JsonReaderException ThrowReaderError(string message, Exception ex = null) + private JsonReaderException ThrowReaderError(string message, Exception? ex = null) { SetToken(JsonToken.Undefined, null, false); return JsonReaderException.Create(this, message, ex); @@ -2197,7 +2246,7 @@ private JsonReaderException ThrowReaderError(string message, Exception ex = null #if HAVE_BIG_INTEGER // By using the BigInteger type in a separate method, - // the runtime can execute the ParseNumber even if + // the runtime can execute the ParseNumber even if // the System.Numerics.BigInteger.Parse method is // missing, which happens in some versions of Mono [MethodImpl(MethodImplOptions.NoInlining)] @@ -2209,6 +2258,8 @@ private static object BigIntegerParse(string number, CultureInfo culture) private void ParseComment(bool setToken) { + MiscellaneousUtils.Assert(_chars != null); + // should have already parsed / character before reaching this method _charPos++; @@ -2303,6 +2354,7 @@ private void EndComment(bool setToken, int initialPosition, int endPosition) { if (setToken) { + MiscellaneousUtils.Assert(_chars != null); SetToken(JsonToken.Comment, new string(_chars, initialPosition, endPosition - initialPosition)); } } @@ -2314,6 +2366,8 @@ private bool MatchValue(string value) private bool MatchValue(bool enoughChars, string value) { + MiscellaneousUtils.Assert(_chars != null); + if (!enoughChars) { _charPos = _charsUsed; @@ -2336,6 +2390,8 @@ private bool MatchValue(bool enoughChars, string value) private bool MatchValueWithTrailingSeparator(string value) { + MiscellaneousUtils.Assert(_chars != null); + // will match value and then move to the next character, checking that it is a separator character bool match = MatchValue(value); @@ -2354,6 +2410,8 @@ private bool MatchValueWithTrailingSeparator(string value) private bool IsSeparator(char c) { + MiscellaneousUtils.Assert(_chars != null); + switch (c) { case '}': @@ -2399,7 +2457,7 @@ private void ParseTrue() // or the text ends if (MatchValueWithTrailingSeparator(JsonConvert.True)) { - SetToken(JsonToken.Boolean, true); + SetToken(JsonToken.Boolean, BoxedPrimitives.BooleanTrue); } else { @@ -2435,7 +2493,7 @@ private void ParseFalse() { if (MatchValueWithTrailingSeparator(JsonConvert.False)) { - SetToken(JsonToken.Boolean, false); + SetToken(JsonToken.Boolean, BoxedPrimitives.BooleanFalse); } else { @@ -2458,7 +2516,7 @@ private object ParseNumberNegativeInfinity(ReadType readType, bool matched) case ReadType.ReadAsDouble: if (_floatParseHandling == FloatParseHandling.Double) { - SetToken(JsonToken.Float, double.NegativeInfinity); + SetToken(JsonToken.Float, BoxedPrimitives.DoubleNegativeInfinity); return double.NegativeInfinity; } break; @@ -2487,7 +2545,7 @@ private object ParseNumberPositiveInfinity(ReadType readType, bool matched) case ReadType.ReadAsDouble: if (_floatParseHandling == FloatParseHandling.Double) { - SetToken(JsonToken.Float, double.PositiveInfinity); + SetToken(JsonToken.Float, BoxedPrimitives.DoublePositiveInfinity); return double.PositiveInfinity; } break; @@ -2517,7 +2575,7 @@ private object ParseNumberNaN(ReadType readType, bool matched) case ReadType.ReadAsDouble: if (_floatParseHandling == FloatParseHandling.Double) { - SetToken(JsonToken.Float, double.NaN); + SetToken(JsonToken.Float, BoxedPrimitives.DoubleNaN); return double.NaN; } break; @@ -2596,4 +2654,5 @@ public int LineNumber /// public int LinePosition => _charPos - _lineStartPos; } +#nullable disable } diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextWriter.Async.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextWriter.Async.cs index 737315a24f..aecb6d8fdf 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextWriter.Async.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextWriter.Async.cs @@ -33,9 +33,12 @@ #endif using System.Threading.Tasks; using Microsoft.IdentityModel.Json.Utilities; +using System.Diagnostics; namespace Microsoft.IdentityModel.Json { +#nullable enable +#pragma warning disable CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly internal partial class JsonTextWriter { // It's not safe to perform the async methods here in a derived class as if the synchronous equivalent @@ -131,7 +134,34 @@ internal async Task DoCloseAsync(CancellationToken cancellationToken) await WriteEndAsync(cancellationToken).ConfigureAwait(false); } - CloseBufferAndWriter(); + await CloseBufferAndWriterAsync().ConfigureAwait(false); + } + + private async Task CloseBufferAndWriterAsync() + { + if (_writeBuffer != null) + { + BufferUtils.ReturnBuffer(_arrayPool, _writeBuffer); + _writeBuffer = null; + } + + if (CloseOutput && _writer != null) + { +#if HAVE_ASYNC_DISPOSABLE + await _writer.DisposeAsync().ConfigureAwait(false); +#else + // DisposeAsync isn't available. Instead, flush any remaining content with FlushAsync + // to prevent Close/Dispose from making a blocking flush. + // + // No cancellation token on TextWriter.FlushAsync?! + await _writer.FlushAsync().ConfigureAwait(false); +#if HAVE_STREAM_READER_WRITER_CLOSE + _writer.Close(); +#else + _writer.Dispose(); +#endif +#endif + } } /// @@ -164,6 +194,7 @@ internal Task DoWriteIndentAsync(CancellationToken cancellationToken) int currentIndentCount = Top * _indentation; int newLineLen = SetIndentChars(); + MiscellaneousUtils.Assert(_indentChars != null); if (currentIndentCount <= IndentCharBufferSize) { @@ -175,6 +206,8 @@ internal Task DoWriteIndentAsync(CancellationToken cancellationToken) private async Task WriteIndentAsync(int currentIndentCount, int newLineLen, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_indentChars != null); + await _writer.WriteAsync(_indentChars, 0, newLineLen + Math.Min(currentIndentCount, IndentCharBufferSize), cancellationToken).ConfigureAwait(false); while ((currentIndentCount -= IndentCharBufferSize) > 0) @@ -186,7 +219,7 @@ private async Task WriteIndentAsync(int currentIndentCount, int newLineLen, Canc private Task WriteValueInternalAsync(JsonToken token, string value, CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(token, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return _writer.WriteAsync(value, cancellationToken); } @@ -225,12 +258,12 @@ internal Task DoWriteIndentSpaceAsync(CancellationToken cancellationToken) /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteRawAsync(string json, CancellationToken cancellationToken = default) + public override Task WriteRawAsync(string? json, CancellationToken cancellationToken = default) { return _safeAsync ? DoWriteRawAsync(json, cancellationToken) : base.WriteRawAsync(json, cancellationToken); } - internal Task DoWriteRawAsync(string json, CancellationToken cancellationToken) + internal Task DoWriteRawAsync(string? json, CancellationToken cancellationToken) { return _writer.WriteAsync(json, cancellationToken); } @@ -260,13 +293,13 @@ private Task WriteDigitsAsync(ulong uvalue, bool negative, CancellationToken can } int length = WriteNumberToBuffer(uvalue, negative); - return _writer.WriteAsync(_writeBuffer, 0, length, cancellationToken); + return _writer.WriteAsync(_writeBuffer!, 0, length, cancellationToken); } private Task WriteIntegerValueAsync(ulong uvalue, bool negative, CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(JsonToken.Integer, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return WriteDigitsAsync(uvalue, negative, cancellationToken); } @@ -298,7 +331,7 @@ internal Task WriteIntegerValueAsync(ulong uvalue, CancellationToken cancellatio private Task WriteEscapedStringAsync(string value, bool quote, CancellationToken cancellationToken) { - return JavaScriptUtils.WriteEscapedJavaScriptStringAsync(_writer, value, _quoteChar, quote, _charEscapeFlags, StringEscapeHandling, this, _writeBuffer, cancellationToken); + return JavaScriptUtils.WriteEscapedJavaScriptStringAsync(_writer, value, _quoteChar, quote, _charEscapeFlags!, StringEscapeHandling, this, _writeBuffer!, cancellationToken); } /// @@ -317,13 +350,13 @@ public override Task WritePropertyNameAsync(string name, CancellationToken cance internal Task DoWritePropertyNameAsync(string name, CancellationToken cancellationToken) { Task task = InternalWritePropertyNameAsync(name, cancellationToken); - if (!task.IsCompletedSucessfully()) + if (!task.IsCompletedSuccessfully()) { return DoWritePropertyNameAsync(task, name, cancellationToken); } task = WriteEscapedStringAsync(name, _quoteName, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return _writer.WriteAsync(':', cancellationToken); } @@ -395,7 +428,7 @@ public override Task WriteStartArrayAsync(CancellationToken cancellationToken = internal Task DoWriteStartArrayAsync(CancellationToken cancellationToken) { Task task = InternalWriteStartAsync(JsonToken.StartArray, JsonContainerType.Array, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return _writer.WriteAsync('[', cancellationToken); } @@ -425,7 +458,7 @@ public override Task WriteStartObjectAsync(CancellationToken cancellationToken = internal Task DoWriteStartObjectAsync(CancellationToken cancellationToken) { Task task = InternalWriteStartAsync(JsonToken.StartObject, JsonContainerType.Object, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return _writer.WriteAsync('{', cancellationToken); } @@ -477,7 +510,7 @@ public override Task WriteUndefinedAsync(CancellationToken cancellationToken = d internal Task DoWriteUndefinedAsync(CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(JsonToken.Undefined, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return _writer.WriteAsync(JsonConvert.Undefined, cancellationToken); } @@ -585,7 +618,7 @@ internal Task DoWriteValueAsync(byte? value, CancellationToken cancellationToken /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteValueAsync(byte[] value, CancellationToken cancellationToken = default) + public override Task WriteValueAsync(byte[]? value, CancellationToken cancellationToken = default) { return _safeAsync ? (value == null ? WriteNullAsync(cancellationToken) : WriteValueNonNullAsync(value, cancellationToken)) : base.WriteValueAsync(value, cancellationToken); } @@ -653,11 +686,11 @@ internal async Task DoWriteValueAsync(DateTime value, CancellationToken cancella await InternalWriteValueAsync(JsonToken.Date, cancellationToken).ConfigureAwait(false); value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling); - if (string.IsNullOrEmpty(DateFormatString)) + if (StringUtils.IsNullOrEmpty(DateFormatString)) { int length = WriteValueToBuffer(value); - await _writer.WriteAsync(_writeBuffer, 0, length, cancellationToken).ConfigureAwait(false); + await _writer.WriteAsync(_writeBuffer!, 0, length, cancellationToken).ConfigureAwait(false); } else { @@ -702,11 +735,11 @@ internal async Task DoWriteValueAsync(DateTimeOffset value, CancellationToken ca { await InternalWriteValueAsync(JsonToken.Date, cancellationToken).ConfigureAwait(false); - if (string.IsNullOrEmpty(DateFormatString)) + if (StringUtils.IsNullOrEmpty(DateFormatString)) { int length = WriteValueToBuffer(value); - await _writer.WriteAsync(_writeBuffer, 0, length, cancellationToken).ConfigureAwait(false); + await _writer.WriteAsync(_writeBuffer!, 0, length, cancellationToken).ConfigureAwait(false); } else { @@ -853,9 +886,7 @@ internal async Task DoWriteValueAsync(Guid value, CancellationToken cancellation #if HAVE_CHAR_TO_STRING_WITH_CULTURE await _writer.WriteAsync(value.ToString("D", CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false); #else -#pragma warning disable CA1305 // Specify IFormatProvider await _writer.WriteAsync(value.ToString("D"), cancellationToken).ConfigureAwait(false); -#pragma warning restore CA1305 // Specify IFormatProvider #endif await _writer.WriteAsync(_quoteChar).ConfigureAwait(false); } @@ -955,7 +986,7 @@ internal Task WriteValueAsync(BigInteger value, CancellationToken cancellationTo /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteValueAsync(object value, CancellationToken cancellationToken = default) + public override Task WriteValueAsync(object? value, CancellationToken cancellationToken = default) { if (_safeAsync) { @@ -984,7 +1015,7 @@ public override Task WriteValueAsync(object value, CancellationToken cancellatio /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override Task WriteValueAsync(sbyte value, CancellationToken cancellationToken = default) { return _safeAsync ? WriteIntegerValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken); @@ -998,7 +1029,7 @@ public override Task WriteValueAsync(sbyte value, CancellationToken cancellation /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override Task WriteValueAsync(sbyte? value, CancellationToken cancellationToken = default) { return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken); @@ -1048,15 +1079,15 @@ internal Task DoWriteValueAsync(short? value, CancellationToken cancellationToke /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteValueAsync(string value, CancellationToken cancellationToken = default) + public override Task WriteValueAsync(string? value, CancellationToken cancellationToken = default) { return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken); } - internal Task DoWriteValueAsync(string value, CancellationToken cancellationToken) + internal Task DoWriteValueAsync(string? value, CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(JsonToken.String, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return value == null ? _writer.WriteAsync(JsonConvert.Null, cancellationToken) : WriteEscapedStringAsync(value, true, cancellationToken); } @@ -1064,7 +1095,7 @@ internal Task DoWriteValueAsync(string value, CancellationToken cancellationToke return DoWriteValueAsync(task, value, cancellationToken); } - private async Task DoWriteValueAsync(Task task, string value, CancellationToken cancellationToken) + private async Task DoWriteValueAsync(Task task, string? value, CancellationToken cancellationToken) { await task.ConfigureAwait(false); await (value == null ? _writer.WriteAsync(JsonConvert.Null, cancellationToken) : WriteEscapedStringAsync(value, true, cancellationToken)).ConfigureAwait(false); @@ -1117,7 +1148,7 @@ internal Task DoWriteValueAsync(TimeSpan? value, CancellationToken cancellationT /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override Task WriteValueAsync(uint value, CancellationToken cancellationToken = default) { return _safeAsync ? WriteIntegerValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken); @@ -1131,7 +1162,7 @@ public override Task WriteValueAsync(uint value, CancellationToken cancellationT /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override Task WriteValueAsync(uint? value, CancellationToken cancellationToken = default) { return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken); @@ -1150,7 +1181,7 @@ internal Task DoWriteValueAsync(uint? value, CancellationToken cancellationToken /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override Task WriteValueAsync(ulong value, CancellationToken cancellationToken = default) { return _safeAsync ? WriteIntegerValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken); @@ -1164,7 +1195,7 @@ public override Task WriteValueAsync(ulong value, CancellationToken cancellation /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override Task WriteValueAsync(ulong? value, CancellationToken cancellationToken = default) { return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken); @@ -1183,7 +1214,7 @@ internal Task DoWriteValueAsync(ulong? value, CancellationToken cancellationToke /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteValueAsync(Uri value, CancellationToken cancellationToken = default) + public override Task WriteValueAsync(Uri? value, CancellationToken cancellationToken = default) { return _safeAsync ? (value == null ? WriteNullAsync(cancellationToken) : WriteValueNotNullAsync(value, cancellationToken)) : base.WriteValueAsync(value, cancellationToken); } @@ -1191,7 +1222,7 @@ public override Task WriteValueAsync(Uri value, CancellationToken cancellationTo internal Task WriteValueNotNullAsync(Uri value, CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(JsonToken.String, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return WriteEscapedStringAsync(value.OriginalString, true, cancellationToken); } @@ -1213,7 +1244,7 @@ internal async Task WriteValueNotNullAsync(Task task, Uri value, CancellationTok /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override Task WriteValueAsync(ushort value, CancellationToken cancellationToken = default) { return _safeAsync ? WriteIntegerValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken); @@ -1227,7 +1258,7 @@ public override Task WriteValueAsync(ushort value, CancellationToken cancellatio /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override Task WriteValueAsync(ushort? value, CancellationToken cancellationToken = default) { return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken); @@ -1246,16 +1277,16 @@ internal Task DoWriteValueAsync(ushort? value, CancellationToken cancellationTok /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteCommentAsync(string text, CancellationToken cancellationToken = default) + public override Task WriteCommentAsync(string? text, CancellationToken cancellationToken = default) { return _safeAsync ? DoWriteCommentAsync(text, cancellationToken) : base.WriteCommentAsync(text, cancellationToken); } - internal async Task DoWriteCommentAsync(string text, CancellationToken cancellationToken) + internal async Task DoWriteCommentAsync(string? text, CancellationToken cancellationToken) { await InternalWriteCommentAsync(cancellationToken).ConfigureAwait(false); await _writer.WriteAsync("/*", cancellationToken).ConfigureAwait(false); - await _writer.WriteAsync(text, cancellationToken).ConfigureAwait(false); + await _writer.WriteAsync(text ?? string.Empty, cancellationToken).ConfigureAwait(false); await _writer.WriteAsync("*/", cancellationToken).ConfigureAwait(false); } @@ -1303,16 +1334,16 @@ public override Task WriteEndObjectAsync(CancellationToken cancellationToken = d /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteRawValueAsync(string json, CancellationToken cancellationToken = default) + public override Task WriteRawValueAsync(string? json, CancellationToken cancellationToken = default) { return _safeAsync ? DoWriteRawValueAsync(json, cancellationToken) : base.WriteRawValueAsync(json, cancellationToken); } - internal Task DoWriteRawValueAsync(string json, CancellationToken cancellationToken) + internal Task DoWriteRawValueAsync(string? json, CancellationToken cancellationToken) { UpdateScopeWithFinishedValue(); Task task = AutoCompleteAsync(JsonToken.Undefined, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return WriteRawAsync(json, cancellationToken); } @@ -1320,7 +1351,7 @@ internal Task DoWriteRawValueAsync(string json, CancellationToken cancellationTo return DoWriteRawValueAsync(task, json, cancellationToken); } - private async Task DoWriteRawValueAsync(Task task, string json, CancellationToken cancellationToken) + private async Task DoWriteRawValueAsync(Task task, string? json, CancellationToken cancellationToken) { await task.ConfigureAwait(false); await WriteRawAsync(json, cancellationToken).ConfigureAwait(false); @@ -1333,7 +1364,7 @@ internal char[] EnsureWriteBuffer(int length, int copyTo) length = 35; } - char[] buffer = _writeBuffer; + char[]? buffer = _writeBuffer; if (buffer == null) { return _writeBuffer = BufferUtils.RentBuffer(_arrayPool, length); @@ -1355,5 +1386,7 @@ internal char[] EnsureWriteBuffer(int length, int copyTo) return newBuffer; } } +#nullable disable +#pragma warning restore CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextWriter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextWriter.cs index 71013d2988..7d9ed0c5b1 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextWriter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonTextWriter.cs @@ -33,9 +33,12 @@ using System.IO; using System.Xml; using Microsoft.IdentityModel.Json.Utilities; +using System.Diagnostics; namespace Microsoft.IdentityModel.Json { +#nullable enable +#pragma warning disable CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly /// /// Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data. /// @@ -43,15 +46,15 @@ internal partial class JsonTextWriter : JsonWriter { private const int IndentCharBufferSize = 12; private readonly TextWriter _writer; - private Base64Encoder _base64Encoder; + private Base64Encoder? _base64Encoder; private char _indentChar; private int _indentation; private char _quoteChar; private bool _quoteName; - private bool[] _charEscapeFlags; - private char[] _writeBuffer; - private IArrayPool _arrayPool; - private char[] _indentChars; + private bool[]? _charEscapeFlags; + private char[]? _writeBuffer; + private IArrayPool? _arrayPool; + private char[]? _indentChars; private Base64Encoder Base64Encoder { @@ -69,7 +72,7 @@ private Base64Encoder Base64Encoder /// /// Gets or sets the writer's character array pool. /// - public IArrayPool ArrayPool + public IArrayPool? ArrayPool { get => _arrayPool; set @@ -324,6 +327,7 @@ protected override void WriteIndent() int newLineLen = SetIndentChars(); + MiscellaneousUtils.Assert(_indentChars != null); _writer.Write(_indentChars, 0, newLineLen + Math.Min(currentIndentCount, IndentCharBufferSize)); while ((currentIndentCount -= IndentCharBufferSize) > 0) @@ -342,7 +346,7 @@ private int SetIndentChars() { for (int i = 0; i != newLineLen; ++i) { - if (writerNewLine[i] != _indentChars[i]) + if (writerNewLine[i] != _indentChars![i]) { match = false; break; @@ -387,7 +391,7 @@ private void WriteValueInternal(string value, JsonToken token) /// An error will raised if the value cannot be written as a single JSON token. /// /// The value to write. - public override void WriteValue(object value) + public override void WriteValue(object? value) { #if HAVE_BIG_INTEGER if (value is BigInteger i) @@ -424,7 +428,7 @@ public override void WriteUndefined() /// Writes raw JSON. /// /// The raw JSON to write. - public override void WriteRaw(string json) + public override void WriteRaw(string? json) { InternalWriteRaw(); @@ -435,7 +439,7 @@ public override void WriteRaw(string json) /// Writes a value. /// /// The value to write. - public override void WriteValue(string value) + public override void WriteValue(string? value) { InternalWriteValue(JsonToken.String); @@ -452,7 +456,7 @@ public override void WriteValue(string value) private void WriteEscapedString(string value, bool quote) { EnsureWriteBuffer(); - JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, quote, _charEscapeFlags, StringEscapeHandling, _arrayPool, ref _writeBuffer); + JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, quote, _charEscapeFlags!, StringEscapeHandling, _arrayPool, ref _writeBuffer); } /// @@ -469,7 +473,7 @@ public override void WriteValue(int value) /// Writes a value. /// /// The value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override void WriteValue(uint value) { InternalWriteValue(JsonToken.Integer); @@ -490,7 +494,7 @@ public override void WriteValue(long value) /// Writes a value. /// /// The value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override void WriteValue(ulong value) { InternalWriteValue(JsonToken.Integer); @@ -575,7 +579,7 @@ public override void WriteValue(short value) /// Writes a value. /// /// The value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override void WriteValue(ushort value) { InternalWriteValue(JsonToken.Integer); @@ -606,7 +610,7 @@ public override void WriteValue(byte value) /// Writes a value. /// /// The value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override void WriteValue(sbyte value) { InternalWriteValue(JsonToken.Integer); @@ -632,10 +636,11 @@ public override void WriteValue(DateTime value) InternalWriteValue(JsonToken.Date); value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling); - if (string.IsNullOrEmpty(DateFormatString)) + if (StringUtils.IsNullOrEmpty(DateFormatString)) { int length = WriteValueToBuffer(value); + MiscellaneousUtils.Assert(_writeBuffer != null); _writer.Write(_writeBuffer, 0, length); } else @@ -649,6 +654,7 @@ public override void WriteValue(DateTime value) private int WriteValueToBuffer(DateTime value) { EnsureWriteBuffer(); + MiscellaneousUtils.Assert(_writeBuffer != null); int pos = 0; _writeBuffer[pos++] = _quoteChar; @@ -661,7 +667,7 @@ private int WriteValueToBuffer(DateTime value) /// Writes a [] value. /// /// The [] value to write. - public override void WriteValue(byte[] value) + public override void WriteValue(byte[]? value) { if (value == null) { @@ -686,10 +692,11 @@ public override void WriteValue(DateTimeOffset value) { InternalWriteValue(JsonToken.Date); - if (string.IsNullOrEmpty(DateFormatString)) + if (StringUtils.IsNullOrEmpty(DateFormatString)) { int length = WriteValueToBuffer(value); + MiscellaneousUtils.Assert(_writeBuffer != null); _writer.Write(_writeBuffer, 0, length); } else @@ -703,6 +710,7 @@ public override void WriteValue(DateTimeOffset value) private int WriteValueToBuffer(DateTimeOffset value) { EnsureWriteBuffer(); + MiscellaneousUtils.Assert(_writeBuffer != null); int pos = 0; _writeBuffer[pos++] = _quoteChar; @@ -720,14 +728,12 @@ public override void WriteValue(Guid value) { InternalWriteValue(JsonToken.String); - string text = null; + string text; #if HAVE_CHAR_TO_STRING_WITH_CULTURE text = value.ToString("D", CultureInfo.InvariantCulture); #else -#pragma warning disable CA1305 // Specify IFormatProvider text = value.ToString("D"); -#pragma warning restore CA1305 // Specify IFormatProvider #endif _writer.Write(_quoteChar); @@ -759,7 +765,7 @@ public override void WriteValue(TimeSpan value) /// Writes a value. /// /// The value to write. - public override void WriteValue(Uri value) + public override void WriteValue(Uri? value) { if (value == null) { @@ -774,10 +780,10 @@ public override void WriteValue(Uri value) #endregion /// - /// Writes a comment /*...*/ containing the specified text. + /// Writes a comment /*...*/ containing the specified text. /// /// Text to place inside the comment. - public override void WriteComment(string text) + public override void WriteComment(string? text) { InternalWriteComment(); @@ -828,6 +834,8 @@ private void WriteIntegerValue(ulong value, bool negative) else { int length = WriteNumberToBuffer(value, negative); + + MiscellaneousUtils.Assert(_writeBuffer != null); _writer.Write(_writeBuffer, 0, length); } } @@ -841,6 +849,7 @@ private int WriteNumberToBuffer(ulong value, bool negative) } EnsureWriteBuffer(); + MiscellaneousUtils.Assert(_writeBuffer != null); int totalLength = MathUtils.IntLength(value); @@ -885,6 +894,8 @@ private void WriteIntegerValue(uint value, bool negative) else { int length = WriteNumberToBuffer(value, negative); + + MiscellaneousUtils.Assert(_writeBuffer != null); _writer.Write(_writeBuffer, 0, length); } } @@ -892,6 +903,7 @@ private void WriteIntegerValue(uint value, bool negative) private int WriteNumberToBuffer(uint value, bool negative) { EnsureWriteBuffer(); + MiscellaneousUtils.Assert(_writeBuffer != null); int totalLength = MathUtils.IntLength(value); @@ -914,4 +926,6 @@ private int WriteNumberToBuffer(uint value, bool negative) return totalLength; } } -} \ No newline at end of file +#nullable disable +#pragma warning restore CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonToken.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonToken.cs index 5dda7f69bf..6a734c26ee 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonToken.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonToken.cs @@ -124,4 +124,4 @@ internal enum JsonToken /// Bytes = 17 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonValidatingReader.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonValidatingReader.cs index de3b55b01e..3d22398750 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonValidatingReader.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonValidatingReader.cs @@ -41,6 +41,8 @@ #endif +#nullable disable + namespace Microsoft.IdentityModel.Json { /// @@ -121,7 +123,7 @@ private IEnumerable GetRequiredProperties(JsonSchemaModel schema) public override int Depth => _reader.Depth; /// - /// Gets the path of the current JSON token. + /// Gets the path of the current JSON token. /// public override string Path => _reader.Path; @@ -1020,4 +1022,4 @@ bool IJsonLineInfo.HasLineInfo() int IJsonLineInfo.LinePosition => (_reader is IJsonLineInfo lineInfo) ? lineInfo.LinePosition : 0; } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonWriter.Async.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonWriter.Async.cs index c7262e1c65..2085c55354 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonWriter.Async.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonWriter.Async.cs @@ -36,8 +36,23 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable +#pragma warning disable CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly internal abstract partial class JsonWriter +#if HAVE_ASYNC_DISPOABLE + : IAsyncDisposable +#endif { +#if HAVE_ASYNC_DISPOABLE + async ValueTask IAsyncDisposable.DisposeAsync() + { + if (_currentState != State.Closed) + { + await CloseAsync().ConfigureAwait(false); + } + } +#endif + internal Task AutoCompleteAsync(JsonToken tokenBeingWritten, CancellationToken cancellationToken) { State oldState = _currentState; @@ -225,7 +240,7 @@ protected virtual Task WriteIndentSpaceAsync(CancellationToken cancellationToken /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteRawAsync(string json, CancellationToken cancellationToken = default) + public virtual Task WriteRawAsync(string? json, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -291,7 +306,7 @@ internal Task InternalWriteEndAsync(JsonContainerType type, CancellationToken ca if (_currentState == State.Property) { t = WriteNullAsync(cancellationToken); - if (!t.IsCompletedSucessfully()) + if (!t.IsCompletedSuccessfully()) { return AwaitProperty(t, levelsToComplete, token, cancellationToken); } @@ -302,7 +317,7 @@ internal Task InternalWriteEndAsync(JsonContainerType type, CancellationToken ca if (_currentState != State.ObjectStart && _currentState != State.ArrayStart) { t = WriteIndentAsync(cancellationToken); - if (!t.IsCompletedSucessfully()) + if (!t.IsCompletedSuccessfully()) { return AwaitIndent(t, levelsToComplete, token, cancellationToken); } @@ -310,7 +325,7 @@ internal Task InternalWriteEndAsync(JsonContainerType type, CancellationToken ca } t = WriteEndAsync(token, cancellationToken); - if (!t.IsCompletedSucessfully()) + if (!t.IsCompletedSuccessfully()) { return AwaitEnd(t, levelsToComplete, cancellationToken); } @@ -546,7 +561,7 @@ internal async Task InternalWriteStartAsync(JsonToken token, JsonContainerType c /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteCommentAsync(string text, CancellationToken cancellationToken = default) + public virtual Task WriteCommentAsync(string? text, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -570,7 +585,7 @@ internal Task InternalWriteCommentAsync(CancellationToken cancellationToken) /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteRawValueAsync(string json, CancellationToken cancellationToken = default) + public virtual Task WriteRawValueAsync(string? json, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -673,7 +688,7 @@ public Task WriteTokenAsync(JsonToken token, CancellationToken cancellationToken /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public Task WriteTokenAsync(JsonToken token, object value, CancellationToken cancellationToken = default) + public Task WriteTokenAsync(JsonToken token, object? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -691,10 +706,10 @@ public Task WriteTokenAsync(JsonToken token, object value, CancellationToken can return WriteStartArrayAsync(cancellationToken); case JsonToken.StartConstructor: ValidationUtils.ArgumentNotNull(value, nameof(value)); - return WriteStartConstructorAsync(value.ToString(), cancellationToken); + return WriteStartConstructorAsync(value.ToString()!, cancellationToken); case JsonToken.PropertyName: ValidationUtils.ArgumentNotNull(value, nameof(value)); - return WritePropertyNameAsync(value.ToString(), cancellationToken); + return WritePropertyNameAsync(value.ToString()!, cancellationToken); case JsonToken.Comment: return WriteCommentAsync(value?.ToString(), cancellationToken); case JsonToken.Integer: @@ -755,7 +770,7 @@ public Task WriteTokenAsync(JsonToken token, object value, CancellationToken can return WriteValueAsync(guid, cancellationToken); } - return WriteValueAsync((byte[])value, cancellationToken); + return WriteValueAsync((byte[]?)value, cancellationToken); default: throw MiscellaneousUtils.CreateArgumentOutOfRangeException(nameof(token), token, "Unexpected token type."); } @@ -768,7 +783,7 @@ internal virtual async Task WriteTokenAsync(JsonReader reader, bool writeChildre do { // write a JValue date when the constructor is for a date - if (writeDateConstructorAsDate && reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value.ToString(), "Date", StringComparison.Ordinal)) + if (writeDateConstructorAsDate && reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value?.ToString(), "Date", StringComparison.Ordinal)) { await WriteConstructorDateAsync(reader, cancellationToken).ConfigureAwait(false); } @@ -785,7 +800,7 @@ internal virtual async Task WriteTokenAsync(JsonReader reader, bool writeChildre && writeChildren && await reader.ReadAsync(cancellationToken).ConfigureAwait(false)); - if (initialDepth < CalculateWriteTokenFinalDepth(reader)) + if (IsWriteTokenIncomplete(reader, writeChildren, initialDepth)) { throw JsonWriterException.Create(this, "Unexpected end when reading token.", null); } @@ -801,7 +816,7 @@ internal async Task WriteTokenSyncReadingAsync(JsonReader reader, CancellationTo do { // write a JValue date when the constructor is for a date - if (reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value.ToString(), "Date", StringComparison.Ordinal)) + if (reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value?.ToString(), "Date", StringComparison.Ordinal)) { WriteConstructorDate(reader); } @@ -831,7 +846,7 @@ private async Task WriteConstructorDateAsync(JsonReader reader, CancellationToke throw JsonWriterException.Create(this, "Unexpected token when reading date constructor. Expected Integer, got " + reader.TokenType, null); } - DateTime date = DateTimeUtils.ConvertJavaScriptTicksToDateTime((long)reader.Value); + DateTime date = DateTimeUtils.ConvertJavaScriptTicksToDateTime((long)reader.Value!); if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { @@ -929,7 +944,7 @@ public virtual Task WriteValueAsync(byte? value, CancellationToken cancellationT /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteValueAsync(byte[] value, CancellationToken cancellationToken = default) + public virtual Task WriteValueAsync(byte[]? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -1290,7 +1305,7 @@ public virtual Task WriteValueAsync(long? value, CancellationToken cancellationT /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteValueAsync(object value, CancellationToken cancellationToken = default) + public virtual Task WriteValueAsync(object? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -1309,7 +1324,7 @@ public virtual Task WriteValueAsync(object value, CancellationToken cancellation /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual Task WriteValueAsync(sbyte value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) @@ -1329,7 +1344,7 @@ public virtual Task WriteValueAsync(sbyte value, CancellationToken cancellationT /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual Task WriteValueAsync(sbyte? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) @@ -1387,7 +1402,7 @@ public virtual Task WriteValueAsync(short? value, CancellationToken cancellation /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteValueAsync(string value, CancellationToken cancellationToken = default) + public virtual Task WriteValueAsync(string? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -1444,7 +1459,7 @@ public virtual Task WriteValueAsync(TimeSpan? value, CancellationToken cancellat /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual Task WriteValueAsync(uint value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) @@ -1464,7 +1479,7 @@ public virtual Task WriteValueAsync(uint value, CancellationToken cancellationTo /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual Task WriteValueAsync(uint? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) @@ -1484,7 +1499,7 @@ public virtual Task WriteValueAsync(uint? value, CancellationToken cancellationT /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual Task WriteValueAsync(ulong value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) @@ -1504,7 +1519,7 @@ public virtual Task WriteValueAsync(ulong value, CancellationToken cancellationT /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual Task WriteValueAsync(ulong? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) @@ -1524,7 +1539,7 @@ public virtual Task WriteValueAsync(ulong? value, CancellationToken cancellation /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteValueAsync(Uri value, CancellationToken cancellationToken = default) + public virtual Task WriteValueAsync(Uri? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -1543,7 +1558,7 @@ public virtual Task WriteValueAsync(Uri value, CancellationToken cancellationTok /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual Task WriteValueAsync(ushort value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) @@ -1563,7 +1578,7 @@ public virtual Task WriteValueAsync(ushort value, CancellationToken cancellation /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual Task WriteValueAsync(ushort? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) @@ -1781,7 +1796,7 @@ internal static Task WriteValueAsync(JsonWriter writer, PrimitiveTypeCode typeCo } #endif - // write an unknown null value, fix https://github.com/JamesNK/Microsoft.IdentityModel.Json/issues/1460 + // write an unknown null value, fix https://github.com/JamesNK/Newtonsoft.Json/issues/1460 if (value == null) { return writer.WriteNullAsync(cancellationToken); @@ -1792,6 +1807,8 @@ internal static Task WriteValueAsync(JsonWriter writer, PrimitiveTypeCode typeCo } } } +#nullable disable +#pragma warning restore CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly } #endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonWriter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonWriter.cs index af651253cf..117d11754a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonWriter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonWriter.cs @@ -40,6 +40,8 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable +#pragma warning disable CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly /// /// Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data. /// @@ -62,7 +64,7 @@ internal enum State // array that gives a new state based on the current state an the token being written private static readonly State[][] StateArray; - internal static readonly State[][] StateArrayTempate = new[] + internal static readonly State[][] StateArrayTemplate = new[] { // Start PropertyName ObjectStart Object ArrayStart Array ConstructorStart Constructor Closed Error // @@ -78,9 +80,9 @@ internal enum State internal static State[][] BuildStateArray() { - List allStates = StateArrayTempate.ToList(); - State[] errorStates = StateArrayTempate[0]; - State[] valueStates = StateArrayTempate[7]; + List allStates = StateArrayTemplate.ToList(); + State[] errorStates = StateArrayTemplate[0]; + State[] valueStates = StateArrayTemplate[7]; EnumInfo enumValuesAndNames = EnumUtils.GetEnumValuesAndNames(typeof(JsonToken)); @@ -116,7 +118,7 @@ static JsonWriter() StateArray = BuildStateArray(); } - private List _stack; + private List? _stack; private JsonPosition _currentPosition; private State _currentState; private Formatting _formatting; @@ -182,7 +184,9 @@ public WriteState WriteState case State.Start: return WriteState.Start; default: +#pragma warning disable CA1065 // Do not raise exceptions in unexpected locations throw JsonWriterException.Create(this, "Invalid state: " + _currentState, null); +#pragma warning restore CA1065 // Do not raise exceptions in unexpected locations } } } @@ -201,7 +205,7 @@ internal string ContainerPath } /// - /// Gets the path of the writer. + /// Gets the path of the writer. /// public string Path { @@ -218,7 +222,7 @@ public string Path JsonPosition? current = insideContainer ? (JsonPosition?)_currentPosition : null; - return JsonPosition.BuildPath(_stack, current); + return JsonPosition.BuildPath(_stack!, current); } } @@ -226,8 +230,8 @@ public string Path private DateTimeZoneHandling _dateTimeZoneHandling; private StringEscapeHandling _stringEscapeHandling; private FloatFormatHandling _floatFormatHandling; - private string _dateFormatString; - private CultureInfo _culture; + private string? _dateFormatString; + private CultureInfo? _culture; /// /// Gets or sets a value indicating how JSON text output should be formatted. @@ -325,7 +329,7 @@ public FloatFormatHandling FloatFormatHandling /// /// Gets or sets how and values are formatted when writing JSON text. /// - public string DateFormatString + public string? DateFormatString { get => _dateFormatString; set => _dateFormatString = value; @@ -522,7 +526,7 @@ public void WriteToken(JsonReader reader, bool writeChildren) /// A value is only required for tokens that have an associated value, e.g. the property name for . /// null can be passed to the method for tokens that don't have a value, e.g. . /// - public void WriteToken(JsonToken token, object value) + public void WriteToken(JsonToken token, object? value) { switch (token) { @@ -537,11 +541,11 @@ public void WriteToken(JsonToken token, object value) break; case JsonToken.StartConstructor: ValidationUtils.ArgumentNotNull(value, nameof(value)); - WriteStartConstructor(value.ToString()); + WriteStartConstructor(value.ToString()!); break; case JsonToken.PropertyName: ValidationUtils.ArgumentNotNull(value, nameof(value)); - WritePropertyName(value.ToString()); + WritePropertyName(value.ToString()!); break; case JsonToken.Comment: WriteComment(value?.ToString()); @@ -579,8 +583,9 @@ public void WriteToken(JsonToken token, object value) } break; case JsonToken.String: - ValidationUtils.ArgumentNotNull(value, nameof(value)); - WriteValue(value.ToString()); + // Allow for a null string. This matches JTokenReader behavior which can read + // a JsonToken.String with a null value. + WriteValue(value?.ToString()); break; case JsonToken.Boolean: ValidationUtils.ArgumentNotNull(value, nameof(value)); @@ -625,7 +630,7 @@ public void WriteToken(JsonToken token, object value) } else { - WriteValue((byte[])value); + WriteValue((byte[])value!); } break; default: @@ -649,7 +654,7 @@ internal virtual void WriteToken(JsonReader reader, bool writeChildren, bool wri do { // write a JValue date when the constructor is for a date - if (writeDateConstructorAsDate && reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value.ToString(), "Date", StringComparison.Ordinal)) + if (writeDateConstructorAsDate && reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value?.ToString(), "Date", StringComparison.Ordinal)) { WriteConstructorDate(reader); } @@ -666,12 +671,19 @@ internal virtual void WriteToken(JsonReader reader, bool writeChildren, bool wri && writeChildren && reader.Read()); - if (initialDepth < CalculateWriteTokenFinalDepth(reader)) + if (IsWriteTokenIncomplete(reader, writeChildren, initialDepth)) { throw JsonWriterException.Create(this, "Unexpected end when reading token.", null); } } + private bool IsWriteTokenIncomplete(JsonReader reader, bool writeChildren, int initialDepth) + { + int finalDepth = CalculateWriteTokenFinalDepth(reader); + return initialDepth < finalDepth || + (writeChildren && initialDepth == finalDepth && JsonTokenUtils.IsStartToken(reader.TokenType)); + } + private int CalculateWriteTokenInitialDepth(JsonReader reader) { JsonToken type = reader.TokenType; @@ -696,7 +708,7 @@ private int CalculateWriteTokenFinalDepth(JsonReader reader) private void WriteConstructorDate(JsonReader reader) { - if (!JavaScriptUtils.TryGetDateFromConstructorJson(reader, out DateTime dateTime, out string errorMessage)) + if (!JavaScriptUtils.TryGetDateFromConstructorJson(reader, out DateTime dateTime, out string? errorMessage)) { throw JsonWriterException.Create(this, errorMessage, null); } @@ -787,7 +799,7 @@ private int CalculateLevelsToComplete(JsonContainerType type) { int currentLevel = top - i; - if (_stack[currentLevel].Type == type) + if (_stack![currentLevel].Type == type) { levelsToComplete = i + 2; break; @@ -909,7 +921,7 @@ public virtual void WriteUndefined() /// Writes raw JSON without changing the writer's state. /// /// The raw JSON to write. - public virtual void WriteRaw(string json) + public virtual void WriteRaw(string? json) { InternalWriteRaw(); } @@ -918,7 +930,7 @@ public virtual void WriteRaw(string json) /// Writes raw JSON where a value is expected and updates the writer's state. /// /// The raw JSON to write. - public virtual void WriteRawValue(string json) + public virtual void WriteRawValue(string? json) { // hack. want writer to change state as if a value had been written UpdateScopeWithFinishedValue(); @@ -930,7 +942,7 @@ public virtual void WriteRawValue(string json) /// Writes a value. /// /// The value to write. - public virtual void WriteValue(string value) + public virtual void WriteValue(string? value) { InternalWriteValue(JsonToken.String); } @@ -948,7 +960,7 @@ public virtual void WriteValue(int value) /// Writes a value. /// /// The value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual void WriteValue(uint value) { InternalWriteValue(JsonToken.Integer); @@ -967,7 +979,7 @@ public virtual void WriteValue(long value) /// Writes a value. /// /// The value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual void WriteValue(ulong value) { InternalWriteValue(JsonToken.Integer); @@ -1013,7 +1025,7 @@ public virtual void WriteValue(short value) /// Writes a value. /// /// The value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual void WriteValue(ushort value) { InternalWriteValue(JsonToken.Integer); @@ -1041,7 +1053,7 @@ public virtual void WriteValue(byte value) /// Writes a value. /// /// The value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual void WriteValue(sbyte value) { InternalWriteValue(JsonToken.Integer); @@ -1114,7 +1126,7 @@ public virtual void WriteValue(int? value) /// Writes a of value. /// /// The of value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual void WriteValue(uint? value) { if (value == null) @@ -1147,7 +1159,7 @@ public virtual void WriteValue(long? value) /// Writes a of value. /// /// The of value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual void WriteValue(ulong? value) { if (value == null) @@ -1228,7 +1240,7 @@ public virtual void WriteValue(short? value) /// Writes a of value. /// /// The of value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual void WriteValue(ushort? value) { if (value == null) @@ -1277,7 +1289,7 @@ public virtual void WriteValue(byte? value) /// Writes a of value. /// /// The of value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public virtual void WriteValue(sbyte? value) { if (value == null) @@ -1376,7 +1388,7 @@ public virtual void WriteValue(TimeSpan? value) /// Writes a [] value. /// /// The [] value to write. - public virtual void WriteValue(byte[] value) + public virtual void WriteValue(byte[]? value) { if (value == null) { @@ -1392,7 +1404,7 @@ public virtual void WriteValue(byte[] value) /// Writes a value. /// /// The value to write. - public virtual void WriteValue(Uri value) + public virtual void WriteValue(Uri? value) { if (value == null) { @@ -1409,7 +1421,7 @@ public virtual void WriteValue(Uri value) /// An error will raised if the value cannot be written as a single JSON token. /// /// The value to write. - public virtual void WriteValue(object value) + public virtual void WriteValue(object? value) { if (value == null) { @@ -1435,7 +1447,7 @@ public virtual void WriteValue(object value) /// Writes a comment /*...*/ containing the specified text. /// /// Text to place inside the comment. - public virtual void WriteComment(string text) + public virtual void WriteComment(string? text) { InternalWriteComment(); } @@ -1449,7 +1461,9 @@ public virtual void WriteWhitespace(string ws) InternalWriteWhitespace(ws); } +#pragma warning disable CA1063 // Implement IDisposable Correctly void IDisposable.Dispose() +#pragma warning restore CA1063 // Implement IDisposable Correctly { Dispose(true); GC.SuppressFinalize(this); @@ -1647,7 +1661,7 @@ internal static void WriteValue(JsonWriter writer, PrimitiveTypeCode typeCode, o } #endif - // write an unknown null value, fix https://github.com/JamesNK/Microsoft.IdentityModel.Json/issues/1460 + // write an unknown null value, fix https://github.com/JamesNK/Newtonsoft.Json/issues/1460 if (value == null) { writer.WriteNull(); @@ -1778,4 +1792,6 @@ internal void InternalWriteComment() AutoComplete(JsonToken.Comment); } } -} \ No newline at end of file +#nullable disable +#pragma warning restore CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonWriterException.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonWriterException.cs index bbfba9c112..1dc33ae37d 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonWriterException.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/JsonWriterException.cs @@ -30,6 +30,7 @@ namespace Microsoft.IdentityModel.Json { +#nullable enable /// /// The exception thrown when an error occurs while writing JSON text. /// @@ -42,7 +43,7 @@ internal class JsonWriterException : JsonException /// Gets the path to the JSON where the error occurred. /// /// The path to the JSON where the error occurred. - public string Path { get; } + public string? Path { get; } /// /// Initializes a new instance of the class. @@ -93,22 +94,23 @@ public JsonWriterException(SerializationInfo info, StreamingContext context) /// The error message that explains the reason for the exception. /// The path to the JSON where the error occurred. /// The exception that is the cause of the current exception, or null if no inner exception is specified. - public JsonWriterException(string message, string path, Exception innerException) + public JsonWriterException(string message, string path, Exception? innerException) : base(message, innerException) { Path = path; } - internal static JsonWriterException Create(JsonWriter writer, string message, Exception ex) + internal static JsonWriterException Create(JsonWriter writer, string message, Exception? ex) { return Create(writer.ContainerPath, message, ex); } - internal static JsonWriterException Create(string path, string message, Exception ex) + internal static JsonWriterException Create(string path, string message, Exception? ex) { message = JsonPosition.FormatMessage(null, path, message); return new JsonWriterException(message, path, ex); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/CommentHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/CommentHandling.cs index 4fd8bcf488..eea593959b 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/CommentHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/CommentHandling.cs @@ -40,4 +40,4 @@ internal enum CommentHandling /// Load = 1 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/DuplicatePropertyNameHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/DuplicatePropertyNameHandling.cs new file mode 100644 index 0000000000..d7800d4057 --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/DuplicatePropertyNameHandling.cs @@ -0,0 +1,46 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Microsoft.IdentityModel.Json.Linq +{ + /// + /// Specifies how duplicate property names are handled when loading JSON. + /// + internal enum DuplicatePropertyNameHandling + { + /// + /// Replace the existing value when there is a duplicate property. The value of the last property in the JSON object will be used. + /// + Replace = 0, + /// + /// Ignore the new value when there is a duplicate property. The value of the first property in the JSON object will be used. + /// + Ignore = 1, + /// + /// Throw a when a duplicate property is encountered. + /// + Error = 2 + } +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/Extensions.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/Extensions.cs index fb880d2da0..1507a21edd 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/Extensions.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/Extensions.cs @@ -27,6 +27,8 @@ using System.Collections.Generic; using Microsoft.IdentityModel.Json.Utilities; using System.Globalization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else @@ -36,6 +38,7 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable /// /// Contains the LINQ to JSON extension methods. /// @@ -111,9 +114,9 @@ public static IJEnumerable Properties(this IEnumerable sourc /// An of that contains the source collection. /// The token key. /// An of that contains the values of every token in the source collection with the given key. - public static IJEnumerable Values(this IEnumerable source, object key) + public static IJEnumerable Values(this IEnumerable source, object? key) { - return Values(source, key).AsJEnumerable(); + return Values(source, key)!.AsJEnumerable(); } /// @@ -133,7 +136,7 @@ public static IJEnumerable Values(this IEnumerable source) /// An of that contains the source collection. /// The token key. /// An that contains the converted values of every token in the source collection with the given key. - public static IEnumerable Values(this IEnumerable source, object key) + public static IEnumerable Values(this IEnumerable source, object key) { return Values(source, key); } @@ -144,7 +147,7 @@ public static IEnumerable Values(this IEnumerable source, object k /// The type to convert the values to. /// An of that contains the source collection. /// An that contains the converted values of every token in the source collection. - public static IEnumerable Values(this IEnumerable source) + public static IEnumerable Values(this IEnumerable source) { return Values(source, null); } @@ -155,7 +158,7 @@ public static IEnumerable Values(this IEnumerable source) /// The type to convert the value to. /// A cast as a of . /// A converted value. - public static U Value(this IEnumerable value) + public static U? Value(this IEnumerable value) { return value.Value(); } @@ -167,7 +170,7 @@ public static U Value(this IEnumerable value) /// The type to convert the value to. /// A cast as a of . /// A converted value. - public static U Value(this IEnumerable value) where T : JToken + public static U? Value(this IEnumerable value) where T : JToken { ValidationUtils.ArgumentNotNull(value, nameof(value)); @@ -179,7 +182,7 @@ public static U Value(this IEnumerable value) where T : JToken return token.Convert(); } - internal static IEnumerable Values(this IEnumerable source, object key) where T : JToken + internal static IEnumerable Values(this IEnumerable source, object? key) where T : JToken { ValidationUtils.ArgumentNotNull(source, nameof(source)); @@ -204,7 +207,7 @@ internal static IEnumerable Values(this IEnumerable source, object k { foreach (T token in source) { - JToken value = token[key]; + JToken? value = token[key]; if (value != null) { yield return value.Convert(); @@ -224,7 +227,7 @@ internal static IEnumerable Values(this IEnumerable source, object k /// An of that contains the values of every token in the source collection. public static IJEnumerable Children(this IEnumerable source) where T : JToken { - return Children(source).AsJEnumerable(); + return Children(source)!.AsJEnumerable(); } /// @@ -234,14 +237,14 @@ public static IJEnumerable Children(this IEnumerable source) where /// The type to convert the values to. /// The source collection type. /// An that contains the converted values of every token in the source collection. - public static IEnumerable Children(this IEnumerable source) where T : JToken + public static IEnumerable Children(this IEnumerable source) where T : JToken { ValidationUtils.ArgumentNotNull(source, nameof(source)); return source.SelectMany(c => c.Children()).Convert(); } - internal static IEnumerable Convert(this IEnumerable source) where T : JToken + internal static IEnumerable Convert(this IEnumerable source) where T : JToken { ValidationUtils.ArgumentNotNull(source, nameof(source)); @@ -251,7 +254,7 @@ internal static IEnumerable Convert(this IEnumerable source) where T } } - internal static U Convert(this T token) where T : JToken + internal static U? Convert(this T token) where T : JToken? { if (token == null) { @@ -285,10 +288,10 @@ internal static U Convert(this T token) where T : JToken return default; } - targetType = Nullable.GetUnderlyingType(targetType); + targetType = Nullable.GetUnderlyingType(targetType)!; } - return (U)System.Convert.ChangeType(value.Value, targetType, CultureInfo.InvariantCulture); + return (U?)System.Convert.ChangeType(value.Value, targetType, CultureInfo.InvariantCulture); } } @@ -315,7 +318,7 @@ public static IJEnumerable AsJEnumerable(this IEnumerable source) where { if (source == null) { - return null; + return null!; } else if (source is IJEnumerable customEnumerable) { @@ -327,4 +330,5 @@ public static IJEnumerable AsJEnumerable(this IEnumerable source) where } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/IJEnumerable.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/IJEnumerable.cs index a1443fff94..93e20e1059 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/IJEnumerable.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/IJEnumerable.cs @@ -43,4 +43,4 @@ internal interface IJEnumerable< /// IJEnumerable this[object key] { get; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JArray.Async.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JArray.Async.cs index d4e035a9da..dd32a6ac39 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JArray.Async.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JArray.Async.cs @@ -32,6 +32,7 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable internal partial class JArray { /// @@ -54,7 +55,7 @@ public override async Task WriteToAsync(JsonWriter writer, CancellationToken can } /// - /// Asynchronously loads a from a . + /// Asynchronously loads a from a . /// /// A that will be read for the content of the . /// If this is null, default load settings will be used. @@ -66,14 +67,14 @@ public override async Task WriteToAsync(JsonWriter writer, CancellationToken can } /// - /// Asynchronously loads a from a . + /// Asynchronously loads a from a . /// /// A that will be read for the content of the . /// The used to load the JSON. /// If this is null, default load settings will be used. /// The token to monitor for cancellation requests. The default value is . /// A representing the asynchronous load. The property contains the JSON that was read from the specified . - public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { if (reader.TokenType == JsonToken.None) { @@ -98,6 +99,7 @@ public override async Task WriteToAsync(JsonWriter writer, CancellationToken can return a; } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JArray.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JArray.cs index 1d3180f190..a5a18bc502 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JArray.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JArray.cs @@ -32,6 +32,7 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable /// /// Represents a JSON array. /// @@ -99,7 +100,7 @@ internal override JToken CloneToken() } /// - /// Loads an from a . + /// Loads an from a . /// /// A that will be read for the content of the . /// A that contains the JSON that was read from the specified . @@ -109,13 +110,13 @@ internal override JToken CloneToken() } /// - /// Loads an from a . + /// Loads an from a . /// /// A that will be read for the content of the . /// The used to load the JSON. /// If this is null, default load settings will be used. /// A that contains the JSON that was read from the specified . - public new static JArray Load(JsonReader reader, JsonLoadSettings settings) + public new static JArray Load(JsonReader reader, JsonLoadSettings? settings) { if (reader.TokenType == JsonToken.None) { @@ -163,7 +164,7 @@ internal override JToken CloneToken() /// /// /// - public new static JArray Parse(string json, JsonLoadSettings settings) + public new static JArray Parse(string json, JsonLoadSettings? settings) { using (JsonReader reader = new JsonTextReader(new StringReader(json))) { @@ -227,7 +228,7 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter /// Gets the with the specified key. /// /// The with the specified key. - public override JToken this[object key] + public override JToken? this[object key] { get { @@ -263,14 +264,19 @@ public JToken this[int index] set => SetItem(index, value); } - internal override int IndexOfItem(JToken item) + internal override int IndexOfItem(JToken? item) { + if (item == null) + { + return -1; + } + return _values.IndexOfReference(item); } - internal override void MergeItem(object content, JsonMergeSettings settings) + internal override void MergeItem(object content, JsonMergeSettings? settings) { - IEnumerable a = (IsMultiContent(content) || content is JArray) + IEnumerable? a = (IsMultiContent(content) || content is JArray) ? (IEnumerable)content : null; if (a == null) @@ -395,4 +401,5 @@ internal override int GetDeepHashCode() return ContentsHashCode(); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JConstructor.Async.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JConstructor.Async.cs index d256d96610..7c64a53ca3 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JConstructor.Async.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JConstructor.Async.cs @@ -32,6 +32,7 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable internal partial class JConstructor { /// @@ -43,7 +44,7 @@ internal partial class JConstructor /// A that represents the asynchronous write operation. public override async Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters) { - await writer.WriteStartConstructorAsync(_name, cancellationToken).ConfigureAwait(false); + await writer.WriteStartConstructorAsync(_name ?? string.Empty, cancellationToken).ConfigureAwait(false); for (int i = 0; i < _values.Count; i++) { @@ -76,7 +77,7 @@ public override async Task WriteToAsync(JsonWriter writer, CancellationToken can /// /// A that represents the asynchronous load. The /// property returns a that contains the JSON that was read from the specified . - public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { if (reader.TokenType == JsonToken.None) { @@ -93,7 +94,7 @@ public override async Task WriteToAsync(JsonWriter writer, CancellationToken can throw JsonReaderException.Create(reader, "Error reading JConstructor from JsonReader. Current JsonReader item is not a constructor: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - JConstructor c = new JConstructor((string)reader.Value); + JConstructor c = new JConstructor((string)reader.Value!); c.SetLineInfo(reader as IJsonLineInfo, settings); await c.ReadTokenFromAsync(reader, settings, cancellationToken).ConfigureAwait(false); @@ -101,6 +102,7 @@ public override async Task WriteToAsync(JsonWriter writer, CancellationToken can return c; } } +#nullable disable } #endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JConstructor.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JConstructor.cs index c4c27e5ebe..686acafeb5 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JConstructor.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JConstructor.cs @@ -31,12 +31,13 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable /// /// Represents a JSON constructor. /// internal partial class JConstructor : JContainer { - private string _name; + private string? _name; private readonly List _values = new List(); /// @@ -45,12 +46,17 @@ internal partial class JConstructor : JContainer /// The container's children tokens. protected override IList ChildrenTokens => _values; - internal override int IndexOfItem(JToken item) + internal override int IndexOfItem(JToken? item) { + if (item == null) + { + return -1; + } + return _values.IndexOfReference(item); } - internal override void MergeItem(object content, JsonMergeSettings settings) + internal override void MergeItem(object content, JsonMergeSettings? settings) { if (!(content is JConstructor c)) { @@ -68,7 +74,7 @@ internal override void MergeItem(object content, JsonMergeSettings settings) /// Gets or sets the name of this constructor. /// /// The constructor name. - public string Name + public string? Name { get => _name; set => _name = value; @@ -154,7 +160,7 @@ internal override JToken CloneToken() /// A collection of which will be used when writing the token. public override void WriteTo(JsonWriter writer, params JsonConverter[] converters) { - writer.WriteStartConstructor(_name); + writer.WriteStartConstructor(_name!); int count = _values.Count; for (int i = 0; i < count; i++) @@ -169,7 +175,7 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter /// Gets the with the specified key. /// /// The with the specified key. - public override JToken this[object key] + public override JToken? this[object key] { get { @@ -197,7 +203,13 @@ public override JToken this[object key] internal override int GetDeepHashCode() { - return _name.GetHashCode() ^ ContentsHashCode(); + int hash; +#if HAVE_GETHASHCODE_STRING_COMPARISON + hash = _name?.GetHashCode(StringComparison.Ordinal) ?? 0; +#else + hash = _name?.GetHashCode() ?? 0; +#endif + return hash ^ ContentsHashCode(); } /// @@ -217,7 +229,7 @@ internal override int GetDeepHashCode() /// The used to load the JSON. /// If this is null, default load settings will be used. /// A that contains the JSON that was read from the specified . - public new static JConstructor Load(JsonReader reader, JsonLoadSettings settings) + public new static JConstructor Load(JsonReader reader, JsonLoadSettings? settings) { if (reader.TokenType == JsonToken.None) { @@ -234,7 +246,7 @@ internal override int GetDeepHashCode() throw JsonReaderException.Create(reader, "Error reading JConstructor from JsonReader. Current JsonReader item is not a constructor: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - JConstructor c = new JConstructor((string)reader.Value); + JConstructor c = new JConstructor((string)reader.Value!); c.SetLineInfo(reader as IJsonLineInfo, settings); c.ReadTokenFrom(reader, settings); @@ -242,4 +254,5 @@ internal override int GetDeepHashCode() return c; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JContainer.Async.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JContainer.Async.cs index c7feb2fad7..1c9e7715fe 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JContainer.Async.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JContainer.Async.cs @@ -26,6 +26,7 @@ #if HAVE_ASYNC using System; +using System.Diagnostics; using System.Globalization; using System.Threading; using System.Threading.Tasks; @@ -33,9 +34,10 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable internal abstract partial class JContainer { - internal async Task ReadTokenFromAsync(JsonReader reader, JsonLoadSettings options, CancellationToken cancellationToken = default) + internal async Task ReadTokenFromAsync(JsonReader reader, JsonLoadSettings? options, CancellationToken cancellationToken = default) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); int startDepth = reader.Depth; @@ -53,11 +55,11 @@ internal async Task ReadTokenFromAsync(JsonReader reader, JsonLoadSettings optio } } - private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { - IJsonLineInfo lineInfo = reader as IJsonLineInfo; + IJsonLineInfo? lineInfo = reader as IJsonLineInfo; - JContainer parent = this; + JContainer? parent = this; do { @@ -71,6 +73,8 @@ private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings sett parent = parent.Parent; } + MiscellaneousUtils.Assert(parent != null); + switch (reader.TokenType) { case JsonToken.None: @@ -106,7 +110,7 @@ private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings sett parent = parent.Parent; break; case JsonToken.StartConstructor: - JConstructor constructor = new JConstructor(reader.Value.ToString()); + JConstructor constructor = new JConstructor(reader.Value!.ToString()!); constructor.SetLineInfo(lineInfo, settings); parent.Add(constructor); parent = constructor; @@ -132,7 +136,7 @@ private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings sett case JsonToken.Comment: if (settings != null && settings.CommentHandling == CommentHandling.Load) { - v = JValue.CreateComment(reader.Value.ToString()); + v = JValue.CreateComment(reader.Value!.ToString()); v.SetLineInfo(lineInfo, settings); parent.Add(v); } @@ -148,21 +152,15 @@ private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings sett parent.Add(v); break; case JsonToken.PropertyName: - string propertyName = reader.Value.ToString(); - JProperty property = new JProperty(propertyName); - property.SetLineInfo(lineInfo, settings); - JObject parentObject = (JObject)parent; - // handle multiple properties with the same name in JSON - JProperty existingPropertyWithName = parentObject.Property(propertyName); - if (existingPropertyWithName == null) + JProperty? property = ReadProperty(reader, settings, lineInfo, parent); + if (property != null) { - parent.Add(property); + parent = property; } else { - existingPropertyWithName.Replace(property); + await reader.SkipAsync().ConfigureAwait(false); } - parent = property; break; default: throw new InvalidOperationException("The JsonReader should not be on a token of type {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); @@ -170,6 +168,7 @@ private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings sett } while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)); } } +#nullable disable } #endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JContainer.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JContainer.cs index e3d894bd55..4f64973c53 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JContainer.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JContainer.cs @@ -33,15 +33,18 @@ using System.Collections; using System.Globalization; using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else using System.Linq; - #endif namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable /// /// Represents a token that can contain other tokens. /// @@ -55,8 +58,8 @@ namespace Microsoft.IdentityModel.Json.Linq #endif { #if HAVE_COMPONENT_MODEL - internal ListChangedEventHandler _listChanged; - internal AddingNewEventHandler _addingNew; + internal ListChangedEventHandler? _listChanged; + internal AddingNewEventHandler? _addingNew; /// /// Occurs when the list changes or an item in the list changes. @@ -77,12 +80,12 @@ public event AddingNewEventHandler AddingNew } #endif #if HAVE_INOTIFY_COLLECTION_CHANGED - internal NotifyCollectionChangedEventHandler _collectionChanged; + internal NotifyCollectionChangedEventHandler? _collectionChanged; /// /// Occurs when the items list of the collection has changed, or the collection is reset. /// - public event NotifyCollectionChangedEventHandler CollectionChanged + public event NotifyCollectionChangedEventHandler? CollectionChanged { add { _collectionChanged += value; } remove { _collectionChanged -= value; } @@ -95,7 +98,7 @@ public event NotifyCollectionChangedEventHandler CollectionChanged /// The container's children tokens. protected abstract IList ChildrenTokens { get; } - private object _syncRoot; + private object? _syncRoot; #if (HAVE_COMPONENT_MODEL || HAVE_INOTIFY_COLLECTION_CHANGED) private bool _busy; #endif @@ -112,9 +115,11 @@ internal JContainer(JContainer other) int i = 0; foreach (JToken child in other) { - AddInternal(i, child, false); + TryAddInternal(i, child, false); i++; } + + CopyAnnotations(this, other); } internal void CheckReentrancy() @@ -148,7 +153,7 @@ protected virtual void OnAddingNew(AddingNewEventArgs e) /// The instance containing the event data. protected virtual void OnListChanged(ListChangedEventArgs e) { - ListChangedEventHandler handler = _listChanged; + ListChangedEventHandler? handler = _listChanged; if (handler != null) { @@ -171,7 +176,7 @@ protected virtual void OnListChanged(ListChangedEventArgs e) /// The instance containing the event data. protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { - NotifyCollectionChangedEventHandler handler = _collectionChanged; + NotifyCollectionChangedEventHandler? handler = _collectionChanged; if (handler != null) { @@ -228,7 +233,7 @@ internal bool ContentsEqual(JContainer container) /// /// A containing the first child token of the . /// - public override JToken First + public override JToken? First { get { @@ -243,7 +248,7 @@ public override JToken First /// /// A containing the last child token of the . /// - public override JToken Last + public override JToken? Last { get { @@ -271,7 +276,7 @@ public override JEnumerable Children() /// /// A containing the child values of this , in document order. /// - public override IEnumerable Values() + public override IEnumerable Values() where T : default { return ChildrenTokens.Convert(); } @@ -314,12 +319,12 @@ internal IEnumerable GetDescendants(bool self) } } - internal bool IsMultiContent(object content) + internal bool IsMultiContent([NotNullWhen(true)]object? content) { return (content is IEnumerable && !(content is string) && !(content is JToken) && !(content is byte[])); } - internal JToken EnsureParentToken(JToken item, bool skipParentCheck) + internal JToken EnsureParentToken(JToken? item, bool skipParentCheck) { if (item == null) { @@ -343,9 +348,9 @@ internal JToken EnsureParentToken(JToken item, bool skipParentCheck) return item; } - internal abstract int IndexOfItem(JToken item); + internal abstract int IndexOfItem(JToken? item); - internal virtual void InsertItem(int index, JToken item, bool skipParentCheck) + internal virtual bool InsertItem(int index, JToken? item, bool skipParentCheck) { IList children = ChildrenTokens; @@ -358,9 +363,9 @@ internal virtual void InsertItem(int index, JToken item, bool skipParentCheck) item = EnsureParentToken(item, skipParentCheck); - JToken previous = (index == 0) ? null : children[index - 1]; + JToken? previous = (index == 0) ? null : children[index - 1]; // haven't inserted new token yet so next token is still at the inserting index - JToken next = (index == children.Count) ? null : children[index]; + JToken? next = (index == children.Count) ? null : children[index]; ValidateToken(item, null); @@ -392,6 +397,8 @@ internal virtual void InsertItem(int index, JToken item, bool skipParentCheck) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); } #endif + + return true; } internal virtual void RemoveItemAt(int index) @@ -410,8 +417,8 @@ internal virtual void RemoveItemAt(int index) CheckReentrancy(); JToken item = children[index]; - JToken previous = (index == 0) ? null : children[index - 1]; - JToken next = (index == children.Count - 1) ? null : children[index + 1]; + JToken? previous = (index == 0) ? null : children[index - 1]; + JToken? next = (index == children.Count - 1) ? null : children[index + 1]; if (previous != null) { @@ -442,13 +449,16 @@ internal virtual void RemoveItemAt(int index) #endif } - internal virtual bool RemoveItem(JToken item) + internal virtual bool RemoveItem(JToken? item) { - int index = IndexOfItem(item); - if (index >= 0) + if (item != null) { - RemoveItemAt(index); - return true; + int index = IndexOfItem(item); + if (index >= 0) + { + RemoveItemAt(index); + return true; + } } return false; @@ -459,7 +469,7 @@ internal virtual JToken GetItem(int index) return ChildrenTokens[index]; } - internal virtual void SetItem(int index, JToken item) + internal virtual void SetItem(int index, JToken? item) { IList children = ChildrenTokens; @@ -485,8 +495,8 @@ internal virtual void SetItem(int index, JToken item) ValidateToken(item, existing); - JToken previous = (index == 0) ? null : children[index - 1]; - JToken next = (index == children.Count - 1) ? null : children[index + 1]; + JToken? previous = (index == 0) ? null : children[index - 1]; + JToken? next = (index == children.Count - 1) ? null : children[index + 1]; item.Parent = this; @@ -562,7 +572,7 @@ internal virtual void ReplaceItem(JToken existing, JToken replacement) SetItem(index, replacement); } - internal virtual bool ContainsItem(JToken item) + internal virtual bool ContainsItem(JToken? item) { return (IndexOfItem(item) != -1); } @@ -594,14 +604,14 @@ internal virtual void CopyItemsTo(Array array, int arrayIndex) } } - internal static bool IsTokenUnchanged(JToken currentValue, JToken newValue) + internal static bool IsTokenUnchanged(JToken currentValue, JToken? newValue) { if (currentValue is JValue v1) { - // null will get turned into a JValue of type null - if (v1.Type == JTokenType.Null && newValue == null) + if (newValue == null) { - return true; + // null will get turned into a JValue of type null + return v1.Type == JTokenType.Null; } return v1.Equals(newValue); @@ -610,7 +620,7 @@ internal static bool IsTokenUnchanged(JToken currentValue, JToken newValue) return false; } - internal virtual void ValidateToken(JToken o, JToken existing) + internal virtual void ValidateToken(JToken o, JToken? existing) { ValidationUtils.ArgumentNotNull(o, nameof(o)); @@ -624,26 +634,31 @@ internal virtual void ValidateToken(JToken o, JToken existing) /// Adds the specified content as children of this . /// /// The content to be added. - public virtual void Add(object content) + public virtual void Add(object? content) + { + TryAddInternal(ChildrenTokens.Count, content, false); + } + + internal bool TryAdd(object? content) { - AddInternal(ChildrenTokens.Count, content, false); + return TryAddInternal(ChildrenTokens.Count, content, false); } internal void AddAndSkipParentCheck(JToken token) { - AddInternal(ChildrenTokens.Count, token, true); + TryAddInternal(ChildrenTokens.Count, token, true); } /// /// Adds the specified content as the first children of this . /// /// The content to be added. - public void AddFirst(object content) + public void AddFirst(object? content) { - AddInternal(0, content, false); + TryAddInternal(0, content, false); } - internal void AddInternal(int index, object content, bool skipParentCheck) + internal bool TryAddInternal(int index, object? content, bool skipParentCheck) { if (IsMultiContent(content)) { @@ -652,19 +667,21 @@ internal void AddInternal(int index, object content, bool skipParentCheck) int multiIndex = index; foreach (object c in enumerable) { - AddInternal(multiIndex, c, skipParentCheck); + TryAddInternal(multiIndex, c, skipParentCheck); multiIndex++; } + + return true; } else { JToken item = CreateFromContent(content); - InsertItem(index, item, skipParentCheck); + return InsertItem(index, item, skipParentCheck); } } - internal static JToken CreateFromContent(object content) + internal static JToken CreateFromContent(object? content) { if (content is JToken token) { @@ -701,15 +718,21 @@ public void RemoveAll() ClearItems(); } - internal abstract void MergeItem(object content, JsonMergeSettings settings); + internal abstract void MergeItem(object content, JsonMergeSettings? settings); /// /// Merge the specified content into this . /// /// The content to be merged. - public void Merge(object content) + public void Merge(object? content) { - MergeItem(content, new JsonMergeSettings()); + if (content == null) + { + return; + } + + ValidateContent(content); + MergeItem(content, null); } /// @@ -717,12 +740,32 @@ public void Merge(object content) /// /// The content to be merged. /// The used to merge the content. - public void Merge(object content, JsonMergeSettings settings) + public void Merge(object? content, JsonMergeSettings? settings) { + if (content == null) + { + return; + } + + ValidateContent(content); MergeItem(content, settings); } - internal void ReadTokenFrom(JsonReader reader, JsonLoadSettings options) + private void ValidateContent(object content) + { + if (content.GetType().IsSubclassOf(typeof(JToken))) + { + return; + } + if (IsMultiContent(content)) + { + return; + } + + throw new ArgumentException("Could not determine JSON object type for type {0}.".FormatWith(CultureInfo.InvariantCulture, content.GetType()), nameof(content)); + } + + internal void ReadTokenFrom(JsonReader reader, JsonLoadSettings? options) { int startDepth = reader.Depth; @@ -741,12 +784,12 @@ internal void ReadTokenFrom(JsonReader reader, JsonLoadSettings options) } } - internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) + internal void ReadContentFrom(JsonReader r, JsonLoadSettings? settings) { ValidationUtils.ArgumentNotNull(r, nameof(r)); - IJsonLineInfo lineInfo = r as IJsonLineInfo; + IJsonLineInfo? lineInfo = r as IJsonLineInfo; - JContainer parent = this; + JContainer? parent = this; do { @@ -760,6 +803,8 @@ internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) parent = parent.Parent; } + MiscellaneousUtils.Assert(parent != null); + switch (r.TokenType) { case JsonToken.None: @@ -795,7 +840,7 @@ internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) parent = parent.Parent; break; case JsonToken.StartConstructor: - JConstructor constructor = new JConstructor(r.Value.ToString()); + JConstructor constructor = new JConstructor(r.Value!.ToString()!); constructor.SetLineInfo(lineInfo, settings); parent.Add(constructor); parent = constructor; @@ -821,7 +866,7 @@ internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) case JsonToken.Comment: if (settings != null && settings.CommentHandling == CommentHandling.Load) { - v = JValue.CreateComment(r.Value.ToString()); + v = JValue.CreateComment(r.Value!.ToString()); v.SetLineInfo(lineInfo, settings); parent.Add(v); } @@ -837,21 +882,15 @@ internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) parent.Add(v); break; case JsonToken.PropertyName: - string propertyName = r.Value.ToString(); - JProperty property = new JProperty(propertyName); - property.SetLineInfo(lineInfo, settings); - JObject parentObject = (JObject)parent; - // handle multiple properties with the same name in JSON - JProperty existingPropertyWithName = parentObject.Property(propertyName); - if (existingPropertyWithName == null) + JProperty? property = ReadProperty(r, settings, lineInfo, parent); + if (property != null) { - parent.Add(property); + parent = property; } else { - existingPropertyWithName.Replace(property); + r.Skip(); } - parent = property; break; default: throw new InvalidOperationException("The JsonReader should not be on a token of type {0}.".FormatWith(CultureInfo.InvariantCulture, r.TokenType)); @@ -859,6 +898,40 @@ internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) } while (r.Read()); } + private static JProperty? ReadProperty(JsonReader r, JsonLoadSettings? settings, IJsonLineInfo? lineInfo, JContainer parent) + { + DuplicatePropertyNameHandling duplicatePropertyNameHandling = settings?.DuplicatePropertyNameHandling ?? DuplicatePropertyNameHandling.Replace; + + JObject parentObject = (JObject)parent; + string propertyName = r.Value!.ToString()!; + JProperty? existingPropertyWithName = parentObject.Property(propertyName, StringComparison.Ordinal); + if (existingPropertyWithName != null) + { + if (duplicatePropertyNameHandling == DuplicatePropertyNameHandling.Ignore) + { + return null; + } + else if (duplicatePropertyNameHandling == DuplicatePropertyNameHandling.Error) + { + throw JsonReaderException.Create(r, "Property with the name '{0}' already exists in the current JSON object.".FormatWith(CultureInfo.InvariantCulture, propertyName)); + } + } + + JProperty property = new JProperty(propertyName); + property.SetLineInfo(lineInfo, settings); + // handle multiple properties with the same name in JSON + if (existingPropertyWithName == null) + { + parent.Add(property); + } + else + { + existingPropertyWithName.Replace(property); + } + + return property; + } + internal int ContentsHashCode() { int hashCode = 0; @@ -877,8 +950,9 @@ string ITypedList.GetListName(PropertyDescriptor[] listAccessors) PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors) { - ICustomTypeDescriptor d = First as ICustomTypeDescriptor; - return d?.GetProperties(); + ICustomTypeDescriptor? d = First as ICustomTypeDescriptor; + + return d?.GetProperties() ?? new PropertyDescriptorCollection(CollectionUtils.ArrayEmpty()); } #endif @@ -934,7 +1008,7 @@ bool ICollection.Remove(JToken item) } #endregion - private JToken EnsureValue(object value) + private JToken? EnsureValue(object? value) { if (value == null) { @@ -950,7 +1024,7 @@ private JToken EnsureValue(object value) } #region IList Members - int IList.Add(object value) + int IList.Add(object? value) { Add(EnsureValue(value)); return Count - 1; @@ -961,17 +1035,17 @@ void IList.Clear() ClearItems(); } - bool IList.Contains(object value) + bool IList.Contains(object? value) { return ContainsItem(EnsureValue(value)); } - int IList.IndexOf(object value) + int IList.IndexOf(object? value) { return IndexOfItem(EnsureValue(value)); } - void IList.Insert(int index, object value) + void IList.Insert(int index, object? value) { InsertItem(index, EnsureValue(value), false); } @@ -980,7 +1054,7 @@ void IList.Insert(int index, object value) bool IList.IsReadOnly => false; - void IList.Remove(object value) + void IList.Remove(object? value) { RemoveItem(EnsureValue(value)); } @@ -990,7 +1064,7 @@ void IList.RemoveAt(int index) RemoveItemAt(index); } - object IList.this[int index] + object? IList.this[int index] { get => GetItem(index); set => SetItem(index, EnsureValue(value)); @@ -1080,7 +1154,7 @@ void IBindingList.RemoveSort() ListSortDirection IBindingList.SortDirection => ListSortDirection.Ascending; - PropertyDescriptor IBindingList.SortProperty => null; + PropertyDescriptor? IBindingList.SortProperty => null; bool IBindingList.SupportsChangeNotification => true; @@ -1090,25 +1164,27 @@ void IBindingList.RemoveSort() #endif #endregion - internal static void MergeEnumerableContent(JContainer target, IEnumerable content, JsonMergeSettings settings) + internal static void MergeEnumerableContent(JContainer target, IEnumerable content, JsonMergeSettings? settings) { - switch (settings.MergeArrayHandling) + switch (settings?.MergeArrayHandling ?? MergeArrayHandling.Concat) { case MergeArrayHandling.Concat: - foreach (JToken item in content) + foreach (object item in content) { - target.Add(item); + target.Add(CreateFromContent(item)); } break; case MergeArrayHandling.Union: #if HAVE_HASH_SET HashSet items = new HashSet(target, EqualityComparer); - foreach (JToken item in content) + foreach (object item in content) { - if (items.Add(item)) + JToken contentItem = CreateFromContent(item); + + if (items.Add(contentItem)) { - target.Add(item); + target.Add(contentItem); } } #else @@ -1118,21 +1194,27 @@ internal static void MergeEnumerableContent(JContainer target, IEnumerable conte items[t] = true; } - foreach (JToken item in content) + foreach (object item in content) { - if (!items.ContainsKey(item)) + JToken contentItem = CreateFromContent(item); + + if (!items.ContainsKey(contentItem)) { - items[item] = true; - target.Add(item); + items[contentItem] = true; + target.Add(contentItem); } } #endif break; case MergeArrayHandling.Replace: + if (target == content) + { + break; + } target.ClearItems(); - foreach (JToken item in content) + foreach (object item in content) { - target.Add(item); + target.Add(CreateFromContent(item)); } break; case MergeArrayHandling.Merge: @@ -1141,7 +1223,7 @@ internal static void MergeEnumerableContent(JContainer target, IEnumerable conte { if (i < target.Count) { - JToken sourceItem = target[i]; + JToken? sourceItem = target[i]; if (sourceItem is JContainer existingContainer) { @@ -1161,7 +1243,7 @@ internal static void MergeEnumerableContent(JContainer target, IEnumerable conte } else { - target.Add(targetItem); + target.Add(CreateFromContent(targetItem)); } i++; @@ -1172,4 +1254,5 @@ internal static void MergeEnumerableContent(JContainer target, IEnumerable conte } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JEnumerable.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JEnumerable.cs index d21ccd3ba0..6e15a2e831 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JEnumerable.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JEnumerable.cs @@ -35,6 +35,7 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable /// /// Represents a collection of objects. /// @@ -88,7 +89,7 @@ public IJEnumerable this[object key] return JEnumerable.Empty; } - return new JEnumerable(_enumerable.Values(key)); + return new JEnumerable(_enumerable.Values(key)!); } } @@ -111,7 +112,7 @@ public bool Equals(JEnumerable other) /// /// true if the specified is equal to this instance; otherwise, false. /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is JEnumerable enumerable) { @@ -125,7 +126,7 @@ public override bool Equals(object obj) /// Returns a hash code for this instance. /// /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// public override int GetHashCode() { @@ -137,4 +138,5 @@ public override int GetHashCode() return _enumerable.GetHashCode(); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JObject.Async.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JObject.Async.cs index 7f92bb479b..b91d3e43b2 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JObject.Async.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JObject.Async.cs @@ -33,6 +33,7 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable internal partial class JObject { /// @@ -45,7 +46,7 @@ internal partial class JObject public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters) { Task t = writer.WriteStartObjectAsync(cancellationToken); - if (!t.IsCompletedSucessfully()) + if (!t.IsCompletedSuccessfully()) { return AwaitProperties(t, 0, writer, cancellationToken, converters); } @@ -53,7 +54,7 @@ public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellat for (int i = 0; i < _properties.Count; i++) { t = _properties[i].WriteToAsync(writer, cancellationToken, converters); - if (!t.IsCompletedSucessfully()) + if (!t.IsCompletedSuccessfully()) { return AwaitProperties(t, i + 1, writer, cancellationToken, converters); } @@ -97,7 +98,7 @@ async Task AwaitProperties(Task task, int i, JsonWriter Writer, CancellationToke /// /// A that represents the asynchronous load. The /// property returns a that contains the JSON that was read from the specified . - public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); @@ -124,6 +125,7 @@ async Task AwaitProperties(Task task, int i, JsonWriter Writer, CancellationToke return o; } } +#nullable disable } #endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JObject.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JObject.cs index 46da192e2f..2569dd3643 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JObject.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JObject.cs @@ -37,6 +37,8 @@ using System.IO; using Microsoft.IdentityModel.Json.Utilities; using System.Globalization; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else @@ -45,13 +47,14 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable /// /// Represents a JSON object. /// /// /// /// - internal partial class JObject : JContainer, IDictionary, INotifyPropertyChanged + internal partial class JObject : JContainer, IDictionary, INotifyPropertyChanged #if HAVE_COMPONENT_MODEL , ICustomTypeDescriptor #endif @@ -70,13 +73,13 @@ internal partial class JObject : JContainer, IDictionary, INotif /// /// Occurs when a property value changes. /// - public event PropertyChangedEventHandler PropertyChanged; + public event PropertyChangedEventHandler? PropertyChanged; #if HAVE_INOTIFY_PROPERTY_CHANGING /// /// Occurs when a property value is changing. /// - public event PropertyChangingEventHandler PropertyChanging; + public event PropertyChangingEventHandler? PropertyChanging; #endif /// @@ -123,23 +126,28 @@ internal override bool DeepEquals(JToken node) return _properties.Compare(t._properties); } - internal override int IndexOfItem(JToken item) + internal override int IndexOfItem(JToken? item) { + if (item == null) + { + return -1; + } + return _properties.IndexOfReference(item); } - internal override void InsertItem(int index, JToken item, bool skipParentCheck) + internal override bool InsertItem(int index, JToken? item, bool skipParentCheck) { // don't add comments to JObject, no name to reference comment by if (item != null && item.Type == JTokenType.Comment) { - return; + return false; } - base.InsertItem(index, item, skipParentCheck); + return base.InsertItem(index, item, skipParentCheck); } - internal override void ValidateToken(JToken o, JToken existing) + internal override void ValidateToken(JToken o, JToken? existing) { ValidationUtils.ArgumentNotNull(o, nameof(o)); @@ -166,16 +174,16 @@ internal override void ValidateToken(JToken o, JToken existing) } } - internal override void MergeItem(object content, JsonMergeSettings settings) + internal override void MergeItem(object content, JsonMergeSettings? settings) { if (!(content is JObject o)) { return; } - foreach (KeyValuePair contentItem in o) + foreach (KeyValuePair contentItem in o) { - JProperty existingProperty = Property(contentItem.Key, settings?.PropertyNameComparison ?? StringComparison.Ordinal); + JProperty? existingProperty = Property(contentItem.Key, settings?.PropertyNameComparison ?? StringComparison.Ordinal); if (existingProperty == null) { @@ -262,7 +270,7 @@ public IEnumerable Properties() /// /// The property name. /// A with the specified name or null. - public JProperty Property(string name) + public JProperty? Property(string name) { return Property(name, StringComparison.Ordinal); } @@ -275,14 +283,14 @@ public JProperty Property(string name) /// The property name. /// One of the enumeration values that specifies how the strings will be compared. /// A matched with the specified name or null. - public JProperty Property(string name, StringComparison comparison) + public JProperty? Property(string name, StringComparison comparison) { if (name == null) { return null; } - if (_properties.TryGetValue(name, out JToken property)) + if (_properties.TryGetValue(name, out JToken? property)) { return (JProperty)property; } @@ -316,7 +324,7 @@ public JEnumerable PropertyValues() /// Gets the with the specified key. /// /// The with the specified key. - public override JToken this[object key] + public override JToken? this[object key] { get { @@ -346,29 +354,29 @@ public override JToken this[object key] /// Gets or sets the with the specified property name. /// /// - public JToken this[string propertyName] + public JToken? this[string propertyName] { get { ValidationUtils.ArgumentNotNull(propertyName, nameof(propertyName)); - JProperty property = Property(propertyName); + JProperty? property = Property(propertyName, StringComparison.Ordinal); return property?.Value; } set { - JProperty property = Property(propertyName); + JProperty? property = Property(propertyName, StringComparison.Ordinal); if (property != null) { - property.Value = value; + property.Value = value!; } else { #if HAVE_INOTIFY_PROPERTY_CHANGING OnPropertyChanging(propertyName); #endif - Add(new JProperty(propertyName, value)); + Add(propertyName, value); OnPropertyChanged(propertyName); } } @@ -397,7 +405,7 @@ public JToken this[string propertyName] /// /// is not valid JSON. /// - public new static JObject Load(JsonReader reader, JsonLoadSettings settings) + public new static JObject Load(JsonReader reader, JsonLoadSettings? settings) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); @@ -453,7 +461,7 @@ public JToken this[string propertyName] /// /// /// - public new static JObject Parse(string json, JsonLoadSettings settings) + public new static JObject Parse(string json, JsonLoadSettings? settings) { using (JsonReader reader = new JsonTextReader(new StringReader(json))) { @@ -488,7 +496,7 @@ public JToken this[string propertyName] { JToken token = FromObjectInternal(o, jsonSerializer); - if (token != null && token.Type != JTokenType.Object) + if (token.Type != JTokenType.Object) { throw new ArgumentException("Object serialized to {0}. JObject instance expected.".FormatWith(CultureInfo.InvariantCulture, token.Type)); } @@ -518,7 +526,7 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter /// /// Name of the property. /// The with the specified property name. - public JToken GetValue(string propertyName) + public JToken? GetValue(string? propertyName) { return GetValue(propertyName, StringComparison.Ordinal); } @@ -531,7 +539,7 @@ public JToken GetValue(string propertyName) /// Name of the property. /// One of the enumeration values that specifies how the strings will be compared. /// The with the specified property name. - public JToken GetValue(string propertyName, StringComparison comparison) + public JToken? GetValue(string? propertyName, StringComparison comparison) { if (propertyName == null) { @@ -553,7 +561,7 @@ public JToken GetValue(string propertyName, StringComparison comparison) /// The value. /// One of the enumeration values that specifies how the strings will be compared. /// true if a value was successfully retrieved; otherwise, false. - public bool TryGetValue(string propertyName, StringComparison comparison, out JToken value) + public bool TryGetValue(string propertyName, StringComparison comparison, [NotNullWhen(true)]out JToken? value) { value = GetValue(propertyName, comparison); return (value != null); @@ -565,7 +573,7 @@ public bool TryGetValue(string propertyName, StringComparison comparison, out JT /// /// Name of the property. /// The value. - public void Add(string propertyName, JToken value) + public void Add(string propertyName, JToken? value) { Add(new JProperty(propertyName, value)); } @@ -582,7 +590,7 @@ public bool ContainsKey(string propertyName) return _properties.Contains(propertyName); } - ICollection IDictionary.Keys => _properties.Keys; + ICollection IDictionary.Keys => _properties.Keys; /// /// Removes the property with the specified name. @@ -591,7 +599,7 @@ public bool ContainsKey(string propertyName) /// true if item was successfully removed; otherwise, false. public bool Remove(string propertyName) { - JProperty property = Property(propertyName); + JProperty? property = Property(propertyName, StringComparison.Ordinal); if (property == null) { return false; @@ -607,9 +615,9 @@ public bool Remove(string propertyName) /// Name of the property. /// The value. /// true if a value was successfully retrieved; otherwise, false. - public bool TryGetValue(string propertyName, out JToken value) + public bool TryGetValue(string propertyName, [NotNullWhen(true)]out JToken? value) { - JProperty property = Property(propertyName); + JProperty? property = Property(propertyName, StringComparison.Ordinal); if (property == null) { value = null; @@ -620,24 +628,24 @@ public bool TryGetValue(string propertyName, out JToken value) return true; } - ICollection IDictionary.Values => throw new NotImplementedException(); + ICollection IDictionary.Values => throw new NotImplementedException(); #endregion #region ICollection> Members - void ICollection>.Add(KeyValuePair item) + void ICollection>.Add(KeyValuePair item) { Add(new JProperty(item.Key, item.Value)); } - void ICollection>.Clear() + void ICollection>.Clear() { RemoveAll(); } - bool ICollection>.Contains(KeyValuePair item) + bool ICollection>.Contains(KeyValuePair item) { - JProperty property = Property(item.Key); + JProperty? property = Property(item.Key, StringComparison.Ordinal); if (property == null) { return false; @@ -646,7 +654,7 @@ bool ICollection>.Contains(KeyValuePair>.CopyTo(KeyValuePair[] array, int arrayIndex) + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { if (array == null) { @@ -668,16 +676,16 @@ void ICollection>.CopyTo(KeyValuePair(property.Name, property.Value); + array[arrayIndex + index] = new KeyValuePair(property.Name, property.Value); index++; } } - bool ICollection>.IsReadOnly => false; + bool ICollection>.IsReadOnly => false; - bool ICollection>.Remove(KeyValuePair item) + bool ICollection>.Remove(KeyValuePair item) { - if (!((ICollection>)this).Contains(item)) + if (!((ICollection>)this).Contains(item)) { return false; } @@ -698,11 +706,11 @@ internal override int GetDeepHashCode() /// /// A that can be used to iterate through the collection. /// - public IEnumerator> GetEnumerator() + public IEnumerator> GetEnumerator() { foreach (JProperty property in _properties) { - yield return new KeyValuePair(property.Name, property.Value); + yield return new KeyValuePair(property.Name, property.Value); } } @@ -735,16 +743,17 @@ PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() return ((ICustomTypeDescriptor)this).GetProperties(null); } - PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) + PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[]? attributes) { - PropertyDescriptorCollection descriptors = new PropertyDescriptorCollection(null); - - foreach (KeyValuePair propertyValue in this) + PropertyDescriptor[] propertiesArray = new PropertyDescriptor[Count]; + int i = 0; + foreach (KeyValuePair propertyValue in this) { - descriptors.Add(new JPropertyDescriptor(propertyValue.Key)); + propertiesArray[i] = new JPropertyDescriptor(propertyValue.Key); + i++; } - return descriptors; + return new PropertyDescriptorCollection(propertiesArray); } AttributeCollection ICustomTypeDescriptor.GetAttributes() @@ -752,12 +761,12 @@ AttributeCollection ICustomTypeDescriptor.GetAttributes() return AttributeCollection.Empty; } - string ICustomTypeDescriptor.GetClassName() + string? ICustomTypeDescriptor.GetClassName() { return null; } - string ICustomTypeDescriptor.GetComponentName() + string? ICustomTypeDescriptor.GetComponentName() { return null; } @@ -767,22 +776,22 @@ TypeConverter ICustomTypeDescriptor.GetConverter() return new TypeConverter(); } - EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() + EventDescriptor? ICustomTypeDescriptor.GetDefaultEvent() { return null; } - PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() + PropertyDescriptor? ICustomTypeDescriptor.GetDefaultProperty() { return null; } - object ICustomTypeDescriptor.GetEditor(Type editorBaseType) + object? ICustomTypeDescriptor.GetEditor(Type editorBaseType) { return null; } - EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) + EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[]? attributes) { return EventDescriptorCollection.Empty; } @@ -792,7 +801,7 @@ EventDescriptorCollection ICustomTypeDescriptor.GetEvents() return EventDescriptorCollection.Empty; } - object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) + object? ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor? pd) { if (pd is JPropertyDescriptor) { @@ -805,7 +814,7 @@ object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) #endif -#if HAVE_DYNAMIC +#if HAVE_DYNAMIC /// /// Returns the responsible for binding operations performed on this object. /// @@ -820,7 +829,7 @@ protected override DynamicMetaObject GetMetaObject(Expression parameter) private class JObjectDynamicProxy : DynamicProxy { - public override bool TryGetMember(JObject instance, GetMemberBinder binder, out object result) + public override bool TryGetMember(JObject instance, GetMemberBinder binder, out object? result) { // result can be null result = instance[binder.Name]; @@ -846,4 +855,5 @@ public override IEnumerable GetDynamicMemberNames(JObject instance) } #endif } +#nullable disable } diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JProperty.Async.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JProperty.Async.cs index 4cd487672b..74043335d2 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JProperty.Async.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JProperty.Async.cs @@ -32,6 +32,8 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable +#pragma warning disable CA1068 // CancellationToken parameters must come last internal partial class JProperty { /// @@ -44,7 +46,7 @@ internal partial class JProperty public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters) { Task task = writer.WritePropertyNameAsync(_name, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return WriteValueAsync(writer, cancellationToken, converters); } @@ -59,9 +61,7 @@ private async Task WriteToAsync(Task task, JsonWriter writer, CancellationToken await WriteValueAsync(writer, cancellationToken, converters).ConfigureAwait(false); } -#pragma warning disable CA1068 // CancellationToken parameters must come last private Task WriteValueAsync(JsonWriter writer, CancellationToken cancellationToken, JsonConverter[] converters) -#pragma warning restore CA1068 // CancellationToken parameters must come last { JToken value = Value; return value != null @@ -90,7 +90,7 @@ private Task WriteValueAsync(JsonWriter writer, CancellationToken cancellationTo /// The token to monitor for cancellation requests. The default value is . /// A representing the asynchronous creation. The /// property returns a that contains the JSON that was read from the specified . - public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { if (reader.TokenType == JsonToken.None) { @@ -107,7 +107,7 @@ private Task WriteValueAsync(JsonWriter writer, CancellationToken cancellationTo throw JsonReaderException.Create(reader, "Error reading JProperty from JsonReader. Current JsonReader item is not a property: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - JProperty p = new JProperty((string)reader.Value); + JProperty p = new JProperty((string)reader.Value!); p.SetLineInfo(reader as IJsonLineInfo, settings); await p.ReadTokenFromAsync(reader, settings, cancellationToken).ConfigureAwait(false); @@ -115,6 +115,8 @@ private Task WriteValueAsync(JsonWriter writer, CancellationToken cancellationTo return p; } } +#nullable disable +#pragma warning restore CA1068 // CancellationToken parameters must come last } #endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JProperty.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JProperty.cs index e212526bc2..e769632d85 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JProperty.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JProperty.cs @@ -35,12 +35,13 @@ namespace Microsoft.IdentityModel.Json.Linq /// /// Represents a JSON property. /// +#nullable enable internal partial class JProperty : JContainer { #region JPropertyList private class JPropertyList : IList { - internal JToken _token; + internal JToken? _token; public IEnumerator GetEnumerator() { @@ -115,13 +116,24 @@ public void RemoveAt(int index) public JToken this[int index] { - get => (index == 0) ? _token : null; + get + { + if (index != 0) + { + throw new IndexOutOfRangeException(); + } + + MiscellaneousUtils.Assert(_token != null); + return _token; + } set { - if (index == 0) + if (index != 0) { - _token = value; + throw new IndexOutOfRangeException(); } + + _token = value; } } } @@ -153,7 +165,7 @@ public string Name public JToken Value { [DebuggerStepThrough] - get { return _content._token; } + get { return _content._token!; } set { CheckReentrancy(); @@ -191,7 +203,7 @@ internal override JToken GetItem(int index) return Value; } - internal override void SetItem(int index, JToken item) + internal override void SetItem(int index, JToken? item) { if (index != 0) { @@ -203,14 +215,14 @@ internal override void SetItem(int index, JToken item) return; } - ((JObject)Parent)?.InternalPropertyChanging(this); + ((JObject?)Parent)?.InternalPropertyChanging(this); base.SetItem(0, item); - ((JObject)Parent)?.InternalPropertyChanged(this); + ((JObject?)Parent)?.InternalPropertyChanged(this); } - internal override bool RemoveItem(JToken item) + internal override bool RemoveItem(JToken? item) { throw new JsonException("Cannot add or remove items from {0}.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty))); } @@ -220,17 +232,22 @@ internal override void RemoveItemAt(int index) throw new JsonException("Cannot add or remove items from {0}.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty))); } - internal override int IndexOfItem(JToken item) + internal override int IndexOfItem(JToken? item) { + if (item == null) + { + return -1; + } + return _content.IndexOf(item); } - internal override void InsertItem(int index, JToken item, bool skipParentCheck) + internal override bool InsertItem(int index, JToken? item, bool skipParentCheck) { // don't add comments to JProperty if (item != null && item.Type == JTokenType.Comment) { - return; + return false; } if (Value != null) @@ -238,17 +255,17 @@ internal override void InsertItem(int index, JToken item, bool skipParentCheck) throw new JsonException("{0} cannot have multiple values.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty))); } - base.InsertItem(0, item, false); + return base.InsertItem(0, item, false); } - internal override bool ContainsItem(JToken item) + internal override bool ContainsItem(JToken? item) { return (Value == item); } - internal override void MergeItem(object content, JsonMergeSettings settings) + internal override void MergeItem(object content, JsonMergeSettings? settings) { - JToken value = (content as JProperty)?.Value; + JToken? value = (content as JProperty)?.Value; if (value != null && value.Type != JTokenType.Null) { @@ -304,7 +321,7 @@ public JProperty(string name, params object[] content) /// /// The property name. /// The property content. - public JProperty(string name, object content) + public JProperty(string name, object? content) { ValidationUtils.ArgumentNotNull(name, nameof(name)); @@ -337,7 +354,13 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter internal override int GetDeepHashCode() { - return _name.GetHashCode() ^ (Value?.GetDeepHashCode() ?? 0); + int hash; +#if HAVE_GETHASHCODE_STRING_COMPARISON + hash = _name.GetHashCode(StringComparison.Ordinal); +#else + hash = _name.GetHashCode(); +#endif + return hash ^ (Value?.GetDeepHashCode() ?? 0); } /// @@ -357,7 +380,7 @@ internal override int GetDeepHashCode() /// The used to load the JSON. /// If this is null, default load settings will be used. /// A that contains the JSON that was read from the specified . - public new static JProperty Load(JsonReader reader, JsonLoadSettings settings) + public new static JProperty Load(JsonReader reader, JsonLoadSettings? settings) { if (reader.TokenType == JsonToken.None) { @@ -374,7 +397,7 @@ internal override int GetDeepHashCode() throw JsonReaderException.Create(reader, "Error reading JProperty from JsonReader. Current JsonReader item is not a property: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - JProperty p = new JProperty((string)reader.Value); + JProperty p = new JProperty((string)reader.Value!); p.SetLineInfo(reader as IJsonLineInfo, settings); p.ReadTokenFrom(reader, settings); @@ -382,4 +405,5 @@ internal override int GetDeepHashCode() return p; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JPropertyDescriptor.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JPropertyDescriptor.cs index 703dacc26b..ee3e9943e2 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JPropertyDescriptor.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JPropertyDescriptor.cs @@ -29,6 +29,7 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable /// /// Represents a view of a . /// @@ -67,7 +68,7 @@ public override bool CanResetValue(object component) /// The value of a property for a given component. /// /// The component with the property for which to retrieve the value. - public override object GetValue(object component) + public override object? GetValue(object? component) { return (component as JObject)?[Name]; } @@ -85,7 +86,7 @@ public override void ResetValue(object component) /// /// The component with the property value that is to be set. /// The new value. - public override void SetValue(object component, object value) + public override void SetValue(object? component, object? value) { if (component is JObject o) { @@ -151,6 +152,7 @@ protected override int NameHashCode } } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JPropertyKeyedCollection.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JPropertyKeyedCollection.cs index dd43d1d6d7..5cdb287297 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JPropertyKeyedCollection.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JPropertyKeyedCollection.cs @@ -26,15 +26,18 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using Microsoft.IdentityModel.Json.Utilities; namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable internal class JPropertyKeyedCollection : Collection { private static readonly IEqualityComparer Comparer = StringComparer.Ordinal; - private Dictionary _dictionary; + private Dictionary? _dictionary; public JPropertyKeyedCollection() : base(new List()) { @@ -43,7 +46,7 @@ public JPropertyKeyedCollection() : base(new List()) private void AddKey(string key, JToken item) { EnsureDictionary(); - _dictionary[key] = item; + _dictionary![key] = item; } protected void ChangeItemKey(JToken item, string newKey) @@ -129,7 +132,7 @@ public bool Remove(string key) if (_dictionary != null) { - return _dictionary.ContainsKey(key) && Remove(_dictionary[key]); + return _dictionary.TryGetValue(key, out JToken? value) && Remove(value); } return false; @@ -189,7 +192,7 @@ public JToken this[string key] } } - public bool TryGetValue(string key, out JToken value) + public bool TryGetValue(string key, [NotNullWhen(true)]out JToken? value) { if (_dictionary == null) { @@ -205,7 +208,7 @@ public ICollection Keys get { EnsureDictionary(); - return _dictionary.Keys; + return _dictionary!.Keys; } } @@ -214,7 +217,7 @@ public ICollection Values get { EnsureDictionary(); - return _dictionary.Values; + return _dictionary!.Values; } } @@ -232,8 +235,8 @@ public bool Compare(JPropertyKeyedCollection other) // dictionaries in JavaScript aren't ordered // ignore order when comparing properties - Dictionary d1 = _dictionary; - Dictionary d2 = other._dictionary; + Dictionary? d1 = _dictionary; + Dictionary? d2 = other._dictionary; if (d1 == null && d2 == null) { @@ -242,7 +245,7 @@ public bool Compare(JPropertyKeyedCollection other) if (d1 == null) { - return (d2.Count == 0); + return (d2!.Count == 0); } if (d2 == null) @@ -257,7 +260,7 @@ public bool Compare(JPropertyKeyedCollection other) foreach (KeyValuePair keyAndProperty in d1) { - if (!d2.TryGetValue(keyAndProperty.Key, out JToken secondValue)) + if (!d2.TryGetValue(keyAndProperty.Key, out JToken? secondValue)) { return false; } @@ -279,4 +282,5 @@ public bool Compare(JPropertyKeyedCollection other) return true; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JRaw.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JRaw.cs index 34168e365f..ba599276de 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JRaw.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JRaw.cs @@ -28,6 +28,7 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable /// /// Represents a raw JSON string. /// @@ -46,7 +47,7 @@ public JRaw(JRaw other) /// Initializes a new instance of the class. /// /// The raw json. - public JRaw(object rawJson) + public JRaw(object? rawJson) : base(rawJson, JTokenType.Raw) { } @@ -72,4 +73,5 @@ internal override JToken CloneToken() return new JRaw(this); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JToken.Async.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JToken.Async.cs index 9c9568cb7b..12b6e948a8 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JToken.Async.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JToken.Async.cs @@ -33,6 +33,7 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable internal abstract partial class JToken { /// @@ -65,7 +66,7 @@ public Task WriteToAsync(JsonWriter writer, params JsonConverter[] converters) /// The token to monitor for cancellation requests. The default value is . /// /// A that represents the asynchronous creation. The - /// property returns a that contains + /// property returns a that contains /// the token and its descendant tokens /// that were read from the reader. The runtime type of the token is determined /// by the token type of the first token encountered in the reader. @@ -84,12 +85,12 @@ public static Task ReadFromAsync(JsonReader reader, CancellationToken ca /// The token to monitor for cancellation requests. The default value is . /// /// A that represents the asynchronous creation. The - /// property returns a that contains + /// property returns a that contains /// the token and its descendant tokens /// that were read from the reader. The runtime type of the token is determined /// by the token type of the first token encountered in the reader. /// - public static async Task ReadFromAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + public static async Task ReadFromAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); @@ -101,7 +102,7 @@ public static async Task ReadFromAsync(JsonReader reader, JsonLoadSettin } } - IJsonLineInfo lineInfo = reader as IJsonLineInfo; + IJsonLineInfo? lineInfo = reader as IJsonLineInfo; switch (reader.TokenType) { @@ -123,7 +124,7 @@ public static async Task ReadFromAsync(JsonReader reader, JsonLoadSettin v.SetLineInfo(lineInfo, settings); return v; case JsonToken.Comment: - v = JValue.CreateComment(reader.Value.ToString()); + v = JValue.CreateComment(reader.Value?.ToString()); v.SetLineInfo(lineInfo, settings); return v; case JsonToken.Null: @@ -168,11 +169,12 @@ public static Task LoadAsync(JsonReader reader, CancellationToken cancel /// that were read from the reader. The runtime type of the token is determined /// by the token type of the first token encountered in the reader. /// - public static Task LoadAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + public static Task LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { return ReadFromAsync(reader, settings, cancellationToken); } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JToken.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JToken.cs index c5e2596139..1dc42cb130 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JToken.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JToken.cs @@ -38,15 +38,19 @@ using System.Diagnostics; using System.Globalization; using System.Collections; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else using System.Linq; - #endif +using Microsoft.IdentityModel.Json.Serialization; namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable +#pragma warning disable CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly /// /// Represents an abstract JSON token. /// @@ -58,12 +62,12 @@ internal abstract partial class JToken : IJEnumerable, IJsonLineInfo , IDynamicMetaObjectProvider #endif { - private static JTokenEqualityComparer _equalityComparer; + private static JTokenEqualityComparer? _equalityComparer; - private JContainer _parent; - private JToken _previous; - private JToken _next; - private object _annotations; + private JContainer? _parent; + private JToken? _previous; + private JToken? _next; + private object? _annotations; private static readonly JTokenType[] BooleanTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean }; private static readonly JTokenType[] NumberTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean }; @@ -99,7 +103,7 @@ public static JTokenEqualityComparer EqualityComparer /// Gets or sets the parent. /// /// The parent. - public JContainer Parent + public JContainer? Parent { [DebuggerStepThrough] get { return _parent; } @@ -114,7 +118,7 @@ public JToken Root { get { - JContainer parent = Parent; + JContainer? parent = Parent; if (parent == null) { return this; @@ -152,7 +156,7 @@ public JToken Root /// The first to compare. /// The second to compare. /// true if the tokens are equal; otherwise false. - public static bool DeepEquals(JToken t1, JToken t2) + public static bool DeepEquals(JToken? t1, JToken? t2) { return (t1 == t2 || (t1 != null && t2 != null && t1.DeepEquals(t2))); } @@ -161,7 +165,7 @@ public static bool DeepEquals(JToken t1, JToken t2) /// Gets the next sibling token of this node. /// /// The that contains the next sibling token. - public JToken Next + public JToken? Next { get => _next; internal set => _next = value; @@ -171,14 +175,14 @@ public JToken Next /// Gets the previous sibling token of this node. /// /// The that contains the previous sibling token. - public JToken Previous + public JToken? Previous { get => _previous; internal set => _previous = value; } /// - /// Gets the path of the JSON token. + /// Gets the path of the JSON token. /// public string Path { @@ -190,8 +194,8 @@ public string Path } List positions = new List(); - JToken previous = null; - for (JToken current = this; current != null; current = current.Parent) + JToken? previous = null; + for (JToken? current = this; current != null; current = current.Parent) { switch (current.Type) { @@ -231,7 +235,7 @@ internal JToken() /// Adds the specified content immediately after this token. /// /// A content object that contains simple content or a collection of content objects to be added after this token. - public void AddAfterSelf(object content) + public void AddAfterSelf(object? content) { if (_parent == null) { @@ -239,14 +243,14 @@ public void AddAfterSelf(object content) } int index = _parent.IndexOfItem(this); - _parent.AddInternal(index + 1, content, false); + _parent.TryAddInternal(index + 1, content, false); } /// /// Adds the specified content immediately before this token. /// /// A content object that contains simple content or a collection of content objects to be added before this token. - public void AddBeforeSelf(object content) + public void AddBeforeSelf(object? content) { if (_parent == null) { @@ -254,7 +258,7 @@ public void AddBeforeSelf(object content) } int index = _parent.IndexOfItem(this); - _parent.AddInternal(index, content, false); + _parent.TryAddInternal(index, content, false); } /// @@ -277,7 +281,7 @@ public IEnumerable AncestorsAndSelf() internal IEnumerable GetAncestors(bool self) { - for (JToken current = self ? this : Parent; current != null; current = current.Parent) + for (JToken? current = self ? this : Parent; current != null; current = current.Parent) { yield return current; } @@ -294,7 +298,7 @@ public IEnumerable AfterSelf() yield break; } - for (JToken o = Next; o != null; o = o.Next) + for (JToken? o = Next; o != null; o = o.Next) { yield return o; } @@ -306,7 +310,12 @@ public IEnumerable AfterSelf() /// A collection of the sibling tokens before this token, in document order. public IEnumerable BeforeSelf() { - for (JToken o = Parent.First; o != this; o = o.Next) + if (Parent == null) + { + yield break; + } + + for (JToken? o = Parent.First; o != this && o != null; o = o.Next) { yield return o; } @@ -316,7 +325,7 @@ public IEnumerable BeforeSelf() /// Gets the with the specified key. /// /// The with the specified key. - public virtual JToken this[object key] + public virtual JToken? this[object key] { get => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); set => throw new InvalidOperationException("Cannot set child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); @@ -328,11 +337,11 @@ public virtual JToken this[object key] /// The type to convert the token to. /// The token key. /// The converted token value. - public virtual T Value(object key) + public virtual T? Value(object key) { - JToken token = this[key]; + JToken? token = this[key]; - // null check to fix MonoTouch issue - https://github.com/dolbz/Microsoft.IdentityModel.Json/commit/a24e3062846b30ee505f3271ac08862bb471b822 + // null check to fix MonoTouch issue - https://github.com/dolbz/Newtonsoft.Json/commit/a24e3062846b30ee505f3271ac08862bb471b822 return token == null ? default : Extensions.Convert(token); } @@ -340,13 +349,13 @@ public virtual T Value(object key) /// Get the first child token of this token. /// /// A containing the first child token of the . - public virtual JToken First => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); + public virtual JToken? First => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); /// /// Get the last child token of this token. /// /// A containing the last child token of the . - public virtual JToken Last => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); + public virtual JToken? Last => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); /// /// Returns a collection of the child tokens of this token, in document order. @@ -372,7 +381,7 @@ public JEnumerable Children() where T : JToken /// /// The type to convert the values to. /// A containing the child values of this , in document order. - public virtual IEnumerable Values() + public virtual IEnumerable Values() { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); } @@ -414,6 +423,10 @@ public void Replace(JToken value) /// /// Returns the indented JSON for this token. /// + /// + /// ToString() returns a non-JSON string value for tokens with a type of . + /// If you want the JSON for all token types then you should use . + /// /// /// The indented JSON for this token. /// @@ -441,7 +454,7 @@ public string ToString(Formatting formatting, params JsonConverter[] converters) } } - private static JValue EnsureValue(JToken value) + private static JValue? EnsureValue(JToken value) { if (value == null) { @@ -453,7 +466,7 @@ private static JValue EnsureValue(JToken value) value = property.Value; } - JValue v = value as JValue; + JValue? v = value as JValue; return v; } @@ -475,7 +488,7 @@ private static bool ValidateToken(JToken o, JTokenType[] validTypes, bool nullab return (Array.IndexOf(validTypes, o.Type) != -1) || (nullable && (o.Type == JTokenType.Null || o.Type == JTokenType.Undefined)); } -#region Cast from operators + #region Cast from operators /// /// Performs an explicit conversion from to . /// @@ -483,7 +496,7 @@ private static bool ValidateToken(JToken o, JTokenType[] validTypes, bool nullab /// The result of the conversion. public static explicit operator bool(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, BooleanTypes, false)) { throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -507,7 +520,7 @@ public static explicit operator bool(JToken value) /// The result of the conversion. public static explicit operator DateTimeOffset(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, DateTimeTypes, false)) { throw new ArgumentException("Can not convert {0} to DateTimeOffset.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -532,14 +545,14 @@ public static explicit operator DateTimeOffset(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator bool?(JToken value) + public static explicit operator bool?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, BooleanTypes, true)) { throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -562,7 +575,7 @@ public static explicit operator DateTimeOffset(JToken value) /// The result of the conversion. public static explicit operator long(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -583,14 +596,14 @@ public static explicit operator long(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator DateTime?(JToken value) + public static explicit operator DateTime?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, DateTimeTypes, true)) { throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -612,14 +625,14 @@ public static explicit operator long(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator DateTimeOffset?(JToken value) + public static explicit operator DateTimeOffset?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, DateTimeTypes, true)) { throw new ArgumentException("Can not convert {0} to DateTimeOffset.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -648,14 +661,14 @@ public static explicit operator long(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator decimal?(JToken value) + public static explicit operator decimal?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Decimal.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -676,14 +689,14 @@ public static explicit operator long(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator double?(JToken value) + public static explicit operator double?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Double.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -704,14 +717,14 @@ public static explicit operator long(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator char?(JToken value) + public static explicit operator char?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, CharTypes, true)) { throw new ArgumentException("Can not convert {0} to Char.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -734,7 +747,7 @@ public static explicit operator long(JToken value) /// The result of the conversion. public static explicit operator int(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Int32.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -757,7 +770,7 @@ public static explicit operator int(JToken value) /// The result of the conversion. public static explicit operator short(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Int16.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -778,10 +791,10 @@ public static explicit operator short(JToken value) /// /// The value. /// The result of the conversion. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static explicit operator ushort(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to UInt16.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -802,10 +815,10 @@ public static explicit operator ushort(JToken value) /// /// The value. /// The result of the conversion. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static explicit operator char(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, CharTypes, false)) { throw new ArgumentException("Can not convert {0} to Char.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -828,7 +841,7 @@ public static explicit operator char(JToken value) /// The result of the conversion. public static explicit operator byte(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Byte.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -849,10 +862,10 @@ public static explicit operator byte(JToken value) /// /// The value. /// The result of the conversion. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static explicit operator sbyte(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to SByte.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -873,14 +886,14 @@ public static explicit operator sbyte(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator int?(JToken value) + public static explicit operator int?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Int32.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -901,14 +914,14 @@ public static explicit operator sbyte(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator short?(JToken value) + public static explicit operator short?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Int16.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -929,15 +942,15 @@ public static explicit operator sbyte(JToken value) /// /// The value. /// The result of the conversion. - // [ClsCompliant(false)] - public static explicit operator ushort?(JToken value) + [CLSCompliant(false)] + public static explicit operator ushort?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to UInt16.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -958,14 +971,14 @@ public static explicit operator sbyte(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator byte?(JToken value) + public static explicit operator byte?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Byte.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -986,15 +999,15 @@ public static explicit operator sbyte(JToken value) /// /// The value. /// The result of the conversion. - // [ClsCompliant(false)] - public static explicit operator sbyte?(JToken value) + [CLSCompliant(false)] + public static explicit operator sbyte?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to SByte.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1017,7 +1030,7 @@ public static explicit operator sbyte(JToken value) /// The result of the conversion. public static explicit operator DateTime(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, DateTimeTypes, false)) { throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1038,14 +1051,14 @@ public static explicit operator DateTime(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator long?(JToken value) + public static explicit operator long?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1066,14 +1079,14 @@ public static explicit operator DateTime(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator float?(JToken value) + public static explicit operator float?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Single.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1096,7 +1109,7 @@ public static explicit operator DateTime(JToken value) /// The result of the conversion. public static explicit operator decimal(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Decimal.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1117,15 +1130,15 @@ public static explicit operator decimal(JToken value) /// /// The value. /// The result of the conversion. - // [ClsCompliant(false)] - public static explicit operator uint?(JToken value) + [CLSCompliant(false)] + public static explicit operator uint?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1146,15 +1159,15 @@ public static explicit operator decimal(JToken value) /// /// The value. /// The result of the conversion. - // [ClsCompliant(false)] - public static explicit operator ulong?(JToken value) + [CLSCompliant(false)] + public static explicit operator ulong?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1177,7 +1190,7 @@ public static explicit operator decimal(JToken value) /// The result of the conversion. public static explicit operator double(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Double.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1200,7 +1213,7 @@ public static explicit operator double(JToken value) /// The result of the conversion. public static explicit operator float(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Single.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1221,14 +1234,14 @@ public static explicit operator float(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator string(JToken value) + public static explicit operator string?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, StringTypes, true)) { throw new ArgumentException("Can not convert {0} to String.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1259,10 +1272,10 @@ public static explicit operator string(JToken value) /// /// The value. /// The result of the conversion. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static explicit operator uint(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1283,10 +1296,10 @@ public static explicit operator uint(JToken value) /// /// The value. /// The result of the conversion. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static explicit operator ulong(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1307,14 +1320,14 @@ public static explicit operator ulong(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator byte[](JToken value) + public static explicit operator byte[]?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, BytesTypes, false)) { throw new ArgumentException("Can not convert {0} to byte array.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1322,7 +1335,7 @@ public static explicit operator byte[](JToken value) if (v.Value is string) { - return Convert.FromBase64String(Convert.ToString(v.Value, CultureInfo.InvariantCulture)); + return Convert.FromBase64String(Convert.ToString(v.Value, CultureInfo.InvariantCulture)!); } #if HAVE_BIG_INTEGER if (v.Value is BigInteger integer) @@ -1346,7 +1359,7 @@ public static explicit operator byte[](JToken value) /// The result of the conversion. public static explicit operator Guid(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, GuidTypes, false)) { throw new ArgumentException("Can not convert {0} to Guid.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1357,7 +1370,7 @@ public static explicit operator Guid(JToken value) return new Guid(bytes); } - return (v.Value is Guid guid) ? guid : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture)); + return (v.Value is Guid guid) ? guid : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture)!); } /// @@ -1365,14 +1378,14 @@ public static explicit operator Guid(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator Guid?(JToken value) + public static explicit operator Guid?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, GuidTypes, true)) { throw new ArgumentException("Can not convert {0} to Guid.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1388,7 +1401,7 @@ public static explicit operator Guid(JToken value) return new Guid(bytes); } - return (v.Value is Guid guid) ? guid : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture)); + return (v.Value is Guid guid) ? guid : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture)!); } /// @@ -1398,13 +1411,13 @@ public static explicit operator Guid(JToken value) /// The result of the conversion. public static explicit operator TimeSpan(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, TimeSpanTypes, false)) { throw new ArgumentException("Can not convert {0} to TimeSpan.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); } - return (v.Value is TimeSpan span) ? span : ConvertUtils.ParseTimeSpan(Convert.ToString(v.Value, CultureInfo.InvariantCulture)); + return (v.Value is TimeSpan span) ? span : ConvertUtils.ParseTimeSpan(Convert.ToString(v.Value, CultureInfo.InvariantCulture)!); } /// @@ -1412,14 +1425,14 @@ public static explicit operator TimeSpan(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator TimeSpan?(JToken value) + public static explicit operator TimeSpan?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, TimeSpanTypes, true)) { throw new ArgumentException("Can not convert {0} to TimeSpan.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1430,7 +1443,7 @@ public static explicit operator TimeSpan(JToken value) return null; } - return (v.Value is TimeSpan span) ? span : ConvertUtils.ParseTimeSpan(Convert.ToString(v.Value, CultureInfo.InvariantCulture)); + return (v.Value is TimeSpan span) ? span : ConvertUtils.ParseTimeSpan(Convert.ToString(v.Value, CultureInfo.InvariantCulture)!); } /// @@ -1438,14 +1451,14 @@ public static explicit operator TimeSpan(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator Uri(JToken value) + public static explicit operator Uri?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, UriTypes, true)) { throw new ArgumentException("Can not convert {0} to Uri.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1456,24 +1469,24 @@ public static explicit operator Uri(JToken value) return null; } - return (v.Value is Uri uri) ? uri : new Uri(Convert.ToString(v.Value, CultureInfo.InvariantCulture)); + return (v.Value is Uri uri) ? uri : new Uri(Convert.ToString(v.Value, CultureInfo.InvariantCulture)!); } #if HAVE_BIG_INTEGER private static BigInteger ToBigInteger(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, BigIntegerTypes, false)) { throw new ArgumentException("Can not convert {0} to BigInteger.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); } - return ConvertUtils.ToBigInteger(v.Value); + return ConvertUtils.ToBigInteger(v.Value!); } private static BigInteger? ToBigIntegerNullable(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, BigIntegerTypes, true)) { throw new ArgumentException("Can not convert {0} to BigInteger.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1487,9 +1500,9 @@ private static BigInteger ToBigInteger(JToken value) return ConvertUtils.ToBigInteger(v.Value); } #endif -#endregion + #endregion -#region Cast to operators + #region Cast to operators /// /// Performs an implicit conversion from to . /// @@ -1537,7 +1550,7 @@ public static implicit operator JToken(byte? value) /// /// The value to create a from. /// The initialized with the specified value. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static implicit operator JToken(sbyte value) { return new JValue(value); @@ -1548,7 +1561,7 @@ public static implicit operator JToken(sbyte value) /// /// The value to create a from. /// The initialized with the specified value. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static implicit operator JToken(sbyte? value) { return new JValue(value); @@ -1621,7 +1634,7 @@ public static implicit operator JToken(double? value) /// /// The value to create a from. /// The initialized with the specified value. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static implicit operator JToken(short value) { return new JValue(value); @@ -1632,7 +1645,7 @@ public static implicit operator JToken(short value) /// /// The value to create a from. /// The initialized with the specified value. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static implicit operator JToken(ushort value) { return new JValue(value); @@ -1703,7 +1716,7 @@ public static implicit operator JToken(decimal value) /// /// The value to create a from. /// The initialized with the specified value. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static implicit operator JToken(short? value) { return new JValue(value); @@ -1714,7 +1727,7 @@ public static implicit operator JToken(short? value) /// /// The value to create a from. /// The initialized with the specified value. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static implicit operator JToken(ushort? value) { return new JValue(value); @@ -1725,7 +1738,7 @@ public static implicit operator JToken(ushort? value) /// /// The value to create a from. /// The initialized with the specified value. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static implicit operator JToken(uint? value) { return new JValue(value); @@ -1736,7 +1749,7 @@ public static implicit operator JToken(uint? value) /// /// The value to create a from. /// The initialized with the specified value. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static implicit operator JToken(ulong? value) { return new JValue(value); @@ -1767,7 +1780,7 @@ public static implicit operator JToken(float value) /// /// The value to create a from. /// The initialized with the specified value. - public static implicit operator JToken(string value) + public static implicit operator JToken(string? value) { return new JValue(value); } @@ -1777,7 +1790,7 @@ public static implicit operator JToken(string value) /// /// The value to create a from. /// The initialized with the specified value. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static implicit operator JToken(uint value) { return new JValue(value); @@ -1788,7 +1801,7 @@ public static implicit operator JToken(uint value) /// /// The value to create a from. /// The initialized with the specified value. - // [ClsCompliant(false)] + [CLSCompliant(false)] public static implicit operator JToken(ulong value) { return new JValue(value); @@ -1809,7 +1822,7 @@ public static implicit operator JToken(byte[] value) /// /// The value to create a from. /// The initialized with the specified value. - public static implicit operator JToken(Uri value) + public static implicit operator JToken(Uri? value) { return new JValue(value); } @@ -1853,7 +1866,7 @@ public static implicit operator JToken(Guid? value) { return new JValue(value); } -#endregion + #endregion IEnumerator IEnumerable.GetEnumerator() { @@ -1867,7 +1880,7 @@ IEnumerator IEnumerable.GetEnumerator() internal abstract int GetDeepHashCode(); - IJEnumerable IJEnumerable.this[object key] => this[key]; + IJEnumerable IJEnumerable.this[object key] => this[key]!; /// /// Creates a for this token. @@ -1887,7 +1900,7 @@ internal static JToken FromObjectInternal(object o, JsonSerializer jsonSerialize using (JTokenWriter jsonWriter = new JTokenWriter()) { jsonSerializer.Serialize(jsonWriter, o); - token = jsonWriter.Token; + token = jsonWriter.Token!; } return token; @@ -1919,9 +1932,9 @@ public static JToken FromObject(object o, JsonSerializer jsonSerializer) /// /// The object type that the token will be deserialized to. /// The new object created from the JSON value. - public T ToObject() + public T? ToObject() { - return (T)ToObject(typeof(T)); + return (T?)ToObject(typeof(T)); } /// @@ -1929,7 +1942,7 @@ public T ToObject() /// /// The object type that the token will be deserialized to. /// The new object created from the JSON value. - public object ToObject(Type objectType) + public object? ToObject(Type objectType) { if (JsonConvert.DefaultSettings == null) { @@ -1946,15 +1959,15 @@ public object ToObject(Type objectType) } catch (Exception ex) { - Type enumType = objectType.IsEnum() ? objectType : Nullable.GetUnderlyingType(objectType); - throw new ArgumentException("Could not convert '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, (string)this, enumType.Name), ex); + Type enumType = objectType.IsEnum() ? objectType : Nullable.GetUnderlyingType(objectType)!; + throw new ArgumentException("Could not convert '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, (string?)this, enumType.Name), ex); } } if (Type == JTokenType.Integer) { - Type enumType = objectType.IsEnum() ? objectType : Nullable.GetUnderlyingType(objectType); - return Enum.ToObject(enumType, ((JValue)this).Value); + Type enumType = objectType.IsEnum() ? objectType : Nullable.GetUnderlyingType(objectType)!; + return Enum.ToObject(enumType, ((JValue)this).Value!); } } @@ -2023,13 +2036,13 @@ public object ToObject(Type objectType) return (DateTimeOffset)this; #endif case PrimitiveTypeCode.String: - return (string)this; + return (string?)this; case PrimitiveTypeCode.GuidNullable: return (Guid?)this; case PrimitiveTypeCode.Guid: return (Guid)this; case PrimitiveTypeCode.Uri: - return (Uri)this; + return (Uri?)this; case PrimitiveTypeCode.TimeSpanNullable: return (TimeSpan?)this; case PrimitiveTypeCode.TimeSpan: @@ -2052,9 +2065,9 @@ public object ToObject(Type objectType) /// The object type that the token will be deserialized to. /// The that will be used when creating the object. /// The new object created from the JSON value. - public T ToObject(JsonSerializer jsonSerializer) + public T? ToObject(JsonSerializer jsonSerializer) { - return (T)ToObject(typeof(T), jsonSerializer); + return (T?)ToObject(typeof(T), jsonSerializer); } /// @@ -2063,12 +2076,19 @@ public T ToObject(JsonSerializer jsonSerializer) /// The object type that the token will be deserialized to. /// The that will be used when creating the object. /// The new object created from the JSON value. - public object ToObject(Type objectType, JsonSerializer jsonSerializer) + public object? ToObject(Type? objectType, JsonSerializer jsonSerializer) { ValidationUtils.ArgumentNotNull(jsonSerializer, nameof(jsonSerializer)); using (JTokenReader jsonReader = new JTokenReader(this)) { + // Hacky fix to ensure the serializer settings are set onto the new reader. + // This is required because the serializer won't update settings when used inside of a converter. + if (jsonSerializer is JsonSerializerProxy proxy) + { + proxy._serializer.SetupReader(jsonReader, out _, out _, out _, out _, out _, out _); + } + return jsonSerializer.Deserialize(jsonReader, objectType); } } @@ -2098,7 +2118,7 @@ public static JToken ReadFrom(JsonReader reader) /// that were read from the reader. The runtime type of the token is determined /// by the token type of the first token encountered in the reader. /// - public static JToken ReadFrom(JsonReader reader, JsonLoadSettings settings) + public static JToken ReadFrom(JsonReader reader, JsonLoadSettings? settings) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); @@ -2123,7 +2143,7 @@ public static JToken ReadFrom(JsonReader reader, JsonLoadSettings settings) throw JsonReaderException.Create(reader, "Error reading JToken from JsonReader."); } - IJsonLineInfo lineInfo = reader as IJsonLineInfo; + IJsonLineInfo? lineInfo = reader as IJsonLineInfo; switch (reader.TokenType) { @@ -2145,7 +2165,7 @@ public static JToken ReadFrom(JsonReader reader, JsonLoadSettings settings) v.SetLineInfo(lineInfo, settings); return v; case JsonToken.Comment: - v = JValue.CreateComment(reader.Value.ToString()); + v = JValue.CreateComment(reader.Value!.ToString()); v.SetLineInfo(lineInfo, settings); return v; case JsonToken.Null: @@ -2178,7 +2198,7 @@ public static JToken Parse(string json) /// The used to load the JSON. /// If this is null, default load settings will be used. /// A populated from the string that contains JSON. - public static JToken Parse(string json, JsonLoadSettings settings) + public static JToken Parse(string json, JsonLoadSettings? settings) { using (JsonReader reader = new JsonTextReader(new StringReader(json))) { @@ -2189,7 +2209,6 @@ public static JToken Parse(string json, JsonLoadSettings settings) // Any content encountered here other than a comment will throw in the reader. } - return t; } } @@ -2205,7 +2224,7 @@ public static JToken Parse(string json, JsonLoadSettings settings) /// that were read from the reader. The runtime type of the token is determined /// by the token type of the first token encountered in the reader. /// - public static JToken Load(JsonReader reader, JsonLoadSettings settings) + public static JToken Load(JsonReader reader, JsonLoadSettings? settings) { return ReadFrom(reader, settings); } @@ -2224,7 +2243,7 @@ public static JToken Load(JsonReader reader) return Load(reader, null); } - internal void SetLineInfo(IJsonLineInfo lineInfo, JsonLoadSettings settings) + internal void SetLineInfo(IJsonLineInfo? lineInfo, JsonLoadSettings? settings) { if (settings != null && settings.LineInfoHandling != LineInfoHandling.Load) { @@ -2265,7 +2284,7 @@ int IJsonLineInfo.LineNumber { get { - LineInfoAnnotation annotation = Annotation(); + LineInfoAnnotation? annotation = Annotation(); if (annotation != null) { return annotation.LineNumber; @@ -2279,7 +2298,7 @@ int IJsonLineInfo.LinePosition { get { - LineInfoAnnotation annotation = Annotation(); + LineInfoAnnotation? annotation = Annotation(); if (annotation != null) { return annotation.LinePosition; @@ -2290,31 +2309,48 @@ int IJsonLineInfo.LinePosition } /// - /// Selects a using a JPath expression. Selects the token that matches the object path. + /// Selects a using a JSONPath expression. Selects the token that matches the object path. /// /// - /// A that contains a JPath expression. + /// A that contains a JSONPath expression. /// /// A , or null. - public JToken SelectToken(string path) + public JToken? SelectToken(string path) { - return SelectToken(path, false); + return SelectToken(path, settings: null); } /// - /// Selects a using a JPath expression. Selects the token that matches the object path. + /// Selects a using a JSONPath expression. Selects the token that matches the object path. /// /// - /// A that contains a JPath expression. + /// A that contains a JSONPath expression. /// /// A flag to indicate whether an error should be thrown if no tokens are found when evaluating part of the expression. /// A . - public JToken SelectToken(string path, bool errorWhenNoMatch) + public JToken? SelectToken(string path, bool errorWhenNoMatch) + { + JsonSelectSettings? settings = errorWhenNoMatch + ? new JsonSelectSettings { ErrorWhenNoMatch = true } + : null; + + return SelectToken(path, settings); + } + + /// + /// Selects a using a JSONPath expression. Selects the token that matches the object path. + /// + /// + /// A that contains a JSONPath expression. + /// + /// The used to select tokens. + /// A . + public JToken? SelectToken(string path, JsonSelectSettings? settings) { JPath p = new JPath(path); - JToken token = null; - foreach (JToken t in p.Evaluate(this, this, errorWhenNoMatch)) + JToken? token = null; + foreach (JToken t in p.Evaluate(this, this, settings)) { if (token != null) { @@ -2328,29 +2364,46 @@ public JToken SelectToken(string path, bool errorWhenNoMatch) } /// - /// Selects a collection of elements using a JPath expression. + /// Selects a collection of elements using a JSONPath expression. /// /// - /// A that contains a JPath expression. + /// A that contains a JSONPath expression. /// /// An of that contains the selected elements. public IEnumerable SelectTokens(string path) { - return SelectTokens(path, false); + return SelectTokens(path, settings: null); } /// - /// Selects a collection of elements using a JPath expression. + /// Selects a collection of elements using a JSONPath expression. /// /// - /// A that contains a JPath expression. + /// A that contains a JSONPath expression. /// /// A flag to indicate whether an error should be thrown if no tokens are found when evaluating part of the expression. /// An of that contains the selected elements. public IEnumerable SelectTokens(string path, bool errorWhenNoMatch) { - JPath p = new JPath(path); - return p.Evaluate(this, this, errorWhenNoMatch); + JsonSelectSettings? settings = errorWhenNoMatch + ? new JsonSelectSettings { ErrorWhenNoMatch = true } + : null; + + return SelectTokens(path, settings); + } + + /// + /// Selects a collection of elements using a JSONPath expression. + /// + /// + /// A that contains a JSONPath expression. + /// + /// The used to select tokens. + /// An of that contains the selected elements. + public IEnumerable SelectTokens(string path, JsonSelectSettings? settings) + { + var p = new JPath(path); + return p.Evaluate(this, this, settings); } #if HAVE_DYNAMIC @@ -2438,7 +2491,7 @@ public void AddAnnotation(object annotation) /// /// The type of the annotation to retrieve. /// The first annotation object that matches the specified type, or null if no annotation is of the specified type. - public T Annotation() where T : class + public T? Annotation() where T : class { if (_annotations != null) { @@ -2469,7 +2522,7 @@ public T Annotation() where T : class /// /// The of the annotation to retrieve. /// The first annotation object that matches the specified type, or null if no annotation is of the specified type. - public object Annotation(Type type) + public object? Annotation(Type type) { if (type == null) { @@ -2595,7 +2648,7 @@ public void RemoveAnnotations() where T : class { if (_annotations != null) { - if (!(_annotations is object[] annotations)) + if (!(_annotations is object?[] annotations)) { if (_annotations is T) { @@ -2608,7 +2661,7 @@ public void RemoveAnnotations() where T : class int keepCount = 0; while (index < annotations.Length) { - object obj2 = annotations[index]; + object? obj2 = annotations[index]; if (obj2 == null) { break; @@ -2650,7 +2703,7 @@ public void RemoveAnnotations(Type type) if (_annotations != null) { - if (!(_annotations is object[] annotations)) + if (!(_annotations is object?[] annotations)) { if (type.IsInstanceOfType(_annotations)) { @@ -2663,7 +2716,7 @@ public void RemoveAnnotations(Type type) int keepCount = 0; while (index < annotations.Length) { - object o = annotations[index]; + object? o = annotations[index]; if (o == null) { break; @@ -2691,5 +2744,19 @@ public void RemoveAnnotations(Type type) } } } + + internal void CopyAnnotations(JToken target, JToken source) + { + if (source._annotations is object[] annotations) + { + target._annotations = annotations.ToArray(); + } + else + { + target._annotations = source._annotations; + } + } } -} \ No newline at end of file +#nullable disable +#pragma warning disable CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenEqualityComparer.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenEqualityComparer.cs index 374057668f..85095b9691 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenEqualityComparer.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenEqualityComparer.cs @@ -27,6 +27,7 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable /// /// Compares tokens to determine whether they are equal. /// @@ -40,7 +41,7 @@ internal class JTokenEqualityComparer : IEqualityComparer /// /// true if the specified objects are equal; otherwise, false. /// - public bool Equals(JToken x, JToken y) + public bool Equals(JToken? x, JToken? y) { return JToken.DeepEquals(x, y); } @@ -61,4 +62,5 @@ public int GetHashCode(JToken obj) return obj.GetDeepHashCode(); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenReader.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenReader.cs index 2927f6dc9b..2b4b6fabb8 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenReader.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenReader.cs @@ -28,20 +28,21 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable /// /// Represents a reader that provides fast, non-cached, forward-only access to serialized JSON data. /// internal class JTokenReader : JsonReader, IJsonLineInfo { private readonly JToken _root; - private string _initialPath; - private JToken _parent; - private JToken _current; + private string? _initialPath; + private JToken? _parent; + private JToken? _current; /// /// Gets the at the reader's current position. /// - public JToken CurrentToken => _current; + public JToken? CurrentToken => _current; /// /// Initializes a new instance of the class. @@ -54,8 +55,12 @@ public JTokenReader(JToken token) _root = token; } - // this is used by json.net schema - internal JTokenReader(JToken token, string initialPath) + /// + /// Initializes a new instance of the class. + /// + /// The token to read from. + /// The initial path of the token. It is prepended to the returned . + public JTokenReader(JToken token, string initialPath) : this(token) { _initialPath = initialPath; @@ -86,6 +91,12 @@ public override bool Read() } } + // The current value could already be the root value if it is a comment + if (_current == _root) + { + return false; + } + _current = _root; SetToken(_current); return true; @@ -98,8 +109,8 @@ private bool ReadOver(JToken t) return ReadToEnd(); } - JToken next = t.Next; - if ((next == null || next == t) || t == t.Parent.Last) + JToken? next = t.Next; + if ((next == null || next == t) || t == t.Parent!.Last) { if (t.Parent == null) { @@ -142,7 +153,7 @@ private bool ReadToEnd() private bool ReadInto(JContainer c) { - JToken firstChild = c.First; + JToken? firstChild = c.First; if (firstChild == null) { return SetEnd(c); @@ -211,7 +222,7 @@ private void SetToken(JToken token) break; case JTokenType.Date: { - object v = ((JValue)token).Value; + object? v = ((JValue)token).Value; if (v is DateTime dt) { v = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling); @@ -231,7 +242,7 @@ private void SetToken(JToken token) break; case JTokenType.Uri: { - object v = ((JValue)token).Value; + object? v = ((JValue)token).Value; SetToken(JsonToken.String, v is Uri uri ? uri.OriginalString : SafeToString(v)); break; } @@ -243,7 +254,7 @@ private void SetToken(JToken token) } } - private string SafeToString(object value) + private string? SafeToString(object? value) { return value?.ToString(); } @@ -255,7 +266,7 @@ bool IJsonLineInfo.HasLineInfo() return false; } - IJsonLineInfo info = _current; + IJsonLineInfo? info = _current; return (info != null && info.HasLineInfo()); } @@ -268,7 +279,7 @@ int IJsonLineInfo.LineNumber return 0; } - IJsonLineInfo info = _current; + IJsonLineInfo? info = _current; if (info != null) { return info.LineNumber; @@ -287,7 +298,7 @@ int IJsonLineInfo.LinePosition return 0; } - IJsonLineInfo info = _current; + IJsonLineInfo? info = _current; if (info != null) { return info.LinePosition; @@ -298,7 +309,7 @@ int IJsonLineInfo.LinePosition } /// - /// Gets the path of the current JSON token. + /// Gets the path of the current JSON token. /// public override string Path { @@ -311,9 +322,9 @@ public override string Path _initialPath = _root.Path; } - if (!string.IsNullOrEmpty(_initialPath)) + if (!StringUtils.IsNullOrEmpty(_initialPath)) { - if (string.IsNullOrEmpty(path)) + if (StringUtils.IsNullOrEmpty(path)) { return _initialPath; } @@ -332,4 +343,5 @@ public override string Path } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenType.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenType.cs index efa6679ed5..bea656dd77 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenType.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenType.cs @@ -120,4 +120,4 @@ internal enum JTokenType /// TimeSpan = 17 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenWriter.Async.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenWriter.Async.cs index 4508380ccf..07b8f0bb72 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenWriter.Async.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenWriter.Async.cs @@ -50,4 +50,4 @@ internal override Task WriteTokenAsync(JsonReader reader, bool writeChildren, bo } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenWriter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenWriter.cs index 7376dd303c..941ff14a6e 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenWriter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JTokenWriter.cs @@ -24,6 +24,7 @@ #endregion using System; +using System.Diagnostics; using System.Globalization; #if HAVE_BIG_INTEGER using System.Numerics; @@ -32,27 +33,29 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable +#pragma warning disable CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly /// /// Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data. /// internal partial class JTokenWriter : JsonWriter { - private JContainer _token; - private JContainer _parent; + private JContainer? _token; + private JContainer? _parent; // used when writer is writing single value and the value has no containing parent - private JValue _value; - private JToken _current; + private JValue? _value; + private JToken? _current; /// /// Gets the at the writer's current position. /// - public JToken CurrentToken => _current; + public JToken? CurrentToken => _current; /// /// Gets the token being written. /// /// The token being written. - public JToken Token + public JToken? Token { get { @@ -131,7 +134,7 @@ private void AddParent(JContainer container) private void RemoveParent() { _current = _parent; - _parent = _parent.Parent; + _parent = _parent!.Parent; if (_parent != null && _parent.Type == JTokenType.Property) { @@ -186,21 +189,26 @@ public override void WritePropertyName(string name) base.WritePropertyName(name); } - private void AddValue(object value, JsonToken token) + private void AddRawValue(object? value, JTokenType type, JsonToken token) { - AddValue(new JValue(value), token); + AddJValue(new JValue(value, type), token); } - internal void AddValue(JValue value, JsonToken token) + internal void AddJValue(JValue? value, JsonToken token) { if (_parent != null) { - _parent.Add(value); - _current = _parent.Last; - - if (_parent.Type == JTokenType.Property) + // TryAdd will return false if an invalid JToken type is added. + // For example, a JComment can't be added to a JObject. + // If there is an invalid JToken type then skip it. + if (_parent.TryAdd(value)) { - _parent = _parent.Parent; + _current = _parent.Last; + + if (_parent.Type == JTokenType.Property) + { + _parent = _parent.Parent; + } } } else @@ -216,13 +224,13 @@ internal void AddValue(JValue value, JsonToken token) /// An error will be raised if the value cannot be written as a single JSON token. /// /// The value to write. - public override void WriteValue(object value) + public override void WriteValue(object? value) { #if HAVE_BIG_INTEGER if (value is BigInteger) { InternalWriteValue(JsonToken.Integer); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } else #endif @@ -237,7 +245,7 @@ public override void WriteValue(object value) public override void WriteNull() { base.WriteNull(); - AddValue(null, JsonToken.Null); + AddJValue(JValue.CreateNull(), JsonToken.Null); } /// @@ -246,37 +254,37 @@ public override void WriteNull() public override void WriteUndefined() { base.WriteUndefined(); - AddValue(null, JsonToken.Undefined); + AddJValue(JValue.CreateUndefined(), JsonToken.Undefined); } /// /// Writes raw JSON. /// /// The raw JSON to write. - public override void WriteRaw(string json) + public override void WriteRaw(string? json) { base.WriteRaw(json); - AddValue(new JRaw(json), JsonToken.Raw); + AddJValue(new JRaw(json), JsonToken.Raw); } /// /// Writes a comment /*...*/ containing the specified text. /// /// Text to place inside the comment. - public override void WriteComment(string text) + public override void WriteComment(string? text) { base.WriteComment(text); - AddValue(JValue.CreateComment(text), JsonToken.Comment); + AddJValue(JValue.CreateComment(text), JsonToken.Comment); } /// /// Writes a value. /// /// The value to write. - public override void WriteValue(string value) + public override void WriteValue(string? value) { base.WriteValue(value); - AddValue(value, JsonToken.String); + AddJValue(new JValue(value), JsonToken.String); } /// @@ -286,18 +294,18 @@ public override void WriteValue(string value) public override void WriteValue(int value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } /// /// Writes a value. /// /// The value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override void WriteValue(uint value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } /// @@ -307,18 +315,18 @@ public override void WriteValue(uint value) public override void WriteValue(long value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddJValue(new JValue(value), JsonToken.Integer); } /// /// Writes a value. /// /// The value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override void WriteValue(ulong value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddJValue(new JValue(value), JsonToken.Integer); } /// @@ -328,7 +336,7 @@ public override void WriteValue(ulong value) public override void WriteValue(float value) { base.WriteValue(value); - AddValue(value, JsonToken.Float); + AddJValue(new JValue(value), JsonToken.Float); } /// @@ -338,7 +346,7 @@ public override void WriteValue(float value) public override void WriteValue(double value) { base.WriteValue(value); - AddValue(value, JsonToken.Float); + AddJValue(new JValue(value), JsonToken.Float); } /// @@ -348,7 +356,7 @@ public override void WriteValue(double value) public override void WriteValue(bool value) { base.WriteValue(value); - AddValue(value, JsonToken.Boolean); + AddJValue(new JValue(value), JsonToken.Boolean); } /// @@ -358,18 +366,18 @@ public override void WriteValue(bool value) public override void WriteValue(short value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } /// /// Writes a value. /// /// The value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override void WriteValue(ushort value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } /// @@ -383,11 +391,9 @@ public override void WriteValue(char value) #if HAVE_CHAR_TO_STRING_WITH_CULTURE s = value.ToString(CultureInfo.InvariantCulture); #else -#pragma warning disable CA1305 // Specify IFormatProvider s = value.ToString(); -#pragma warning restore CA1305 // Specify IFormatProvider #endif - AddValue(s, JsonToken.String); + AddJValue(new JValue(s), JsonToken.String); } /// @@ -397,18 +403,18 @@ public override void WriteValue(char value) public override void WriteValue(byte value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } /// /// Writes a value. /// /// The value to write. - // [ClsCompliant(false)] + [CLSCompliant(false)] public override void WriteValue(sbyte value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } /// @@ -418,7 +424,7 @@ public override void WriteValue(sbyte value) public override void WriteValue(decimal value) { base.WriteValue(value); - AddValue(value, JsonToken.Float); + AddJValue(new JValue(value), JsonToken.Float); } /// @@ -429,7 +435,7 @@ public override void WriteValue(DateTime value) { base.WriteValue(value); value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling); - AddValue(value, JsonToken.Date); + AddJValue(new JValue(value), JsonToken.Date); } #if HAVE_DATE_TIME_OFFSET @@ -440,7 +446,7 @@ public override void WriteValue(DateTime value) public override void WriteValue(DateTimeOffset value) { base.WriteValue(value); - AddValue(value, JsonToken.Date); + AddJValue(new JValue(value), JsonToken.Date); } #endif @@ -448,10 +454,10 @@ public override void WriteValue(DateTimeOffset value) /// Writes a [] value. /// /// The [] value to write. - public override void WriteValue(byte[] value) + public override void WriteValue(byte[]? value) { base.WriteValue(value); - AddValue(value, JsonToken.Bytes); + AddJValue(new JValue(value, JTokenType.Bytes), JsonToken.Bytes); } /// @@ -461,7 +467,7 @@ public override void WriteValue(byte[] value) public override void WriteValue(TimeSpan value) { base.WriteValue(value); - AddValue(value, JsonToken.String); + AddJValue(new JValue(value), JsonToken.String); } /// @@ -471,17 +477,17 @@ public override void WriteValue(TimeSpan value) public override void WriteValue(Guid value) { base.WriteValue(value); - AddValue(value, JsonToken.String); + AddJValue(new JValue(value), JsonToken.String); } /// /// Writes a value. /// /// The value to write. - public override void WriteValue(Uri value) + public override void WriteValue(Uri? value) { base.WriteValue(value); - AddValue(value, JsonToken.String); + AddJValue(new JValue(value), JsonToken.String); } #endregion @@ -498,7 +504,7 @@ internal override void WriteToken(JsonReader reader, bool writeChildren, bool wr } } - JToken value = tokenReader.CurrentToken.CloneToken(); + JToken value = tokenReader.CurrentToken!.CloneToken(); if (_parent != null) { @@ -531,4 +537,6 @@ internal override void WriteToken(JsonReader reader, bool writeChildren, bool wr } } } -} \ No newline at end of file +#nullable disable +#pragma warning restore CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JValue.Async.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JValue.Async.cs index 97db26b2ba..b49d4a23f6 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JValue.Async.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JValue.Async.cs @@ -36,9 +36,8 @@ namespace Microsoft.IdentityModel.Json.Linq { -#pragma warning disable CA1036 // Should define operators since implements IComparable +#nullable enable internal partial class JValue -#pragma warning restore CA1036 // Should define operators since implements IComparable { /// /// Writes this token to a asynchronously. @@ -51,7 +50,7 @@ public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellat { if (converters != null && converters.Length > 0 && _value != null) { - JsonConverter matchingConverter = JsonSerializer.GetMatchingConverter(converters, _value.GetType()); + JsonConverter? matchingConverter = JsonSerializer.GetMatchingConverter(converters, _value.GetType()); if (matchingConverter != null && matchingConverter.CanWrite) { // TODO: Call WriteJsonAsync when it exists. @@ -123,18 +122,19 @@ public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellat return writer.WriteValueAsync(Convert.ToDateTime(_value, CultureInfo.InvariantCulture), cancellationToken); case JTokenType.Bytes: - return writer.WriteValueAsync((byte[])_value, cancellationToken); + return writer.WriteValueAsync((byte[]?)_value, cancellationToken); case JTokenType.Guid: return writer.WriteValueAsync(_value != null ? (Guid?)_value : null, cancellationToken); case JTokenType.TimeSpan: return writer.WriteValueAsync(_value != null ? (TimeSpan?)_value : null, cancellationToken); case JTokenType.Uri: - return writer.WriteValueAsync((Uri)_value, cancellationToken); + return writer.WriteValueAsync((Uri?)_value, cancellationToken); } throw MiscellaneousUtils.CreateArgumentOutOfRangeException(nameof(Type), _valueType, "Unexpected token type."); } } +#nullable disable } #endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JValue.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JValue.cs index 28dd87fcdd..811e3136dc 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JValue.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JValue.cs @@ -28,6 +28,8 @@ using System.Diagnostics; using Microsoft.IdentityModel.Json.Utilities; using System.Globalization; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if HAVE_DYNAMIC using System.Dynamic; using System.Linq.Expressions; @@ -38,6 +40,8 @@ namespace Microsoft.IdentityModel.Json.Linq { +#nullable enable +#pragma warning disable CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly /// /// Represents a value in JSON (string, integer, date, etc). /// @@ -47,9 +51,9 @@ internal partial class JValue : JToken, IEquatable, IFormattable, ICompa #endif { private JTokenType _valueType; - private object _value; + private object? _value; - internal JValue(object value, JTokenType type) + internal JValue(object? value, JTokenType type) { _value = value; _valueType = type; @@ -62,6 +66,7 @@ internal JValue(object value, JTokenType type) public JValue(JValue other) : this(other.Value, other.Type) { + CopyAnnotations(this, other); } /// @@ -69,7 +74,7 @@ public JValue(JValue other) /// /// The value. public JValue(long value) - : this(value, JTokenType.Integer) + : this(BoxedPrimitives.Get(value), JTokenType.Integer) { } @@ -78,7 +83,7 @@ public JValue(long value) /// /// The value. public JValue(decimal value) - : this(value, JTokenType.Float) + : this(BoxedPrimitives.Get(value), JTokenType.Float) { } @@ -95,7 +100,7 @@ public JValue(char value) /// Initializes a new instance of the class with the given value. /// /// The value. - // [ClsCompliant(false)] + [CLSCompliant(false)] public JValue(ulong value) : this(value, JTokenType.Integer) { @@ -106,7 +111,7 @@ public JValue(ulong value) /// /// The value. public JValue(double value) - : this(value, JTokenType.Float) + : this(BoxedPrimitives.Get(value), JTokenType.Float) { } @@ -144,7 +149,7 @@ public JValue(DateTimeOffset value) /// /// The value. public JValue(bool value) - : this(value, JTokenType.Boolean) + : this(BoxedPrimitives.Get(value), JTokenType.Boolean) { } @@ -152,7 +157,7 @@ public JValue(bool value) /// Initializes a new instance of the class with the given value. /// /// The value. - public JValue(string value) + public JValue(string? value) : this(value, JTokenType.String) { } @@ -170,7 +175,7 @@ public JValue(Guid value) /// Initializes a new instance of the class with the given value. /// /// The value. - public JValue(Uri value) + public JValue(Uri? value) : this(value, (value != null) ? JTokenType.Uri : JTokenType.Null) { } @@ -188,7 +193,7 @@ public JValue(TimeSpan value) /// Initializes a new instance of the class with the given value. /// /// The value. - public JValue(object value) + public JValue(object? value) : this(value, GetValueType(null, value)) { } @@ -241,7 +246,7 @@ private static int CompareBigInteger(BigInteger i1, object i2) } #endif - internal static int Compare(JTokenType valueType, object objA, object objB) + internal static int Compare(JTokenType valueType, object? objA, object? objB) { if (objA == objB) { @@ -267,8 +272,8 @@ internal static int Compare(JTokenType valueType, object objA, object objB) } if (objB is BigInteger integerB) { - return -CompareBigInteger(integerB, objA); - } + return -CompareBigInteger(integerB, objA); + } #endif if (objA is ulong || objB is ulong || objA is decimal || objB is decimal) { @@ -300,12 +305,12 @@ internal static int Compare(JTokenType valueType, object objA, object objB) return Convert.ToDecimal(objA, CultureInfo.InvariantCulture).CompareTo(Convert.ToDecimal(objB, CultureInfo.InvariantCulture)); } return CompareFloat(objA, objB); - } + } case JTokenType.Comment: case JTokenType.String: case JTokenType.Raw: - string s1 = Convert.ToString(objA, CultureInfo.InvariantCulture); - string s2 = Convert.ToString(objB, CultureInfo.InvariantCulture); + string? s1 = Convert.ToString(objA, CultureInfo.InvariantCulture); + string? s2 = Convert.ToString(objB, CultureInfo.InvariantCulture); return string.CompareOrdinal(s1, s2); case JTokenType.Boolean: @@ -353,10 +358,10 @@ internal static int Compare(JTokenType valueType, object objA, object objB) throw new ArgumentException("Object must be of type byte[]."); } - byte[] bytesA = objA as byte[]; - Debug.Assert(bytesA != null); + byte[]? bytesA = objA as byte[]; + MiscellaneousUtils.Assert(bytesA != null); - return MiscellaneousUtils.ByteArrayCompare(bytesA, bytesB); + return MiscellaneousUtils.ByteArrayCompare(bytesA!, bytesB); case JTokenType.Guid: if (!(objB is Guid)) { @@ -368,7 +373,7 @@ internal static int Compare(JTokenType valueType, object objA, object objB) return guid1.CompareTo(guid2); case JTokenType.Uri: - Uri uri2 = objB as Uri; + Uri? uri2 = objB as Uri; if (uri2 == null) { throw new ArgumentException("Object must be of type Uri."); @@ -407,7 +412,7 @@ private static int CompareFloat(object objA, object objB) } #if HAVE_EXPRESSIONS - private static bool Operation(ExpressionType operation, object objA, object objB, out object result) + private static bool Operation(ExpressionType operation, object? objA, object? objB, out object? result) { if (objA is string || objB is string) { @@ -564,7 +569,7 @@ internal override JToken CloneToken() /// /// The value. /// A comment with the given value. - public static JValue CreateComment(string value) + public static JValue CreateComment(string? value) { return new JValue(value, JTokenType.Comment); } @@ -574,7 +579,7 @@ public static JValue CreateComment(string value) /// /// The value. /// A string with the given value. - public static JValue CreateString(string value) + public static JValue CreateString(string? value) { return new JValue(value, JTokenType.String); } @@ -597,7 +602,7 @@ public static JValue CreateUndefined() return new JValue(null, JTokenType.Undefined); } - private static JTokenType GetValueType(JTokenType? current, object value) + private static JTokenType GetValueType(JTokenType? current, object? value) { if (value == null) { @@ -694,13 +699,13 @@ private static JTokenType GetStringValueType(JTokenType? current) /// Gets or sets the underlying token value. /// /// The underlying token value. - public object Value + public object? Value { get => _value; set { - Type currentType = _value?.GetType(); - Type newType = value?.GetType(); + Type? currentType = _value?.GetType(); + Type? newType = value?.GetType(); if (currentType != newType) { @@ -720,7 +725,7 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter { if (converters != null && converters.Length > 0 && _value != null) { - JsonConverter matchingConverter = JsonSerializer.GetMatchingConverter(converters, _value.GetType()); + JsonConverter? matchingConverter = JsonSerializer.GetMatchingConverter(converters, _value.GetType()); if (matchingConverter != null && matchingConverter.CanWrite) { matchingConverter.WriteJson(writer, _value, JsonSerializer.CreateDefault()); @@ -803,7 +808,7 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter } return; case JTokenType.Bytes: - writer.WriteValue((byte[])_value); + writer.WriteValue((byte[]?)_value); return; case JTokenType.Guid: writer.WriteValue((_value != null) ? (Guid?)_value : null); @@ -812,7 +817,7 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter writer.WriteValue((_value != null) ? (TimeSpan?)_value : null); return; case JTokenType.Uri: - writer.WriteValue((Uri)_value); + writer.WriteValue((Uri?)_value); return; } @@ -839,7 +844,7 @@ private static bool ValuesEquals(JValue v1, JValue v2) /// true if the current object is equal to the parameter; otherwise, false. /// /// An object to compare with this object. - public bool Equals(JValue other) + public bool Equals(JValue? other) { if (other == null) { @@ -856,9 +861,14 @@ public bool Equals(JValue other) /// /// true if the specified is equal to the current ; otherwise, false. /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { - return Equals(obj as JValue); + if (obj is JValue v) + { + return Equals(v); + } + + return false; } /// @@ -880,6 +890,10 @@ public override int GetHashCode() /// /// Returns a that represents this instance. /// + /// + /// ToString() returns a non-JSON string value for tokens with a type of . + /// If you want the JSON for all token types then you should use . + /// /// /// A that represents this instance. /// @@ -890,7 +904,7 @@ public override string ToString() return string.Empty; } - return _value.ToString(); + return _value.ToString()!; } /// @@ -912,7 +926,7 @@ public string ToString(string format) /// /// A that represents this instance. /// - public string ToString(IFormatProvider formatProvider) + public string ToString(IFormatProvider? formatProvider) { return ToString(null, formatProvider); } @@ -925,7 +939,7 @@ public string ToString(IFormatProvider formatProvider) /// /// A that represents this instance. /// - public string ToString(string format, IFormatProvider formatProvider) + public string ToString(string? format, IFormatProvider? formatProvider) { if (_value == null) { @@ -938,7 +952,7 @@ public string ToString(string format, IFormatProvider formatProvider) } else { - return _value.ToString(); + return _value.ToString()!; } } @@ -957,7 +971,7 @@ protected override DynamicMetaObject GetMetaObject(Expression parameter) private class JValueDynamicProxy : DynamicProxy { - public override bool TryConvert(JValue instance, ConvertBinder binder, out object result) + public override bool TryConvert(JValue instance, ConvertBinder binder, [NotNullWhen(true)]out object? result) { if (binder.Type == typeof(JValue) || binder.Type == typeof(JToken)) { @@ -965,7 +979,7 @@ public override bool TryConvert(JValue instance, ConvertBinder binder, out objec return true; } - object value = instance.Value; + object? value = instance.Value; if (value == null) { @@ -977,9 +991,9 @@ public override bool TryConvert(JValue instance, ConvertBinder binder, out objec return true; } - public override bool TryBinaryOperation(JValue instance, BinaryOperationBinder binder, object arg, out object result) + public override bool TryBinaryOperation(JValue instance, BinaryOperationBinder binder, object arg, [NotNullWhen(true)]out object? result) { - object compareValue = arg is JValue value ? value.Value : arg; + object? compareValue = arg is JValue value ? value.Value : arg; switch (binder.Operation) { @@ -1023,7 +1037,7 @@ public override bool TryBinaryOperation(JValue instance, BinaryOperationBinder b } #endif - int IComparable.CompareTo(object obj) + int IComparable.CompareTo(object? obj) { if (obj == null) { @@ -1031,7 +1045,7 @@ int IComparable.CompareTo(object obj) } JTokenType comparisonType; - object otherValue; + object? otherValue; if (obj is JValue value) { otherValue = value.Value; @@ -1066,7 +1080,7 @@ int IComparable.CompareTo(object obj) /// /// is not of the same type as this instance. /// - public int CompareTo(JValue obj) + public int CompareTo(JValue? obj) { if (obj == null) { @@ -1096,80 +1110,82 @@ TypeCode IConvertible.GetTypeCode() return TypeCode.Object; } - bool IConvertible.ToBoolean(IFormatProvider provider) + bool IConvertible.ToBoolean(IFormatProvider? provider) { return (bool)this; } - char IConvertible.ToChar(IFormatProvider provider) + char IConvertible.ToChar(IFormatProvider? provider) { return (char)this; } - sbyte IConvertible.ToSByte(IFormatProvider provider) + sbyte IConvertible.ToSByte(IFormatProvider? provider) { return (sbyte)this; } - byte IConvertible.ToByte(IFormatProvider provider) + byte IConvertible.ToByte(IFormatProvider? provider) { return (byte)this; } - short IConvertible.ToInt16(IFormatProvider provider) + short IConvertible.ToInt16(IFormatProvider? provider) { return (short)this; } - ushort IConvertible.ToUInt16(IFormatProvider provider) + ushort IConvertible.ToUInt16(IFormatProvider? provider) { return (ushort)this; } - int IConvertible.ToInt32(IFormatProvider provider) + int IConvertible.ToInt32(IFormatProvider? provider) { return (int)this; } - uint IConvertible.ToUInt32(IFormatProvider provider) + uint IConvertible.ToUInt32(IFormatProvider? provider) { return (uint)this; } - long IConvertible.ToInt64(IFormatProvider provider) + long IConvertible.ToInt64(IFormatProvider? provider) { return (long)this; } - ulong IConvertible.ToUInt64(IFormatProvider provider) + ulong IConvertible.ToUInt64(IFormatProvider? provider) { return (ulong)this; } - float IConvertible.ToSingle(IFormatProvider provider) + float IConvertible.ToSingle(IFormatProvider? provider) { return (float)this; } - double IConvertible.ToDouble(IFormatProvider provider) + double IConvertible.ToDouble(IFormatProvider? provider) { return (double)this; } - decimal IConvertible.ToDecimal(IFormatProvider provider) + decimal IConvertible.ToDecimal(IFormatProvider? provider) { return (decimal)this; } - DateTime IConvertible.ToDateTime(IFormatProvider provider) + DateTime IConvertible.ToDateTime(IFormatProvider? provider) { return (DateTime)this; } - object IConvertible.ToType(Type conversionType, IFormatProvider provider) + object IConvertible.ToType(Type conversionType, IFormatProvider? provider) { - return ToObject(conversionType); + return ToObject(conversionType)!; } #endif } +#nullable disable +#pragma warning restore CS3019 // CLS compliance checking will not be performed because it is not visible from outside this assembly } diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonLoadSettings.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonLoadSettings.cs index e9ef1c1805..e0bde4290a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonLoadSettings.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonLoadSettings.cs @@ -9,6 +9,7 @@ internal class JsonLoadSettings { private CommentHandling _commentHandling; private LineInfoHandling _lineInfoHandling; + private DuplicatePropertyNameHandling _duplicatePropertyNameHandling; /// /// Initializes a new instance of the class. @@ -17,10 +18,12 @@ public JsonLoadSettings() { _lineInfoHandling = LineInfoHandling.Load; _commentHandling = CommentHandling.Ignore; + _duplicatePropertyNameHandling = DuplicatePropertyNameHandling.Replace; } /// /// Gets or sets how JSON comments are handled when loading JSON. + /// The default value is . /// /// The JSON comment handling. public CommentHandling CommentHandling @@ -39,6 +42,7 @@ public CommentHandling CommentHandling /// /// Gets or sets how JSON line info is handled when loading JSON. + /// The default value is . /// /// The JSON line info handling. public LineInfoHandling LineInfoHandling @@ -54,5 +58,24 @@ public LineInfoHandling LineInfoHandling _lineInfoHandling = value; } } + + /// + /// Gets or sets how duplicate property names in JSON objects are handled when loading JSON. + /// The default value is . + /// + /// The JSON duplicate property name handling. + public DuplicatePropertyNameHandling DuplicatePropertyNameHandling + { + get => _duplicatePropertyNameHandling; + set + { + if (value < DuplicatePropertyNameHandling.Replace || value > DuplicatePropertyNameHandling.Error) + { + throw new ArgumentOutOfRangeException(nameof(value)); + } + + _duplicatePropertyNameHandling = value; + } + } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonMergeSettings.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonMergeSettings.cs index 83875c0df3..c25b88d7e4 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonMergeSettings.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonMergeSettings.cs @@ -100,4 +100,4 @@ public StringComparison PropertyNameComparison } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/ArrayIndexFilter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/ArrayIndexFilter.cs index e63422dfd7..d4aa95842f 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/ArrayIndexFilter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/ArrayIndexFilter.cs @@ -4,17 +4,18 @@ namespace Microsoft.IdentityModel.Json.Linq.JsonPath { +#nullable enable internal class ArrayIndexFilter : PathFilter { public int? Index { get; set; } - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken t in current) { if (Index != null) { - JToken v = GetTokenIndex(t, errorWhenNoMatch, Index.GetValueOrDefault()); + JToken? v = GetTokenIndex(t, settings, Index.GetValueOrDefault()); if (v != null) { @@ -32,7 +33,7 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable Indexes { get; set; } + internal List Indexes; - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public ArrayMultipleIndexFilter(List indexes) + { + Indexes = indexes; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken t in current) { foreach (int i in Indexes) { - JToken v = GetTokenIndex(t, errorWhenNoMatch, i); + JToken? v = GetTokenIndex(t, settings, i); if (v != null) { @@ -22,4 +28,5 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { if (Step == 0) { @@ -56,7 +57,7 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable stopIndex); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/FieldFilter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/FieldFilter.cs index b9a0db062f..0f6ad2ccd6 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/FieldFilter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/FieldFilter.cs @@ -4,11 +4,17 @@ namespace Microsoft.IdentityModel.Json.Linq.JsonPath { +#nullable enable internal class FieldFilter : PathFilter { - public string Name { get; set; } + internal string? Name; - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public FieldFilter(string? name) + { + Name = name; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken t in current) { @@ -16,28 +22,28 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable p in o) + foreach (KeyValuePair p in o) { - yield return p.Value; + yield return p.Value!; } } } else { - if (errorWhenNoMatch) + if (settings?.ErrorWhenNoMatch ?? false) { throw new JsonException("Property '{0}' not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, Name ?? "*", t.GetType().Name)); } @@ -45,4 +51,5 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable Names { get; set; } + internal List Names; - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public FieldMultipleFilter(List names) + { + Names = names; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken t in current) { @@ -21,14 +27,14 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable "'" + n + "'") #if !HAVE_STRING_JOIN_WITH_ENUMERABLE @@ -48,4 +54,5 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable filters, int currentPartStartIndex, bool case '(': if (_currentIndex > currentPartStartIndex) { - string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex); + string? member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex); if (member == "*") { member = null; @@ -118,6 +119,8 @@ private bool ParsePath(List filters, int currentPartStartIndex, bool } filters.Add(ParseIndexer(currentChar, scan)); + scan = false; + _currentIndex++; currentPartStartIndex = _currentIndex; followingIndexer = true; @@ -136,7 +139,7 @@ private bool ParsePath(List filters, int currentPartStartIndex, bool case '.': if (_currentIndex > currentPartStartIndex) { - string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex); + string? member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex); if (member == "*") { member = null; @@ -177,7 +180,7 @@ private bool ParsePath(List filters, int currentPartStartIndex, bool if (_currentIndex > currentPartStartIndex) { - string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex).TrimEnd(); + string? member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex).TrimEnd(); if (member == "*") { member = null; @@ -196,9 +199,9 @@ private bool ParsePath(List filters, int currentPartStartIndex, bool return atPathEnd; } - private static PathFilter CreatePathFilter(string member, bool scan) + private static PathFilter CreatePathFilter(string? member, bool scan) { - PathFilter filter = (scan) ? (PathFilter)new ScanFilter {Name = member} : new FieldFilter {Name = member}; + PathFilter filter = (scan) ? (PathFilter)new ScanFilter(member) : new FieldFilter(member); return filter; } @@ -230,7 +233,7 @@ private PathFilter ParseArrayIndexer(char indexerCloseChar) { int start = _currentIndex; int? end = null; - List indexes = null; + List? indexes = null; int colonCount = 0; int? startIndex = null; int? endIndex = null; @@ -262,7 +265,7 @@ private PathFilter ParseArrayIndexer(char indexerCloseChar) int index = Convert.ToInt32(indexer, CultureInfo.InvariantCulture); indexes.Add(index); - return new ArrayMultipleIndexFilter { Indexes = indexes }; + return new ArrayMultipleIndexFilter(indexes); } else if (colonCount > 0) { @@ -421,26 +424,19 @@ private PathFilter ParseQuery(char indexerCloseChar, bool scan) if (!scan) { - return new QueryFilter - { - Expression = expression - }; + return new QueryFilter(expression); } else { - return new QueryScanFilter - { - Expression = expression - }; + return new QueryScanFilter(expression); } } - private bool TryParseExpression(out List expressionPath) + private bool TryParseExpression(out List? expressionPath) { if (_expression[_currentIndex] == '$') { - expressionPath = new List(); - expressionPath.Add(RootFilter.Instance); + expressionPath = new List { RootFilter.Instance }; } else if (_expression[_currentIndex] == '@') { @@ -454,7 +450,7 @@ private bool TryParseExpression(out List expressionPath) _currentIndex++; - if (ParsePath(expressionPath, _currentIndex, true)) + if (ParsePath(expressionPath!, _currentIndex, true)) { throw new JsonException("Path ended with open query."); } @@ -471,12 +467,12 @@ private object ParseSide() { EatWhitespace(); - if (TryParseExpression(out var expressionPath)) + if (TryParseExpression(out List? expressionPath)) { EatWhitespace(); EnsureLength("Path ended with open query."); - return expressionPath; + return expressionPath!; } if (TryParseValue(out var value)) @@ -492,13 +488,13 @@ private object ParseSide() private QueryExpression ParseExpression() { - QueryExpression rootExpression = null; - CompositeExpression parentExpression = null; + QueryExpression? rootExpression = null; + CompositeExpression? parentExpression = null; while (_currentIndex < _expression.Length) { object left = ParseSide(); - object right = null; + object? right = null; QueryOperator op; if (_expression[_currentIndex] == ')' @@ -514,19 +510,14 @@ private QueryExpression ParseExpression() right = ParseSide(); } - BooleanQueryExpression booleanExpression = new BooleanQueryExpression - { - Left = left, - Operator = op, - Right = right - }; + BooleanQueryExpression booleanExpression = new BooleanQueryExpression(op, left, right); if (_expression[_currentIndex] == ')') { if (parentExpression != null) { parentExpression.Expressions.Add(booleanExpression); - return rootExpression; + return rootExpression!; } return booleanExpression; @@ -540,7 +531,7 @@ private QueryExpression ParseExpression() if (parentExpression == null || parentExpression.Operator != QueryOperator.And) { - CompositeExpression andExpression = new CompositeExpression { Operator = QueryOperator.And }; + CompositeExpression andExpression = new CompositeExpression(QueryOperator.And); parentExpression?.Expressions.Add(andExpression); @@ -563,7 +554,7 @@ private QueryExpression ParseExpression() if (parentExpression == null || parentExpression.Operator != QueryOperator.Or) { - CompositeExpression orExpression = new CompositeExpression { Operator = QueryOperator.Or }; + CompositeExpression orExpression = new CompositeExpression(QueryOperator.Or); parentExpression?.Expressions.Add(orExpression); @@ -582,7 +573,7 @@ private QueryExpression ParseExpression() throw new JsonException("Path ended with open query."); } - private bool TryParseValue(out object value) + private bool TryParseValue(out object? value) { char currentChar = _expression[_currentIndex]; if (currentChar == '\'') @@ -763,9 +754,9 @@ private string ReadRegexString() private bool Match(string s) { int currentPosition = _currentIndex; - foreach (char c in s) + for (int i = 0; i < s.Length; i++) { - if (currentPosition < _expression.Length && _expression[currentPosition] == c) + if (currentPosition < _expression.Length && _expression[currentPosition] == s[i]) { currentPosition++; } @@ -832,7 +823,7 @@ private QueryOperator ParseOperator() private PathFilter ParseQuotedField(char indexerCloseChar, bool scan) { - List fields = null; + List? fields = null; while (_currentIndex < _expression.Length) { @@ -847,8 +838,8 @@ private PathFilter ParseQuotedField(char indexerCloseChar, bool scan) { fields.Add(field); return (scan) - ? (PathFilter)new ScanMultipleFilter { Names = fields } - : (PathFilter)new FieldMultipleFilter { Names = fields }; + ? (PathFilter)new ScanMultipleFilter(fields) + : (PathFilter)new FieldMultipleFilter(fields); } else { @@ -884,20 +875,21 @@ private void EnsureLength(string message) } } - internal IEnumerable Evaluate(JToken root, JToken t, bool errorWhenNoMatch) + internal IEnumerable Evaluate(JToken root, JToken t, JsonSelectSettings? settings) { - return Evaluate(Filters, root, t, errorWhenNoMatch); + return Evaluate(Filters, root, t, settings); } - internal static IEnumerable Evaluate(List filters, JToken root, JToken t, bool errorWhenNoMatch) + internal static IEnumerable Evaluate(List filters, JToken root, JToken t, JsonSelectSettings? settings) { IEnumerable current = new[] { t }; foreach (PathFilter filter in filters) { - current = filter.ExecuteFilter(root, current, errorWhenNoMatch); + current = filter.ExecuteFilter(root, current, settings); } return current; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/PathFilter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/PathFilter.cs index 66432e0ccc..4495a67ece 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/PathFilter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/PathFilter.cs @@ -4,18 +4,18 @@ namespace Microsoft.IdentityModel.Json.Linq.JsonPath { +#nullable enable internal abstract class PathFilter { - public abstract IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch); + public abstract IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings); - protected static JToken GetTokenIndex(JToken t, bool errorWhenNoMatch, int index) + protected static JToken? GetTokenIndex(JToken t, JsonSelectSettings? settings, int index) { - if (t is JArray a) { if (a.Count <= index) { - if (errorWhenNoMatch) + if (settings?.ErrorWhenNoMatch ?? false) { throw new JsonException("Index {0} outside the bounds of JArray.".FormatWith(CultureInfo.InvariantCulture, index)); } @@ -29,7 +29,7 @@ protected static JToken GetTokenIndex(JToken t, bool errorWhenNoMatch, int index { if (c.Count <= index) { - if (errorWhenNoMatch) + if (settings?.ErrorWhenNoMatch ?? false) { throw new JsonException("Index {0} outside the bounds of JConstructor.".FormatWith(CultureInfo.InvariantCulture, index)); } @@ -41,7 +41,7 @@ protected static JToken GetTokenIndex(JToken t, bool errorWhenNoMatch, int index } else { - if (errorWhenNoMatch) + if (settings?.ErrorWhenNoMatch ?? false) { throw new JsonException("Index {0} not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, index, t.GetType().Name)); } @@ -50,7 +50,7 @@ protected static JToken GetTokenIndex(JToken t, bool errorWhenNoMatch, int index } } - protected static JToken GetNextScanValue(JToken originalParent, JToken container, JToken value) + protected static JToken? GetNextScanValue(JToken originalParent, JToken? container, JToken? value) { // step into container's values if (container != null && container.HasValues) @@ -60,7 +60,7 @@ protected static JToken GetNextScanValue(JToken originalParent, JToken container else { // finished container, move to parent - while (value != null && value != originalParent && value == value.Parent.Last) + while (value != null && value != originalParent && value == value.Parent!.Last) { value = value.Parent; } @@ -78,4 +78,5 @@ protected static JToken GetNextScanValue(JToken originalParent, JToken container return value; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/QueryExpression.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/QueryExpression.cs index 5d0c1f0cad..1cbbb82229 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/QueryExpression.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/QueryExpression.cs @@ -13,6 +13,7 @@ namespace Microsoft.IdentityModel.Json.Linq.JsonPath { +#nullable enable internal enum QueryOperator { None = 0, @@ -32,28 +33,39 @@ internal enum QueryOperator internal abstract class QueryExpression { - public QueryOperator Operator { get; set; } + internal QueryOperator Operator; - public abstract bool IsMatch(JToken root, JToken t); + public QueryExpression(QueryOperator @operator) + { + Operator = @operator; + } + + // For unit tests + public bool IsMatch(JToken root, JToken t) + { + return IsMatch(root, t, null); + } + + public abstract bool IsMatch(JToken root, JToken t, JsonSelectSettings? settings); } internal class CompositeExpression : QueryExpression { public List Expressions { get; set; } - public CompositeExpression() + public CompositeExpression(QueryOperator @operator) : base(@operator) { Expressions = new List(); } - public override bool IsMatch(JToken root, JToken t) + public override bool IsMatch(JToken root, JToken t, JsonSelectSettings? settings) { switch (Operator) { case QueryOperator.And: foreach (QueryExpression e in Expressions) { - if (!e.IsMatch(root, t)) + if (!e.IsMatch(root, t, settings)) { return false; } @@ -62,7 +74,7 @@ public override bool IsMatch(JToken root, JToken t) case QueryOperator.Or: foreach (QueryExpression e in Expressions) { - if (e.IsMatch(root, t)) + if (e.IsMatch(root, t, settings)) { return true; } @@ -76,10 +88,16 @@ public override bool IsMatch(JToken root, JToken t) internal class BooleanQueryExpression : QueryExpression { - public object Left { get; set; } - public object Right { get; set; } + public readonly object Left; + public readonly object? Right; - private IEnumerable GetResult(JToken root, JToken t, object o) + public BooleanQueryExpression(QueryOperator @operator, object left, object? right) : base(@operator) + { + Left = left; + Right = right; + } + + private IEnumerable GetResult(JToken root, JToken t, object? o) { if (o is JToken resultToken) { @@ -88,13 +106,13 @@ private IEnumerable GetResult(JToken root, JToken t, object o) if (o is List pathFilters) { - return JPath.Evaluate(pathFilters, root, t, false); + return JPath.Evaluate(pathFilters, root, t, null); } return CollectionUtils.ArrayEmpty(); } - public override bool IsMatch(JToken root, JToken t) + public override bool IsMatch(JToken root, JToken t, JsonSelectSettings? settings) { if (Operator == QueryOperator.Exists) { @@ -113,7 +131,7 @@ public override bool IsMatch(JToken root, JToken t) JToken leftResult = leftResults.Current; foreach (JToken rightResult in rightResults) { - if (MatchTokens(leftResult, rightResult)) + if (MatchTokens(leftResult, rightResult, settings)) { return true; } @@ -125,14 +143,14 @@ public override bool IsMatch(JToken root, JToken t) return false; } - private bool MatchTokens(JToken leftResult, JToken rightResult) + private bool MatchTokens(JToken leftResult, JToken rightResult, JsonSelectSettings? settings) { if (leftResult is JValue leftValue && rightResult is JValue rightValue) { switch (Operator) { case QueryOperator.RegexEquals: - if (RegexEquals(leftValue, rightValue)) + if (RegexEquals(leftValue, rightValue, settings)) { return true; } @@ -204,20 +222,25 @@ private bool MatchTokens(JToken leftResult, JToken rightResult) return false; } - private static bool RegexEquals(JValue input, JValue pattern) + private static bool RegexEquals(JValue input, JValue pattern, JsonSelectSettings? settings) { if (input.Type != JTokenType.String || pattern.Type != JTokenType.String) { return false; } - string regexText = (string)pattern.Value; + string regexText = (string)pattern.Value!; int patternOptionDelimiterIndex = regexText.LastIndexOf('/'); string patternText = regexText.Substring(1, patternOptionDelimiterIndex - 1); string optionsText = regexText.Substring(patternOptionDelimiterIndex + 1); - return Regex.IsMatch((string)input.Value, patternText, MiscellaneousUtils.GetRegexOptions(optionsText)); +#if HAVE_REGEX_TIMEOUTS + TimeSpan timeout = settings?.RegexMatchTimeout ?? Regex.InfiniteMatchTimeout; + return Regex.IsMatch((string)input.Value!, patternText, MiscellaneousUtils.GetRegexOptions(optionsText), timeout); +#else + return Regex.IsMatch((string)input.Value!, patternText, MiscellaneousUtils.GetRegexOptions(optionsText)); +#endif } internal static bool EqualsWithStringCoercion(JValue value, JValue queryValue) @@ -240,7 +263,7 @@ internal static bool EqualsWithStringCoercion(JValue value, JValue queryValue) return false; } - string queryValueString = (string)queryValue.Value; + string queryValueString = (string)queryValue.Value!; string currentValueString; @@ -258,21 +281,21 @@ internal static bool EqualsWithStringCoercion(JValue value, JValue queryValue) else #endif { - DateTimeUtils.WriteDateTimeString(writer, (DateTime)value.Value, DateFormatHandling.IsoDateFormat, null, CultureInfo.InvariantCulture); + DateTimeUtils.WriteDateTimeString(writer, (DateTime)value.Value!, DateFormatHandling.IsoDateFormat, null, CultureInfo.InvariantCulture); } currentValueString = writer.ToString(); } break; case JTokenType.Bytes: - currentValueString = Convert.ToBase64String((byte[])value.Value); + currentValueString = Convert.ToBase64String((byte[])value.Value!); break; case JTokenType.Guid: case JTokenType.TimeSpan: - currentValueString = value.Value.ToString(); + currentValueString = value.Value!.ToString()!; break; case JTokenType.Uri: - currentValueString = ((Uri)value.Value).OriginalString; + currentValueString = ((Uri)value.Value!).OriginalString; break; default: return false; @@ -283,8 +306,8 @@ internal static bool EqualsWithStringCoercion(JValue value, JValue queryValue) internal static bool EqualsWithStrictMatch(JValue value, JValue queryValue) { - Debug.Assert(value != null); - Debug.Assert(queryValue != null); + MiscellaneousUtils.Assert(value != null); + MiscellaneousUtils.Assert(queryValue != null); // Handle comparing an integer with a float // e.g. Comparing 1 and 1.0 @@ -303,4 +326,5 @@ internal static bool EqualsWithStrictMatch(JValue value, JValue queryValue) return value.Equals(queryValue); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/QueryFilter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/QueryFilter.cs index cf7ae0136c..a03d8bf11b 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/QueryFilter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/QueryFilter.cs @@ -3,17 +3,23 @@ namespace Microsoft.IdentityModel.Json.Linq.JsonPath { +#nullable enable internal class QueryFilter : PathFilter { - public QueryExpression Expression { get; set; } + internal QueryExpression Expression; - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public QueryFilter(QueryExpression expression) + { + Expression = expression; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken t in current) { foreach (JToken v in t) { - if (Expression.IsMatch(root, v)) + if (Expression.IsMatch(root, v, settings)) { yield return v; } @@ -21,4 +27,5 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public QueryScanFilter(QueryExpression expression) + { + Expression = expression; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken t in current) { @@ -15,7 +21,7 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { return new[] { root }; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/ScanFilter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/ScanFilter.cs index eeefc2c6aa..edf4c4879c 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/ScanFilter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/JsonPath/ScanFilter.cs @@ -2,11 +2,17 @@ namespace Microsoft.IdentityModel.Json.Linq.JsonPath { +#nullable enable internal class ScanFilter : PathFilter { - public string Name { get; set; } + internal string? Name; - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public ScanFilter(string? name) + { + Name = name; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken c in current) { @@ -15,11 +21,11 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable Names { get; set; } + private List _names; - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public ScanMultipleFilter(List names) + { + _names = names; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken c in current) { - JToken value = c; + JToken? value = c; while (true) { - JContainer container = value as JContainer; + JContainer? container = value as JContainer; value = GetNextScanValue(c, container, value); if (value == null) @@ -24,7 +30,7 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable + /// Specifies the settings used when selecting JSON. + /// + internal class JsonSelectSettings + { +#if HAVE_REGEX_TIMEOUTS + /// + /// Gets or sets a timeout that will be used when executing regular expressions. + /// + /// The timeout that will be used when executing regular expressions. + public TimeSpan? RegexMatchTimeout { get; set; } +#endif + + /// + /// Gets or sets a flag that indicates whether an error should be thrown if + /// no tokens are found when evaluating part of the expression. + /// + /// + /// A flag that indicates whether an error should be thrown if + /// no tokens are found when evaluating part of the expression. + /// + public bool ErrorWhenNoMatch { get; set; } + } +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/LineInfoHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/LineInfoHandling.cs index 80e045aef6..cf895f0f5c 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/LineInfoHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/LineInfoHandling.cs @@ -40,4 +40,4 @@ internal enum LineInfoHandling /// Load = 1 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/MergeArrayHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/MergeArrayHandling.cs index cde4ac9fee..cb642100a0 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/MergeArrayHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/MergeArrayHandling.cs @@ -17,4 +17,4 @@ internal enum MergeArrayHandling /// Merge array items together, matched by index. Merge = 3 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/MergeNullValueHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/MergeNullValueHandling.cs index de1ca2c55b..096e60007f 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/MergeNullValueHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Linq/MergeNullValueHandling.cs @@ -8,12 +8,10 @@ namespace Microsoft.IdentityModel.Json.Linq [Flags] internal enum MergeNullValueHandling { -#pragma warning disable CA1008 // Enums should have zero value - /// - /// The content's null value properties will be ignored during merging. - /// + /// + /// The content's null value properties will be ignored during merging. + /// Ignore = 0, -#pragma warning restore CA1008 // Enums should have zero value /// /// The content's null value properties will be merged. diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/MetadataPropertyHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/MetadataPropertyHandling.cs index 7c33fd45d3..3b9449ec7a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/MetadataPropertyHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/MetadataPropertyHandling.cs @@ -49,4 +49,4 @@ internal enum MetadataPropertyHandling /// Ignore = 2 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/MissingMemberHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/MissingMemberHandling.cs index 358ff4618d..a7aff0c596 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/MissingMemberHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/MissingMemberHandling.cs @@ -44,4 +44,4 @@ internal enum MissingMemberHandling /// Error = 1 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/NullValueHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/NullValueHandling.cs index 640dcb4fe6..9b4684b179 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/NullValueHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/NullValueHandling.cs @@ -44,4 +44,4 @@ internal enum NullValueHandling /// Ignore = 1 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/ObjectCreationHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/ObjectCreationHandling.cs index c01a4edb98..764eddb649 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/ObjectCreationHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/ObjectCreationHandling.cs @@ -45,4 +45,4 @@ internal enum ObjectCreationHandling /// Replace = 2 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/PreserveReferencesHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/PreserveReferencesHandling.cs index 132bee45b0..6bc7584676 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/PreserveReferencesHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/PreserveReferencesHandling.cs @@ -34,7 +34,7 @@ namespace Microsoft.IdentityModel.Json /// Note that references cannot be preserved when a value is set via a non-default constructor such as types that implement . /// /// - /// + /// /// [Flags] internal enum PreserveReferencesHandling @@ -59,4 +59,4 @@ internal enum PreserveReferencesHandling /// All = Objects | Arrays } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/ReferenceLoopHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/ReferenceLoopHandling.cs index b7e0c5bf3d..a032a3bec8 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/ReferenceLoopHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/ReferenceLoopHandling.cs @@ -49,4 +49,4 @@ internal enum ReferenceLoopHandling /// Serialize = 2 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Required.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Required.cs index 933f1470fc..f293cab186 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Required.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Required.cs @@ -50,4 +50,4 @@ internal enum Required /// DisallowNull = 3 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/Extensions.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/Extensions.cs index f86e2aa711..f724f1ff35 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/Extensions.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/Extensions.cs @@ -28,6 +28,8 @@ using Microsoft.IdentityModel.Json.Linq; using Microsoft.IdentityModel.Json.Utilities; +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { /// @@ -134,4 +136,4 @@ public static void Validate(this JToken source, JsonSchema schema, ValidationEve } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchema.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchema.cs index b86c54f66d..b8917101a4 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchema.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchema.cs @@ -30,8 +30,10 @@ using Microsoft.IdentityModel.Json.Utilities; using System.Globalization; + namespace Microsoft.IdentityModel.Json.Schema { +#nullable disable /// /// /// An in-memory representation of a JSON Schema. @@ -241,9 +243,7 @@ internal class JsonSchema internal string Location { get; set; } -#pragma warning disable CA1305 // Specify IFormatProvider private readonly string _internalId = Guid.NewGuid().ToString("N"); -#pragma warning restore CA1305 // Specify IFormatProvider internal string InternalId => _internalId; @@ -352,4 +352,4 @@ public override string ToString() return writer.ToString(); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaBuilder.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaBuilder.cs index cd862a1feb..c296ec0249 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaBuilder.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaBuilder.cs @@ -35,6 +35,8 @@ using Microsoft.IdentityModel.Json.Utilities; using Microsoft.IdentityModel.Json.Linq; +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] @@ -87,7 +89,10 @@ internal JsonSchema Read(JsonReader reader) private string UnescapeReference(string reference) { - return Uri.UnescapeDataString(reference).Replace("~1", "/").Replace("~0", "~"); + string unescapedReference = Uri.UnescapeDataString(reference); + unescapedReference = StringUtils.Replace(unescapedReference, "~1", "/"); + unescapedReference = StringUtils.Replace(unescapedReference, "~0", "~"); + return unescapedReference; } private JsonSchema ResolveReferences(JsonSchema schema) @@ -218,8 +223,12 @@ private JsonSchema BuildSchema(JToken token) return deferredSchema; } - string location = token.Path.Replace(".", "/").Replace("[", "/").Replace("]", string.Empty); - if (!string.IsNullOrEmpty(location)) + string location = token.Path; + location = StringUtils.Replace(location, ".", "/"); + location = StringUtils.Replace(location, "[", "/"); + location = StringUtils.Replace(location, "]", string.Empty); + + if (!StringUtils.IsNullOrEmpty(location)) { location = "/" + location; } diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaConstants.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaConstants.cs index f980d5074e..131078095a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaConstants.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaConstants.cs @@ -26,6 +26,8 @@ using System; using System.Collections.Generic; +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaException.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaException.cs index 7338c10e18..6d92dbdc49 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaException.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaException.cs @@ -26,6 +26,7 @@ using System; using System.Runtime.Serialization; + namespace Microsoft.IdentityModel.Json.Schema { /// @@ -110,4 +111,4 @@ internal JsonSchemaException(string message, Exception innerException, string pa LinePosition = linePosition; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaGenerator.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaGenerator.cs index 1f3a2ff83a..8758bf2d52 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaGenerator.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaGenerator.cs @@ -37,6 +37,8 @@ #endif +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { /// @@ -173,7 +175,7 @@ private string GetTitle(Type type) { JsonContainerAttribute containerAttribute = JsonTypeReflector.GetCachedAttribute(type); - if (!string.IsNullOrEmpty(containerAttribute?.Title)) + if (!StringUtils.IsNullOrEmpty(containerAttribute?.Title)) { return containerAttribute.Title; } @@ -185,7 +187,7 @@ private string GetDescription(Type type) { JsonContainerAttribute containerAttribute = JsonTypeReflector.GetCachedAttribute(type); - if (!string.IsNullOrEmpty(containerAttribute?.Description)) + if (!StringUtils.IsNullOrEmpty(containerAttribute?.Description)) { return containerAttribute.Description; } @@ -202,7 +204,7 @@ private string GetTypeId(Type type, bool explicitOnly) { JsonContainerAttribute containerAttribute = JsonTypeReflector.GetCachedAttribute(type); - if (!string.IsNullOrEmpty(containerAttribute?.Id)) + if (!StringUtils.IsNullOrEmpty(containerAttribute?.Id)) { return containerAttribute.Id; } @@ -230,7 +232,7 @@ private JsonSchema GenerateInternal(Type type, Required valueRequired, bool requ string resolvedId = GetTypeId(type, false); string explicitId = GetTypeId(type, true); - if (!string.IsNullOrEmpty(resolvedId)) + if (!StringUtils.IsNullOrEmpty(resolvedId)) { JsonSchema resolvedSchema = _resolver.GetSchema(resolvedId); if (resolvedSchema != null) @@ -499,4 +501,4 @@ private JsonSchemaType GetJsonSchemaType(Type type, Required valueRequired) } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaModel.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaModel.cs index 6c6835e7b5..ef99ac232a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaModel.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaModel.cs @@ -28,6 +28,8 @@ using Microsoft.IdentityModel.Json.Linq; using Microsoft.IdentityModel.Json.Utilities; +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] @@ -122,4 +124,4 @@ private static void Combine(JsonSchemaModel model, JsonSchema schema) } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaModelBuilder.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaModelBuilder.cs index dfdc9feac9..7cddf8a57c 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaModelBuilder.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaModelBuilder.cs @@ -32,6 +32,8 @@ #endif +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaNode.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaNode.cs index 717553e0b1..f9012b914e 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaNode.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaNode.cs @@ -33,6 +33,8 @@ #endif +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaNodeCollection.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaNodeCollection.cs index 5b9ad8754b..f15a78e73e 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaNodeCollection.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaNodeCollection.cs @@ -26,6 +26,8 @@ using System; using System.Collections.ObjectModel; +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaResolver.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaResolver.cs index 6b8d22935b..01a5524132 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaResolver.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaResolver.cs @@ -32,6 +32,8 @@ #endif +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { /// @@ -76,4 +78,4 @@ public virtual JsonSchema GetSchema(string reference) return schema; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaType.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaType.cs index bb49312eeb..23b07bd958 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaType.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaType.cs @@ -25,6 +25,7 @@ using System; + namespace Microsoft.IdentityModel.Json.Schema { /// @@ -84,4 +85,4 @@ internal enum JsonSchemaType /// Any = String | Float | Integer | Boolean | Object | Array | Null } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaWriter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaWriter.cs index 30193874ce..d44174f5e8 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaWriter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/JsonSchemaWriter.cs @@ -35,6 +35,8 @@ #endif +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/UndefinedSchemaIdHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/UndefinedSchemaIdHandling.cs index c685eb50c6..d9ca4a57ff 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/UndefinedSchemaIdHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/UndefinedSchemaIdHandling.cs @@ -25,6 +25,8 @@ using System; +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { /// @@ -53,4 +55,4 @@ internal enum UndefinedSchemaIdHandling /// UseAssemblyQualifiedName = 2, } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/ValidationEventArgs.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/ValidationEventArgs.cs index da4e90345d..2e54596202 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/ValidationEventArgs.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/ValidationEventArgs.cs @@ -26,6 +26,8 @@ using System; using Microsoft.IdentityModel.Json.Utilities; +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { /// @@ -65,4 +67,4 @@ internal ValidationEventArgs(JsonSchemaException ex) /// The text description. public string Message => _ex.Message; } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/ValidationEventHandler.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/ValidationEventHandler.cs index 96fdf6f96f..4ff9c7ace0 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/ValidationEventHandler.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Schema/ValidationEventHandler.cs @@ -25,6 +25,8 @@ using System; +#nullable disable + namespace Microsoft.IdentityModel.Json.Schema { /// @@ -37,4 +39,4 @@ namespace Microsoft.IdentityModel.Json.Schema /// [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] internal delegate void ValidationEventHandler(object sender, ValidationEventArgs e); -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/CachedAttributeGetter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/CachedAttributeGetter.cs index 3430f80109..e6d28713dc 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/CachedAttributeGetter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/CachedAttributeGetter.cs @@ -29,13 +29,15 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable internal static class CachedAttributeGetter where T : Attribute { - private static readonly ThreadSafeStore TypeAttributeCache = new ThreadSafeStore(JsonTypeReflector.GetAttribute); + private static readonly ThreadSafeStore TypeAttributeCache = new ThreadSafeStore(JsonTypeReflector.GetAttribute); - public static T GetAttribute(object type) + public static T? GetAttribute(object type) { return TypeAttributeCache.Get(type); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/CamelCaseNamingStrategy.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/CamelCaseNamingStrategy.cs index 937b79475c..7e1c37f31c 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/CamelCaseNamingStrategy.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/CamelCaseNamingStrategy.cs @@ -84,4 +84,4 @@ protected override string ResolvePropertyName(string name) return StringUtils.ToCamelCase(name); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/CamelCasePropertyNamesContractResolver.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/CamelCasePropertyNamesContractResolver.cs index 147ad06556..4142165c4f 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/CamelCasePropertyNamesContractResolver.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/CamelCasePropertyNamesContractResolver.cs @@ -30,6 +30,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Resolves member mappings for a type, camel casing property names. /// @@ -37,7 +38,7 @@ internal class CamelCasePropertyNamesContractResolver : DefaultContractResolver { private static readonly object TypeContractCacheLock = new object(); private static readonly DefaultJsonNameTable NameTable = new DefaultJsonNameTable(); - private static Dictionary, JsonContract> _contractCache; + private static Dictionary, JsonContract>? _contractCache; /// /// Initializes a new instance of the class. @@ -65,8 +66,8 @@ public override JsonContract ResolveContract(Type type) // for backwards compadibility the CamelCasePropertyNamesContractResolver shares contracts between instances StructMultiKey key = new StructMultiKey(GetType(), type); - Dictionary, JsonContract> cache = _contractCache; - if (cache == null || !cache.TryGetValue(key, out JsonContract contract)) + Dictionary, JsonContract>? cache = _contractCache; + if (cache == null || !cache.TryGetValue(key, out JsonContract? contract)) { contract = CreateContract(type); @@ -91,4 +92,5 @@ internal override DefaultJsonNameTable GetNameTable() return NameTable; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultContractResolver.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultContractResolver.cs index 6043d096e9..7fefdb40b6 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultContractResolver.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultContractResolver.cs @@ -55,6 +55,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Used by to resolve a for a given . /// @@ -168,7 +169,7 @@ internal class DefaultContractResolver : IContractResolver /// Gets or sets the naming strategy used to resolve how property names and dictionary keys are serialized. /// /// The naming strategy used to resolve how property names and dictionary keys are serialized. - public NamingStrategy NamingStrategy { get; set; } + public NamingStrategy? NamingStrategy { get; set; } /// /// Initializes a new instance of the class. @@ -198,6 +199,25 @@ public virtual JsonContract ResolveContract(Type type) return _contractCache.Get(type); } + private static bool FilterMembers(MemberInfo member) + { + if (member is PropertyInfo property) + { + if (ReflectionUtils.IsIndexedProperty(property)) + { + return false; + } + + return !ReflectionUtils.IsByRefLikeType(property.PropertyType); + } + else if (member is FieldInfo field) + { + return !ReflectionUtils.IsByRefLikeType(field.FieldType); + } + + return true; + } + /// /// Gets the serializable members for the type. /// @@ -214,20 +234,23 @@ protected virtual List GetSerializableMembers(Type objectType) MemberSerialization memberSerialization = JsonTypeReflector.GetObjectMemberSerialization(objectType, ignoreSerializableAttribute); + // Exclude index properties + // Do not filter ByRef types here because accessing FieldType/PropertyType can trigger additonal assembly loads IEnumerable allMembers = ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static) - .Where(m => !ReflectionUtils.IsIndexedProperty(m)); + .Where(m => m is PropertyInfo p ? !ReflectionUtils.IsIndexedProperty(p) : true); List serializableMembers = new List(); if (memberSerialization != MemberSerialization.Fields) { #if HAVE_DATA_CONTRACTS - DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(objectType); + DataContractAttribute? dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(objectType); #endif #pragma warning disable 618 + // Exclude index properties and ByRef types List defaultMembers = ReflectionUtils.GetFieldsAndProperties(objectType, DefaultMembersSearchFlags) - .Where(m => !ReflectionUtils.IsIndexedProperty(m)).ToList(); + .Where(FilterMembers).ToList(); #pragma warning restore 618 foreach (MemberInfo member in allMembers) @@ -330,17 +353,18 @@ protected virtual JsonObjectContract CreateObjectContract(Type objectType) contract.MemberSerialization = JsonTypeReflector.GetObjectMemberSerialization(contract.NonNullableUnderlyingType, ignoreSerializableAttribute); contract.Properties.AddRange(CreateProperties(contract.NonNullableUnderlyingType, contract.MemberSerialization)); - Func extensionDataNameResolver = null; + Func? extensionDataNameResolver = null; - JsonObjectAttribute attribute = JsonTypeReflector.GetCachedAttribute(contract.NonNullableUnderlyingType); + JsonObjectAttribute? attribute = JsonTypeReflector.GetCachedAttribute(contract.NonNullableUnderlyingType); if (attribute != null) { contract.ItemRequired = attribute._itemRequired; contract.ItemNullValueHandling = attribute._itemNullValueHandling; + contract.MissingMemberHandling = attribute._missingMemberHandling; if (attribute.NamingStrategyType != null) { - NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(attribute); + NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(attribute)!; extensionDataNameResolver = s => namingStrategy.GetDictionaryKey(s); } } @@ -354,7 +378,7 @@ protected virtual JsonObjectContract CreateObjectContract(Type objectType) if (contract.IsInstantiable) { - ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); + ConstructorInfo? overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); // check if a JsonConstructorAttribute has been defined and use that if (overrideConstructor != null) @@ -375,7 +399,7 @@ protected virtual JsonObjectContract CreateObjectContract(Type objectType) } else if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic) { - ConstructorInfo constructor = GetParameterizedConstructor(contract.NonNullableUnderlyingType); + ConstructorInfo? constructor = GetParameterizedConstructor(contract.NonNullableUnderlyingType); if (constructor != null) { contract.ParameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(constructor); @@ -386,7 +410,7 @@ protected virtual JsonObjectContract CreateObjectContract(Type objectType) { // value types always have default constructor // check whether there is a constructor that matches with non-writable properties on value type - ConstructorInfo constructor = GetImmutableConstructor(contract.NonNullableUnderlyingType, contract.Properties); + ConstructorInfo? constructor = GetImmutableConstructor(contract.NonNullableUnderlyingType, contract.Properties); if (constructor != null) { contract.OverrideCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(constructor); @@ -395,14 +419,14 @@ protected virtual JsonObjectContract CreateObjectContract(Type objectType) } } - MemberInfo extensionDataMember = GetExtensionDataMemberForType(contract.NonNullableUnderlyingType); + MemberInfo? extensionDataMember = GetExtensionDataMemberForType(contract.NonNullableUnderlyingType); if (extensionDataMember != null) { SetExtensionDataDelegates(contract, extensionDataMember); } // serializing DirectoryInfo without ISerializable will stackoverflow - // https://github.com/JamesNK/Microsoft.IdentityModel.Json/issues/1541 + // https://github.com/JamesNK/Newtonsoft.Json/issues/1541 if (Array.IndexOf(BlacklistedTypeNames, objectType.FullName) != -1) { contract.OnSerializingCallbacks.Add(ThrowUnableToSerializeError); @@ -416,7 +440,7 @@ private static void ThrowUnableToSerializeError(object o, StreamingContext conte throw new JsonSerializationException("Unable to serialize instance of '{0}'.".FormatWith(CultureInfo.InvariantCulture, o.GetType())); } - private MemberInfo GetExtensionDataMemberForType(Type type) + private MemberInfo? GetExtensionDataMemberForType(Type type) { IEnumerable members = GetClassHierarchyForType(type).SelectMany(baseType => { @@ -427,7 +451,7 @@ private MemberInfo GetExtensionDataMemberForType(Type type) return m; }); - MemberInfo extensionDataMember = members.LastOrDefault(m => + MemberInfo? extensionDataMember = members.LastOrDefault(m => { MemberTypes memberType = m.MemberType(); if (memberType != MemberTypes.Property && memberType != MemberTypes.Field) @@ -443,12 +467,12 @@ private MemberInfo GetExtensionDataMemberForType(Type type) if (!ReflectionUtils.CanReadMemberValue(m, true)) { - throw new JsonException("Invalid extension data attribute on '{0}'. Member '{1}' must have a getter.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(m.DeclaringType), m.Name)); + throw new JsonException("Invalid extension data attribute on '{0}'. Member '{1}' must have a getter.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(m.DeclaringType!), m.Name)); } Type t = ReflectionUtils.GetMemberUnderlyingType(m); - if (ReflectionUtils.ImplementsGenericDefinition(t, typeof(IDictionary<,>), out Type dictionaryType)) + if (ReflectionUtils.ImplementsGenericDefinition(t, typeof(IDictionary<,>), out Type? dictionaryType)) { Type keyType = dictionaryType.GetGenericArguments()[0]; Type valueType = dictionaryType.GetGenericArguments()[1]; @@ -459,7 +483,7 @@ private MemberInfo GetExtensionDataMemberForType(Type type) } } - throw new JsonException("Invalid extension data attribute on '{0}'. Member '{1}' type must implement IDictionary.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(m.DeclaringType), m.Name)); + throw new JsonException("Invalid extension data attribute on '{0}'. Member '{1}' type must implement IDictionary.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(m.DeclaringType!), m.Name)); }); return extensionDataMember; @@ -467,7 +491,7 @@ private MemberInfo GetExtensionDataMemberForType(Type type) private static void SetExtensionDataDelegates(JsonObjectContract contract, MemberInfo member) { - JsonExtensionDataAttribute extensionDataAttribute = ReflectionUtils.GetAttribute(member); + JsonExtensionDataAttribute? extensionDataAttribute = ReflectionUtils.GetAttribute(member); if (extensionDataAttribute == null) { return; @@ -475,10 +499,10 @@ private static void SetExtensionDataDelegates(JsonObjectContract contract, Membe Type t = ReflectionUtils.GetMemberUnderlyingType(member); - ReflectionUtils.ImplementsGenericDefinition(t, typeof(IDictionary<,>), out Type dictionaryType); + ReflectionUtils.ImplementsGenericDefinition(t, typeof(IDictionary<,>), out Type? dictionaryType); - Type keyType = dictionaryType.GetGenericArguments()[0]; - Type valueType = dictionaryType.GetGenericArguments()[1]; + Type keyType = dictionaryType!.GetGenericArguments()[0]; + Type valueType = dictionaryType!.GetGenericArguments()[1]; Type createdType; @@ -492,27 +516,27 @@ private static void SetExtensionDataDelegates(JsonObjectContract contract, Membe createdType = t; } - Func getExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(member); + Func getExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(member); if (extensionDataAttribute.ReadData) { - Action setExtensionDataDictionary = (ReflectionUtils.CanSetMemberValue(member, true, false)) + Action? setExtensionDataDictionary = (ReflectionUtils.CanSetMemberValue(member, true, false)) ? JsonTypeReflector.ReflectionDelegateFactory.CreateSet(member) : null; Func createExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor(createdType); - MethodInfo setMethod = t.GetProperty("Item", BindingFlags.Public | BindingFlags.Instance, null, valueType, new[] { keyType }, null)?.GetSetMethod(); + MethodInfo? setMethod = t.GetProperty("Item", BindingFlags.Public | BindingFlags.Instance, null, valueType, new[] { keyType }, null)?.GetSetMethod(); if (setMethod == null) { // Item is explicitly implemented and non-public // get from dictionary interface - setMethod = dictionaryType.GetProperty("Item", BindingFlags.Public | BindingFlags.Instance, null, valueType, new[] { keyType }, null)?.GetSetMethod(); + setMethod = dictionaryType!.GetProperty("Item", BindingFlags.Public | BindingFlags.Instance, null, valueType, new[] { keyType }, null)?.GetSetMethod(); } - MethodCall setExtensionDataDictionaryValue = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(setMethod); + MethodCall setExtensionDataDictionaryValue = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(setMethod!); ExtensionDataSetter extensionDataSetter = (o, key, value) => { - object dictionary = getExtensionDataDictionary(o); + object? dictionary = getExtensionDataDictionary(o); if (dictionary == null) { if (setExtensionDataDictionary == null) @@ -538,7 +562,7 @@ private static void SetExtensionDataDelegates(JsonObjectContract contract, Membe ExtensionDataGetter extensionDataGetter = o => { - object dictionary = getExtensionDataDictionary(o); + object? dictionary = getExtensionDataDictionary(o); if (dictionary == null) { return null; @@ -569,7 +593,7 @@ public IEnumerator> GetEnumerator() { foreach (KeyValuePair item in _e) { - yield return new KeyValuePair(item.Key, item.Value); + yield return new KeyValuePair(item.Key!, item.Value!); } } @@ -579,7 +603,7 @@ IEnumerator IEnumerable.GetEnumerator() } } - private ConstructorInfo GetAttributeConstructor(Type objectType) + private ConstructorInfo? GetAttributeConstructor(Type objectType) { IEnumerator en = objectType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(c => c.IsDefined(typeof(JsonConstructorAttribute), true)).GetEnumerator(); @@ -603,7 +627,7 @@ private ConstructorInfo GetAttributeConstructor(Type objectType) return null; } - private ConstructorInfo GetImmutableConstructor(Type objectType, JsonPropertyCollection memberProperties) + private ConstructorInfo? GetImmutableConstructor(Type objectType, JsonPropertyCollection memberProperties) { IEnumerable constructors = objectType.GetConstructors(); IEnumerator en = constructors.GetEnumerator(); @@ -617,7 +641,7 @@ private ConstructorInfo GetImmutableConstructor(Type objectType, JsonPropertyCol { foreach (ParameterInfo parameterInfo in parameters) { - JsonProperty memberProperty = MatchProperty(memberProperties, parameterInfo.Name, parameterInfo.ParameterType); + JsonProperty? memberProperty = MatchProperty(memberProperties, parameterInfo.Name!, parameterInfo.ParameterType); if (memberProperty == null || memberProperty.Writable) { return null; @@ -632,7 +656,7 @@ private ConstructorInfo GetImmutableConstructor(Type objectType, JsonPropertyCol return null; } - private ConstructorInfo GetParameterizedConstructor(Type objectType) + private ConstructorInfo? GetParameterizedConstructor(Type objectType) { #if PORTABLE IEnumerable constructors = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance); @@ -665,11 +689,16 @@ protected virtual IList CreateConstructorParameters(ConstructorInf { ParameterInfo[] constructorParameters = constructor.GetParameters(); - JsonPropertyCollection parameterCollection = new JsonPropertyCollection(constructor.DeclaringType); + JsonPropertyCollection parameterCollection = new JsonPropertyCollection(constructor.DeclaringType!); foreach (ParameterInfo parameterInfo in constructorParameters) { - JsonProperty matchingMemberProperty = MatchProperty(memberProperties, parameterInfo.Name, parameterInfo.ParameterType); + if (parameterInfo.Name == null) + { + continue; + } + + JsonProperty? matchingMemberProperty = MatchProperty(memberProperties, parameterInfo.Name, parameterInfo.ParameterType); // ensure that property will have a name from matching property or from parameterinfo // parameterinfo could have no name if generated by a proxy (I'm looking at you Castle) @@ -687,7 +716,7 @@ protected virtual IList CreateConstructorParameters(ConstructorInf return parameterCollection; } - private JsonProperty MatchProperty(JsonPropertyCollection properties, string name, Type type) + private JsonProperty? MatchProperty(JsonPropertyCollection properties, string name, Type type) { // it is possible to generate a member with a null name using Reflection.Emit // protect against an ArgumentNullException from GetClosestMatchProperty by testing for null here @@ -696,7 +725,7 @@ private JsonProperty MatchProperty(JsonPropertyCollection properties, string nam return null; } - JsonProperty property = properties.GetClosestMatchProperty(name); + JsonProperty? property = properties.GetClosestMatchProperty(name); // must match type as well as name if (property == null || property.PropertyType != type) { @@ -712,13 +741,13 @@ private JsonProperty MatchProperty(JsonPropertyCollection properties, string nam /// The matching member property. /// The constructor parameter. /// A created for the given . - protected virtual JsonProperty CreatePropertyFromConstructorParameter(JsonProperty matchingMemberProperty, ParameterInfo parameterInfo) + protected virtual JsonProperty CreatePropertyFromConstructorParameter(JsonProperty? matchingMemberProperty, ParameterInfo parameterInfo) { JsonProperty property = new JsonProperty(); property.PropertyType = parameterInfo.ParameterType; property.AttributeProvider = new ReflectionAttributeProvider(parameterInfo); - SetPropertySettingsFromAttributes(property, parameterInfo, parameterInfo.Name, parameterInfo.Member.DeclaringType, MemberSerialization.OptOut, out _); + SetPropertySettingsFromAttributes(property, parameterInfo, parameterInfo.Name!, parameterInfo.Member.DeclaringType!, MemberSerialization.OptOut, out _); property.Readable = false; property.Writable = true; @@ -751,7 +780,7 @@ protected virtual JsonProperty CreatePropertyFromConstructorParameter(JsonProper /// /// Type of the object. /// The contract's default . - protected virtual JsonConverter ResolveContractConverter(Type objectType) + protected virtual JsonConverter? ResolveContractConverter(Type objectType) { return JsonTypeReflector.GetJsonConverter(objectType); } @@ -766,7 +795,7 @@ private Func GetDefaultCreator(Type createdType) #endif private void InitializeContract(JsonContract contract) { - JsonContainerAttribute containerAttribute = JsonTypeReflector.GetCachedAttribute(contract.NonNullableUnderlyingType); + JsonContainerAttribute? containerAttribute = JsonTypeReflector.GetCachedAttribute(contract.NonNullableUnderlyingType); if (containerAttribute != null) { contract.IsReference = containerAttribute._isReference; @@ -774,7 +803,7 @@ private void InitializeContract(JsonContract contract) #if HAVE_DATA_CONTRACTS else { - DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(contract.NonNullableUnderlyingType); + DataContractAttribute? dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(contract.NonNullableUnderlyingType); // doesn't have a null value if (dataContractAttribute != null && dataContractAttribute.IsReference) { @@ -804,11 +833,11 @@ private void ResolveCallbackMethods(JsonContract contract, Type t) { GetCallbackMethodsForType( t, - out List onSerializing, - out List onSerialized, - out List onDeserializing, - out List onDeserialized, - out List onError); + out List? onSerializing, + out List? onSerialized, + out List? onDeserializing, + out List? onDeserialized, + out List? onError); if (onSerializing != null) { @@ -836,7 +865,7 @@ private void ResolveCallbackMethods(JsonContract contract, Type t) } } - private void GetCallbackMethodsForType(Type type, out List onSerializing, out List onSerialized, out List onDeserializing, out List onDeserialized, out List onError) + private void GetCallbackMethodsForType(Type type, out List? onSerializing, out List? onSerialized, out List? onDeserializing, out List? onDeserialized, out List? onError) { onSerializing = null; onSerialized = null; @@ -847,11 +876,11 @@ private void GetCallbackMethodsForType(Type type, out List GetClassHierarchyForType(Type type) { List ret = new List(); - Type current = type; + Type? current = type; while (current != null && current != typeof(object)) { ret.Add(current); @@ -983,10 +1012,10 @@ protected virtual JsonDictionaryContract CreateDictionaryContract(Type objectTyp JsonDictionaryContract contract = new JsonDictionaryContract(objectType); InitializeContract(contract); - JsonContainerAttribute containerAttribute = JsonTypeReflector.GetAttribute(objectType); + JsonContainerAttribute? containerAttribute = JsonTypeReflector.GetAttribute(objectType); if (containerAttribute?.NamingStrategyType != null) { - NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute); + NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute)!; contract.DictionaryKeyResolver = s => namingStrategy.GetDictionaryKey(s); } else @@ -994,7 +1023,7 @@ protected virtual JsonDictionaryContract CreateDictionaryContract(Type objectTyp contract.DictionaryKeyResolver = ResolveDictionaryKey; } - ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); + ConstructorInfo? overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); if (overrideConstructor != null) { @@ -1032,7 +1061,7 @@ protected virtual JsonArrayContract CreateArrayContract(Type objectType) JsonArrayContract contract = new JsonArrayContract(objectType); InitializeContract(contract); - ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); + ConstructorInfo? overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); if (overrideConstructor != null) { @@ -1099,7 +1128,7 @@ protected virtual JsonISerializableContract CreateISerializableContract(Type obj if (contract.IsInstantiable) { - ConstructorInfo constructorInfo = contract.NonNullableUnderlyingType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new[] {typeof(SerializationInfo), typeof(StreamingContext)}, null); + ConstructorInfo? constructorInfo = contract.NonNullableUnderlyingType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new[] {typeof(SerializationInfo), typeof(StreamingContext)}, null); if (constructorInfo != null) { ObjectConstructor creator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(constructorInfo); @@ -1123,10 +1152,10 @@ protected virtual JsonDynamicContract CreateDynamicContract(Type objectType) JsonDynamicContract contract = new JsonDynamicContract(objectType); InitializeContract(contract); - JsonContainerAttribute containerAttribute = JsonTypeReflector.GetAttribute(objectType); + JsonContainerAttribute? containerAttribute = JsonTypeReflector.GetAttribute(objectType); if (containerAttribute?.NamingStrategyType != null) { - NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute); + NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute)!; contract.PropertyNameResolver = s => namingStrategy.GetDictionaryKey(s); } else @@ -1168,7 +1197,7 @@ protected virtual JsonContract CreateContract(Type objectType) } t = ReflectionUtils.EnsureNotNullableType(t); - JsonContainerAttribute containerAttribute = JsonTypeReflector.GetCachedAttribute(t); + JsonContainerAttribute? containerAttribute = JsonTypeReflector.GetCachedAttribute(t); if (containerAttribute is JsonObjectAttribute) { @@ -1197,7 +1226,7 @@ protected virtual JsonContract CreateContract(Type objectType) if (typeof(IEnumerable).IsAssignableFrom(t)) { - return CreateArrayContract(t); + return CreateArrayContract(objectType); } if (CanConvertToString(t)) @@ -1264,10 +1293,17 @@ internal static bool CanConvertToString(Type type) return true; } +#if HAVE_DATE_ONLY + if (type == typeof(DateOnly) || type == typeof(TimeOnly)) + { + return true; + } +#endif + return false; } - private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameters, Type attributeType, MethodInfo currentCallback, ref Type prevAttributeType) + private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameters, Type attributeType, MethodInfo? currentCallback, ref Type? prevAttributeType) { if (!method.IsDefined(attributeType, false)) { @@ -1276,36 +1312,36 @@ private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameter if (currentCallback != null) { - throw new JsonException("Invalid attribute. Both '{0}' and '{1}' in type '{2}' have '{3}'.".FormatWith(CultureInfo.InvariantCulture, method, currentCallback, GetClrTypeFullName(method.DeclaringType), attributeType)); + throw new JsonException("Invalid attribute. Both '{0}' and '{1}' in type '{2}' have '{3}'.".FormatWith(CultureInfo.InvariantCulture, method, currentCallback, GetClrTypeFullName(method.DeclaringType!), attributeType)); } if (prevAttributeType != null) { - throw new JsonException("Invalid Callback. Method '{3}' in type '{2}' has both '{0}' and '{1}'.".FormatWith(CultureInfo.InvariantCulture, prevAttributeType, attributeType, GetClrTypeFullName(method.DeclaringType), method)); + throw new JsonException("Invalid Callback. Method '{3}' in type '{2}' has both '{0}' and '{1}'.".FormatWith(CultureInfo.InvariantCulture, prevAttributeType, attributeType, GetClrTypeFullName(method.DeclaringType!), method)); } if (method.IsVirtual) { - throw new JsonException("Virtual Method '{0}' of type '{1}' cannot be marked with '{2}' attribute.".FormatWith(CultureInfo.InvariantCulture, method, GetClrTypeFullName(method.DeclaringType), attributeType)); + throw new JsonException("Virtual Method '{0}' of type '{1}' cannot be marked with '{2}' attribute.".FormatWith(CultureInfo.InvariantCulture, method, GetClrTypeFullName(method.DeclaringType!), attributeType)); } if (method.ReturnType != typeof(void)) { - throw new JsonException("Serialization Callback '{1}' in type '{0}' must return void.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method)); + throw new JsonException("Serialization Callback '{1}' in type '{0}' must return void.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType!), method)); } if (attributeType == typeof(OnErrorAttribute)) { if (parameters == null || parameters.Length != 2 || parameters[0].ParameterType != typeof(StreamingContext) || parameters[1].ParameterType != typeof(ErrorContext)) { - throw new JsonException("Serialization Error Callback '{1}' in type '{0}' must have two parameters of type '{2}' and '{3}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method, typeof(StreamingContext), typeof(ErrorContext))); + throw new JsonException("Serialization Error Callback '{1}' in type '{0}' must have two parameters of type '{2}' and '{3}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType!), method, typeof(StreamingContext), typeof(ErrorContext))); } } else { if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != typeof(StreamingContext)) { - throw new JsonException("Serialization Callback '{1}' in type '{0}' must have a single parameter of type '{2}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method, typeof(StreamingContext))); + throw new JsonException("Serialization Callback '{1}' in type '{0}' must have a single parameter of type '{2}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType!), method, typeof(StreamingContext))); } } @@ -1318,7 +1354,7 @@ internal static string GetClrTypeFullName(Type type) { if (type.IsGenericTypeDefinition() || !type.ContainsGenericParameters()) { - return type.FullName; + return type.FullName!; } return "{0}.{1}".FormatWith(CultureInfo.InvariantCulture, type.Namespace, type.Name); @@ -1351,7 +1387,7 @@ protected virtual IList CreateProperties(Type type, MemberSerializ // nametable is not thread-safe for multiple writers lock (nameTable) { - property.PropertyName = nameTable.Add(property.PropertyName); + property.PropertyName = nameTable.Add(property.PropertyName!); } properties.AddProperty(property); @@ -1377,7 +1413,7 @@ protected virtual IValueProvider CreateMemberValueProvider(MemberInfo member) // warning - this method use to cause errors with Intellitrace. Retest in VS Ultimate after changes IValueProvider valueProvider; -#if !(PORTABLE40 || PORTABLE || DOTNET || NETSTANDARD2_0) +#if !(PORTABLE40 || PORTABLE || DOTNET || NETSTANDARD2_0 || NET6_0_OR_GREATER) if (DynamicCodeGeneration) { valueProvider = new DynamicValueProvider(member); @@ -1409,7 +1445,7 @@ protected virtual JsonProperty CreateProperty(MemberInfo member, MemberSerializa property.ValueProvider = CreateMemberValueProvider(member); property.AttributeProvider = new ReflectionAttributeProvider(member); - SetPropertySettingsFromAttributes(property, member, member.Name, member.DeclaringType, memberSerialization, out bool allowNonPublicAccess); + SetPropertySettingsFromAttributes(property, member, member.Name, member.DeclaringType!, memberSerialization, out bool allowNonPublicAccess); if (memberSerialization != MemberSerialization.Fields) { @@ -1439,11 +1475,11 @@ protected virtual JsonProperty CreateProperty(MemberInfo member, MemberSerializa private void SetPropertySettingsFromAttributes(JsonProperty property, object attributeProvider, string name, Type declaringType, MemberSerialization memberSerialization, out bool allowNonPublicAccess) { #if HAVE_DATA_CONTRACTS - DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(declaringType); + DataContractAttribute? dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(declaringType); - MemberInfo memberInfo = attributeProvider as MemberInfo; + MemberInfo? memberInfo = attributeProvider as MemberInfo; - DataMemberAttribute dataMemberAttribute; + DataMemberAttribute? dataMemberAttribute; if (dataContractAttribute != null && memberInfo != null) { dataMemberAttribute = JsonTypeReflector.GetDataMemberAttribute((MemberInfo)memberInfo); @@ -1454,8 +1490,8 @@ private void SetPropertySettingsFromAttributes(JsonProperty property, object att } #endif - JsonPropertyAttribute propertyAttribute = JsonTypeReflector.GetAttribute(attributeProvider); - JsonRequiredAttribute requiredAttribute = JsonTypeReflector.GetAttribute(attributeProvider); + JsonPropertyAttribute? propertyAttribute = JsonTypeReflector.GetAttribute(attributeProvider); + JsonRequiredAttribute? requiredAttribute = JsonTypeReflector.GetAttribute(attributeProvider); string mappedName; bool hasSpecifiedName; @@ -1477,9 +1513,9 @@ private void SetPropertySettingsFromAttributes(JsonProperty property, object att hasSpecifiedName = false; } - JsonContainerAttribute containerAttribute = JsonTypeReflector.GetAttribute(declaringType); + JsonContainerAttribute? containerAttribute = JsonTypeReflector.GetAttribute(declaringType); - NamingStrategy namingStrategy; + NamingStrategy? namingStrategy; if (propertyAttribute?.NamingStrategyType != null) { namingStrategy = JsonTypeReflector.CreateNamingStrategyInstance(propertyAttribute.NamingStrategyType, propertyAttribute.NamingStrategyParameters); @@ -1501,7 +1537,7 @@ private void SetPropertySettingsFromAttributes(JsonProperty property, object att { property.PropertyName = ResolvePropertyName(mappedName); } - + property.UnderlyingName = name; bool hasMemberAttribute = false; @@ -1582,7 +1618,7 @@ private void SetPropertySettingsFromAttributes(JsonProperty property, object att // the class type might have a converter but the property converter takes precedence property.Converter = JsonTypeReflector.GetJsonConverter(attributeProvider); - DefaultValueAttribute defaultValueAttribute = JsonTypeReflector.GetAttribute(attributeProvider); + DefaultValueAttribute? defaultValueAttribute = JsonTypeReflector.GetAttribute(attributeProvider); if (defaultValueAttribute != null) { property.DefaultValue = defaultValueAttribute.Value; @@ -1605,24 +1641,24 @@ private void SetPropertySettingsFromAttributes(JsonProperty property, object att } } - private Predicate CreateShouldSerializeTest(MemberInfo member) + private Predicate? CreateShouldSerializeTest(MemberInfo member) { - MethodInfo shouldSerializeMethod = member.DeclaringType.GetMethod(JsonTypeReflector.ShouldSerializePrefix + member.Name, ReflectionUtils.EmptyTypes); + MethodInfo? shouldSerializeMethod = member.DeclaringType!.GetMethod(JsonTypeReflector.ShouldSerializePrefix + member.Name, ReflectionUtils.EmptyTypes); if (shouldSerializeMethod == null || shouldSerializeMethod.ReturnType != typeof(bool)) { return null; } - MethodCall shouldSerializeCall = + MethodCall shouldSerializeCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(shouldSerializeMethod); - return o => (bool)shouldSerializeCall(o); + return o => (bool)shouldSerializeCall(o)!; } private void SetIsSpecifiedActions(JsonProperty property, MemberInfo member, bool allowNonPublicAccess) { - MemberInfo specifiedMember = member.DeclaringType.GetProperty(member.Name + JsonTypeReflector.SpecifiedPostfix, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + MemberInfo? specifiedMember = member.DeclaringType!.GetProperty(member.Name + JsonTypeReflector.SpecifiedPostfix, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (specifiedMember == null) { specifiedMember = member.DeclaringType.GetField(member.Name + JsonTypeReflector.SpecifiedPostfix, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); @@ -1633,7 +1669,7 @@ private void SetIsSpecifiedActions(JsonProperty property, MemberInfo member, boo return; } - Func specifiedPropertyGet = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(specifiedMember); + Func specifiedPropertyGet = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(specifiedMember)!; property.GetIsSpecified = o => (bool)specifiedPropertyGet(o); @@ -1700,4 +1736,5 @@ public string GetResolvedPropertyName(string propertyName) return ResolvePropertyName(propertyName); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultNamingStrategy.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultNamingStrategy.cs index f5420206af..db416138da 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultNamingStrategy.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultNamingStrategy.cs @@ -15,4 +15,4 @@ protected override string ResolvePropertyName(string name) return name; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultReferenceResolver.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultReferenceResolver.cs index a856c72636..7a1e0ddc93 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultReferenceResolver.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultReferenceResolver.cs @@ -29,6 +29,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable internal class DefaultReferenceResolver : IReferenceResolver { private int _referenceCount; @@ -52,15 +53,15 @@ private BidirectionalDictionary GetMappings(object context) public object ResolveReference(object context, string reference) { - GetMappings(context).TryGetByFirst(reference, out object value); - return value; + GetMappings(context).TryGetByFirst(reference, out object? value); + return value!; } public string GetReference(object context, object value) { BidirectionalDictionary mappings = GetMappings(context); - if (!mappings.TryGetBySecond(value, out string reference)) + if (!mappings.TryGetBySecond(value, out string? reference)) { _referenceCount++; reference = _referenceCount.ToString(CultureInfo.InvariantCulture); @@ -80,4 +81,5 @@ public bool IsReferenced(object context, object value) return GetMappings(context).TryGetBySecond(value, out _); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultSerializationBinder.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultSerializationBinder.cs index 22c80eabc7..91c41b7b7f 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultSerializationBinder.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DefaultSerializationBinder.cs @@ -29,10 +29,10 @@ using System.Globalization; using Microsoft.IdentityModel.Json.Utilities; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// The default serialization binder used when resolving and loading classes from type names. /// @@ -44,32 +44,31 @@ internal class DefaultSerializationBinder : { internal static readonly DefaultSerializationBinder Instance = new DefaultSerializationBinder(); - private readonly ThreadSafeStore, Type> _typeCache; + private readonly ThreadSafeStore, Type> _typeCache; /// /// Initializes a new instance of the class. /// public DefaultSerializationBinder() { - _typeCache = new ThreadSafeStore, Type>(GetTypeFromTypeNameKey); + _typeCache = new ThreadSafeStore, Type>(GetTypeFromTypeNameKey); } - [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId="Assembly.LoadWithPartialName")] - private Type GetTypeFromTypeNameKey(StructMultiKey typeNameKey) + private Type GetTypeFromTypeNameKey(StructMultiKey typeNameKey) { - string assemblyName = typeNameKey.Value1; + string? assemblyName = typeNameKey.Value1; string typeName = typeNameKey.Value2; if (assemblyName != null) { - Assembly assembly = null; + Assembly? assembly; #if !(DOTNET || PORTABLE40 || PORTABLE) // look, I don't like using obsolete methods as much as you do but this is the only way // Assembly.Load won't check the GAC for a partial name -#pragma warning disable 618,612,2001 - // assembly = Assembly.LoadWithPartialName(assemblyName); -#pragma warning restore 618,612,2001 +#pragma warning disable 618,612 + assembly = Assembly.LoadWithPartialName(assemblyName); +#pragma warning restore 618,612 #elif DOTNET || PORTABLE assembly = Assembly.Load(new AssemblyName(assemblyName)); #else @@ -98,12 +97,12 @@ private Type GetTypeFromTypeNameKey(StructMultiKey typeNameKey) throw new JsonSerializationException("Could not load assembly '{0}'.".FormatWith(CultureInfo.InvariantCulture, assemblyName)); } - Type type = assembly.GetType(typeName); + Type? type = assembly.GetType(typeName); if (type == null) { // if generic type, try manually parsing the type arguments for the case of dynamically loaded assemblies // example generic typeName format: System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] - if (typeName.IndexOf('`') >= 0) + if (StringUtils.IndexOf(typeName, '`') >= 0) { try { @@ -125,18 +124,18 @@ private Type GetTypeFromTypeNameKey(StructMultiKey typeNameKey) } else { - return Type.GetType(typeName); + return Type.GetType(typeName)!; } } - private Type GetGenericTypeFromTypeName(string typeName, Assembly assembly) + private Type? GetGenericTypeFromTypeName(string typeName, Assembly assembly) { - Type type = null; - int openBracketIndex = typeName.IndexOf('['); + Type? type = null; + int openBracketIndex = StringUtils.IndexOf(typeName, '['); if (openBracketIndex >= 0) { string genericTypeDefName = typeName.Substring(0, openBracketIndex); - Type genericTypeDef = assembly.GetType(genericTypeDefName); + Type? genericTypeDef = assembly.GetType(genericTypeDefName); if (genericTypeDef != null) { List genericTypeArguments = new List(); @@ -161,7 +160,7 @@ private Type GetGenericTypeFromTypeName(string typeName, Assembly assembly) { string typeArgAssemblyQualifiedName = typeName.Substring(typeArgStartIndex, i - typeArgStartIndex); - StructMultiKey typeNameKey = ReflectionUtils.SplitFullyQualifiedTypeName(typeArgAssemblyQualifiedName); + StructMultiKey typeNameKey = ReflectionUtils.SplitFullyQualifiedTypeName(typeArgAssemblyQualifiedName); genericTypeArguments.Add(GetTypeByName(typeNameKey)); } break; @@ -175,7 +174,7 @@ private Type GetGenericTypeFromTypeName(string typeName, Assembly assembly) return type; } - private Type GetTypeByName(StructMultiKey typeNameKey) + private Type GetTypeByName(StructMultiKey typeNameKey) { return _typeCache.Get(typeNameKey); } @@ -188,9 +187,9 @@ private Type GetTypeByName(StructMultiKey typeNameKey) /// /// The type of the object the formatter creates a new instance of. /// - public override Type BindToType(string assemblyName, string typeName) + public override Type BindToType(string? assemblyName, string typeName) { - return GetTypeByName(new StructMultiKey(assemblyName, typeName)); + return GetTypeByName(new StructMultiKey(assemblyName, typeName)); } /// @@ -203,7 +202,7 @@ public override Type BindToType(string assemblyName, string typeName) #if HAVE_SERIALIZATION_BINDER_BIND_TO_NAME override #endif - void BindToName(Type serializedType, out string assemblyName, out string typeName) + void BindToName(Type serializedType, out string? assemblyName, out string? typeName) { #if !HAVE_FULL_REFLECTION assemblyName = serializedType.GetTypeInfo().Assembly.FullName; @@ -214,4 +213,5 @@ void BindToName(Type serializedType, out string assemblyName, out string typeNam #endif } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DiagnosticsTraceWriter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DiagnosticsTraceWriter.cs index 5a8627880e..6e1c0006d4 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DiagnosticsTraceWriter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DiagnosticsTraceWriter.cs @@ -5,6 +5,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Represents a trace writer that writes to the application's instances. /// @@ -43,7 +44,7 @@ private TraceEventType GetTraceEventType(TraceLevel level) /// The at which to write this trace. /// The trace message. /// The trace exception. This parameter is optional. - public void Trace(TraceLevel level, string message, Exception ex) + public void Trace(TraceLevel level, string message, Exception? ex) { if (level == TraceLevel.Off) { @@ -59,12 +60,12 @@ public void Trace(TraceLevel level, string message, Exception ex) { lock (listener) { - listener.TraceEvent(eventCache, "Microsoft.IdentityModel.Json", traceEventType, 0, message); + listener.TraceEvent(eventCache, "Newtonsoft.Json", traceEventType, 0, message); } } else { - listener.TraceEvent(eventCache, "Microsoft.IdentityModel.Json", traceEventType, 0, message); + listener.TraceEvent(eventCache, "Newtonsoft.Json", traceEventType, 0, message); } if (DiagnosticsTrace.AutoFlush) @@ -74,6 +75,7 @@ public void Trace(TraceLevel level, string message, Exception ex) } } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DynamicValueProvider.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DynamicValueProvider.cs index 498d4bfbe2..e60628248f 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DynamicValueProvider.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/DynamicValueProvider.cs @@ -36,14 +36,15 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Get and set values for a using dynamic methods. /// internal class DynamicValueProvider : IValueProvider { private readonly MemberInfo _memberInfo; - private Func _getter; - private Action _setter; + private Func? _getter; + private Action? _setter; /// /// Initializes a new instance of the class. @@ -60,7 +61,7 @@ public DynamicValueProvider(MemberInfo memberInfo) /// /// The target to set the value on. /// The value to set on the target. - public void SetValue(object target, object value) + public void SetValue(object target, object? value) { try { @@ -98,7 +99,7 @@ public void SetValue(object target, object value) /// /// The target to get the value from. /// The value. - public object GetValue(object target) + public object? GetValue(object target) { try { @@ -115,6 +116,7 @@ public object GetValue(object target) } } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ErrorContext.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ErrorContext.cs index ce6bab1b17..e2ae565444 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ErrorContext.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ErrorContext.cs @@ -27,12 +27,13 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Provides information surrounding an error. /// internal class ErrorContext { - internal ErrorContext(object originalObject, object member, string path, Exception error) + internal ErrorContext(object? originalObject, object? member, string path, Exception error) { OriginalObject = originalObject; Member = member; @@ -52,13 +53,13 @@ internal ErrorContext(object originalObject, object member, string path, Excepti /// Gets the original object that caused the error. /// /// The original object that caused the error. - public object OriginalObject { get; } + public object? OriginalObject { get; } /// /// Gets the member that caused the error. /// /// The member that caused the error. - public object Member { get; } + public object? Member { get; } /// /// Gets the path of the JSON location where the error occurred. @@ -72,4 +73,5 @@ internal ErrorContext(object originalObject, object member, string path, Excepti /// true if handled; otherwise, false. public bool Handled { get; set; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ErrorEventArgs.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ErrorEventArgs.cs index d4421f47fb..915c32d6f2 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ErrorEventArgs.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ErrorEventArgs.cs @@ -27,6 +27,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Provides data for the Error event. /// @@ -36,7 +37,7 @@ internal class ErrorEventArgs : EventArgs /// Gets the current object the error event is being raised against. /// /// The current object the error event is being raised against. - public object CurrentObject { get; } + public object? CurrentObject { get; } /// /// Gets the error context. @@ -49,10 +50,11 @@ internal class ErrorEventArgs : EventArgs /// /// The current object. /// The error context. - public ErrorEventArgs(object currentObject, ErrorContext errorContext) + public ErrorEventArgs(object? currentObject, ErrorContext errorContext) { CurrentObject = currentObject; ErrorContext = errorContext; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ExpressionValueProvider.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ExpressionValueProvider.cs index e3188b1abd..97315b4979 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ExpressionValueProvider.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ExpressionValueProvider.cs @@ -37,14 +37,15 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Get and set values for a using dynamic methods. /// internal class ExpressionValueProvider : IValueProvider { private readonly MemberInfo _memberInfo; - private Func _getter; - private Action _setter; + private Func? _getter; + private Action? _setter; /// /// Initializes a new instance of the class. @@ -61,7 +62,7 @@ public ExpressionValueProvider(MemberInfo memberInfo) /// /// The target to set the value on. /// The value to set on the target. - public void SetValue(object target, object value) + public void SetValue(object target, object? value) { try { @@ -99,7 +100,7 @@ public void SetValue(object target, object value) /// /// The target to get the value from. /// The value. - public object GetValue(object target) + public object? GetValue(object target) { try { @@ -116,6 +117,7 @@ public object GetValue(object target) } } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IAttributeProvider.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IAttributeProvider.cs index 255891d936..a28b6ad36d 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IAttributeProvider.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IAttributeProvider.cs @@ -48,4 +48,4 @@ internal interface IAttributeProvider /// A collection of s, or an empty collection. IList GetAttributes(Type attributeType, bool inherit); } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IContractResolver.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IContractResolver.cs index 88e725baff..15276c2536 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IContractResolver.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IContractResolver.cs @@ -43,4 +43,4 @@ internal interface IContractResolver /// The contract for a given type. JsonContract ResolveContract(Type type); } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IReferenceResolver.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IReferenceResolver.cs index ce435d3207..4a027e335a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IReferenceResolver.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IReferenceResolver.cs @@ -64,4 +64,4 @@ internal interface IReferenceResolver /// The object to reference. void AddReference(object context, string reference, object value); } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ISerializationBinder.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ISerializationBinder.cs index 066de56a34..99f77c1830 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ISerializationBinder.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ISerializationBinder.cs @@ -29,6 +29,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Allows users to control class loading and mandate what class to load. /// @@ -40,7 +41,7 @@ internal interface ISerializationBinder /// Specifies the name of the serialized object. /// Specifies the name of the serialized object /// The type of the object the formatter creates a new instance of. - Type BindToType(string assemblyName, string typeName); + Type BindToType(string? assemblyName, string typeName); /// /// When implemented, controls the binding of a serialized object to a type. @@ -48,6 +49,7 @@ internal interface ISerializationBinder /// The type of the object the formatter creates a new instance of. /// Specifies the name of the serialized object. /// Specifies the name of the serialized object. - void BindToName(Type serializedType, out string assemblyName, out string typeName); + void BindToName(Type serializedType, out string? assemblyName, out string? typeName); } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ITraceWriter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ITraceWriter.cs index f63c87f6bb..b0c94c9285 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ITraceWriter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ITraceWriter.cs @@ -4,6 +4,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Represents a trace writer. /// @@ -23,6 +24,7 @@ internal interface ITraceWriter /// The at which to write this trace. /// The trace message. /// The trace exception. This parameter is optional. - void Trace(TraceLevel level, string message, Exception ex); + void Trace(TraceLevel level, string message, Exception? ex); } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IValueProvider.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IValueProvider.cs index 5f285dfe9f..75a476da03 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IValueProvider.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/IValueProvider.cs @@ -25,6 +25,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Provides methods to get and set values. /// @@ -35,13 +36,14 @@ internal interface IValueProvider /// /// The target to set the value on. /// The value to set on the target. - void SetValue(object target, object value); + void SetValue(object target, object? value); /// /// Gets the value. /// /// The target to get the value from. /// The value. - object GetValue(object target); + object? GetValue(object target); } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonArrayContract.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonArrayContract.cs index c848b6f21b..15f70caf69 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonArrayContract.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonArrayContract.cs @@ -31,6 +31,7 @@ using System.Reflection; using Microsoft.IdentityModel.Json.Utilities; using System.Collections; +using System.Diagnostics; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else @@ -40,6 +41,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Contract details for a used by the . /// @@ -49,7 +51,7 @@ internal class JsonArrayContract : JsonContainerContract /// Gets the of the collection items. /// /// The of the collection items. - public Type CollectionItemType { get; } + public Type? CollectionItemType { get; } /// /// Gets a value indicating whether the collection type is a multidimensional array. @@ -57,26 +59,26 @@ internal class JsonArrayContract : JsonContainerContract /// true if the collection type is a multidimensional array; otherwise, false. public bool IsMultidimensionalArray { get; } - private readonly Type _genericCollectionDefinitionType; + private readonly Type? _genericCollectionDefinitionType; - private Type _genericWrapperType; - private ObjectConstructor _genericWrapperCreator; - private Func _genericTemporaryCollectionCreator; + private Type? _genericWrapperType; + private ObjectConstructor? _genericWrapperCreator; + private Func? _genericTemporaryCollectionCreator; internal bool IsArray { get; } internal bool ShouldCreateWrapper { get; } internal bool CanDeserialize { get; private set; } - private readonly ConstructorInfo _parameterizedConstructor; + private readonly ConstructorInfo? _parameterizedConstructor; - private ObjectConstructor _parameterizedCreator; - private ObjectConstructor _overrideCreator; + private ObjectConstructor? _parameterizedCreator; + private ObjectConstructor? _overrideCreator; - internal ObjectConstructor ParameterizedCreator + internal ObjectConstructor? ParameterizedCreator { get { - if (_parameterizedCreator == null) + if (_parameterizedCreator == null && _parameterizedConstructor != null) { _parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(_parameterizedConstructor); } @@ -89,7 +91,7 @@ internal ObjectConstructor ParameterizedCreator /// Gets or sets the function used to create the object. When set this function will override . /// /// The function used to create the object. - public ObjectConstructor OverrideCreator + public ObjectConstructor? OverrideCreator { get => _overrideCreator; set @@ -116,72 +118,75 @@ public JsonArrayContract(Type underlyingType) : base(underlyingType) { ContractType = JsonContractType.Array; - IsArray = CreatedType.IsArray; + + // netcoreapp3.0 uses EmptyPartition for empty enumerable. Treat as an empty array. + IsArray = CreatedType.IsArray || + (NonNullableUnderlyingType.IsGenericType() && NonNullableUnderlyingType.GetGenericTypeDefinition().FullName == "System.Linq.EmptyPartition`1"); bool canDeserialize; - Type tempCollectionType; + Type? tempCollectionType; if (IsArray) { - CollectionItemType = ReflectionUtils.GetCollectionItemType(UnderlyingType); + CollectionItemType = ReflectionUtils.GetCollectionItemType(UnderlyingType)!; IsReadOnlyOrFixedSize = true; _genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType); canDeserialize = true; - IsMultidimensionalArray = (IsArray && UnderlyingType.GetArrayRank() > 1); + IsMultidimensionalArray = (CreatedType.IsArray && UnderlyingType.GetArrayRank() > 1); } - else if (typeof(IList).IsAssignableFrom(underlyingType)) + else if (typeof(IList).IsAssignableFrom(NonNullableUnderlyingType)) { - if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(ICollection<>), out _genericCollectionDefinitionType)) + if (ReflectionUtils.ImplementsGenericDefinition(NonNullableUnderlyingType, typeof(ICollection<>), out _genericCollectionDefinitionType)) { CollectionItemType = _genericCollectionDefinitionType.GetGenericArguments()[0]; } else { - CollectionItemType = ReflectionUtils.GetCollectionItemType(underlyingType); + CollectionItemType = ReflectionUtils.GetCollectionItemType(NonNullableUnderlyingType); } - if (underlyingType == typeof(IList)) + if (NonNullableUnderlyingType == typeof(IList)) { CreatedType = typeof(List); } if (CollectionItemType != null) { - _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType); + _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(NonNullableUnderlyingType, CollectionItemType); } - IsReadOnlyOrFixedSize = ReflectionUtils.InheritsGenericDefinition(underlyingType, typeof(ReadOnlyCollection<>)); + IsReadOnlyOrFixedSize = ReflectionUtils.InheritsGenericDefinition(NonNullableUnderlyingType, typeof(ReadOnlyCollection<>)); canDeserialize = true; } - else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(ICollection<>), out _genericCollectionDefinitionType)) + else if (ReflectionUtils.ImplementsGenericDefinition(NonNullableUnderlyingType, typeof(ICollection<>), out _genericCollectionDefinitionType)) { CollectionItemType = _genericCollectionDefinitionType.GetGenericArguments()[0]; - if (ReflectionUtils.IsGenericDefinition(underlyingType, typeof(ICollection<>)) - || ReflectionUtils.IsGenericDefinition(underlyingType, typeof(IList<>))) + if (ReflectionUtils.IsGenericDefinition(NonNullableUnderlyingType, typeof(ICollection<>)) + || ReflectionUtils.IsGenericDefinition(NonNullableUnderlyingType, typeof(IList<>))) { CreatedType = typeof(List<>).MakeGenericType(CollectionItemType); } #if HAVE_ISET - if (ReflectionUtils.IsGenericDefinition(underlyingType, typeof(ISet<>))) + if (ReflectionUtils.IsGenericDefinition(NonNullableUnderlyingType, typeof(ISet<>))) { CreatedType = typeof(HashSet<>).MakeGenericType(CollectionItemType); } #endif - _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType); + _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(NonNullableUnderlyingType, CollectionItemType); canDeserialize = true; ShouldCreateWrapper = true; } #if HAVE_READ_ONLY_COLLECTIONS - else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IReadOnlyCollection<>), out tempCollectionType)) + else if (ReflectionUtils.ImplementsGenericDefinition(NonNullableUnderlyingType, typeof(IReadOnlyCollection<>), out tempCollectionType)) { CollectionItemType = tempCollectionType.GetGenericArguments()[0]; - if (ReflectionUtils.IsGenericDefinition(underlyingType, typeof(IReadOnlyCollection<>)) - || ReflectionUtils.IsGenericDefinition(underlyingType, typeof(IReadOnlyList<>))) + if (ReflectionUtils.IsGenericDefinition(NonNullableUnderlyingType, typeof(IReadOnlyCollection<>)) + || ReflectionUtils.IsGenericDefinition(NonNullableUnderlyingType, typeof(IReadOnlyList<>))) { CreatedType = typeof(ReadOnlyCollection<>).MakeGenericType(CollectionItemType); } @@ -190,14 +195,14 @@ public JsonArrayContract(Type underlyingType) _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(CreatedType, CollectionItemType); #if HAVE_FSHARP_TYPES - StoreFSharpListCreatorIfNecessary(underlyingType); + StoreFSharpListCreatorIfNecessary(NonNullableUnderlyingType); #endif IsReadOnlyOrFixedSize = true; canDeserialize = HasParameterizedCreatorInternal; } #endif - else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IEnumerable<>), out tempCollectionType)) + else if (ReflectionUtils.ImplementsGenericDefinition(NonNullableUnderlyingType, typeof(IEnumerable<>), out tempCollectionType)) { CollectionItemType = tempCollectionType.GetGenericArguments()[0]; @@ -206,13 +211,13 @@ public JsonArrayContract(Type underlyingType) CreatedType = typeof(List<>).MakeGenericType(CollectionItemType); } - _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType); + _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(NonNullableUnderlyingType, CollectionItemType); #if HAVE_FSHARP_TYPES - StoreFSharpListCreatorIfNecessary(underlyingType); + StoreFSharpListCreatorIfNecessary(NonNullableUnderlyingType); #endif - if (underlyingType.IsGenericType() && underlyingType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + if (NonNullableUnderlyingType.IsGenericType() && NonNullableUnderlyingType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { _genericCollectionDefinitionType = tempCollectionType; @@ -251,11 +256,12 @@ public JsonArrayContract(Type underlyingType) } #endif - if (ImmutableCollectionsUtils.TryBuildImmutableForArrayContract( - underlyingType, + if (CollectionItemType != null && + ImmutableCollectionsUtils.TryBuildImmutableForArrayContract( + NonNullableUnderlyingType, CollectionItemType, - out Type immutableCreatedType, - out ObjectConstructor immutableParameterizedCreator)) + out Type? immutableCreatedType, + out ObjectConstructor? immutableParameterizedCreator)) { CreatedType = immutableCreatedType; _parameterizedCreator = immutableParameterizedCreator; @@ -268,6 +274,9 @@ internal IWrappedCollection CreateWrapper(object list) { if (_genericWrapperCreator == null) { + MiscellaneousUtils.Assert(_genericCollectionDefinitionType != null); + MiscellaneousUtils.Assert(CollectionItemType != null); + _genericWrapperType = typeof(CollectionWrapper<>).MakeGenericType(CollectionItemType); Type constructorArgument; @@ -282,7 +291,7 @@ internal IWrappedCollection CreateWrapper(object list) constructorArgument = _genericCollectionDefinitionType; } - ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { constructorArgument }); + ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { constructorArgument })!; _genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(genericWrapperConstructor); } @@ -311,9 +320,10 @@ private void StoreFSharpListCreatorIfNecessary(Type underlyingType) if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpListTypeName) { FSharpUtils.EnsureInitialized(underlyingType.Assembly()); - _parameterizedCreator = FSharpUtils.CreateSeq(CollectionItemType); + _parameterizedCreator = FSharpUtils.Instance.CreateSeq(CollectionItemType!); } } #endif } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonContainerContract.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonContainerContract.cs index f057f10a48..fcdb40c79b 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonContainerContract.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonContainerContract.cs @@ -37,16 +37,17 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Contract details for a used by the . /// internal class JsonContainerContract : JsonContract { - private JsonContract _itemContract; - private JsonContract _finalItemContract; + private JsonContract? _itemContract; + private JsonContract? _finalItemContract; // will be null for containers that don't have an item type (e.g. IList) or for complex objects - internal JsonContract ItemContract + internal JsonContract? ItemContract { get => _itemContract; set @@ -64,13 +65,13 @@ internal JsonContract ItemContract } // the final (i.e. can't be inherited from like a sealed class or valuetype) item contract - internal JsonContract FinalItemContract => _finalItemContract; + internal JsonContract? FinalItemContract => _finalItemContract; /// /// Gets or sets the default collection items . /// /// The converter. - public JsonConverter ItemConverter { get; set; } + public JsonConverter? ItemConverter { get; set; } /// /// Gets or sets a value indicating whether the collection items preserve object references. @@ -97,7 +98,7 @@ internal JsonContract ItemContract internal JsonContainerContract(Type underlyingType) : base(underlyingType) { - JsonContainerAttribute jsonContainerAttribute = JsonTypeReflector.GetCachedAttribute(underlyingType); + JsonContainerAttribute? jsonContainerAttribute = JsonTypeReflector.GetCachedAttribute(underlyingType); if (jsonContainerAttribute != null) { @@ -114,4 +115,5 @@ internal JsonContainerContract(Type underlyingType) } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonContract.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonContract.cs index 44be7c841e..f6c5e2cde3 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonContract.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonContract.cs @@ -33,6 +33,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable internal enum JsonContractType { None = 0, @@ -67,13 +68,13 @@ internal enum JsonContractType /// The object to set extension data on. /// The extension data key. /// The extension data value. - internal delegate void ExtensionDataSetter(object o, string key, object value); + internal delegate void ExtensionDataSetter(object o, string key, object? value); /// /// Gets extension data for an object during serialization. /// /// The object to set extension data on. - internal delegate IEnumerable> ExtensionDataGetter(object o); + internal delegate IEnumerable>? ExtensionDataGetter(object o); /// /// Contract details for a used by the . @@ -90,11 +91,11 @@ internal abstract class JsonContract internal bool IsSealed; internal bool IsInstantiable; - private List _onDeserializedCallbacks; - private IList _onDeserializingCallbacks; - private IList _onSerializedCallbacks; - private IList _onSerializingCallbacks; - private IList _onErrorCallbacks; + private List? _onDeserializedCallbacks; + private List? _onDeserializingCallbacks; + private List? _onSerializedCallbacks; + private List? _onSerializingCallbacks; + private List? _onErrorCallbacks; private Type _createdType; /// @@ -112,6 +113,7 @@ public Type CreatedType get => _createdType; set { + ValidationUtils.ArgumentNotNull(value, nameof(value)); _createdType = value; IsSealed = _createdType.IsSealed(); @@ -129,11 +131,14 @@ public Type CreatedType /// Gets or sets the default for this contract. /// /// The converter. - public JsonConverter Converter { get; set; } + public JsonConverter? Converter { get; set; } - // internally specified JsonConverter's to override default behavour - // checked for after passed in converters and attribute specified converters - internal JsonConverter InternalConverter { get; set; } + /// + /// Gets the internally resolved for the contract's type. + /// This converter is used as a fallback converter when no other converter is resolved. + /// Setting will always override this converter. + /// + public JsonConverter? InternalConverter { get; internal set; } /// /// Gets or sets all methods called immediately after deserialization of the object. @@ -224,7 +229,7 @@ public IList OnErrorCallbacks /// Gets or sets the default creator method used to create the object. /// /// The default creator method used to create the object. - public Func DefaultCreator { get; set; } + public Func? DefaultCreator { get; set; } /// /// Gets or sets a value indicating whether the default creator is non-public. @@ -243,10 +248,10 @@ internal JsonContract(Type underlyingType) underlyingType = ReflectionUtils.EnsureNotByRefType(underlyingType); IsNullable = ReflectionUtils.IsNullable(underlyingType); + + NonNullableUnderlyingType = (IsNullable && ReflectionUtils.IsNullableType(underlyingType)) ? Nullable.GetUnderlyingType(underlyingType)! : underlyingType; - NonNullableUnderlyingType = (IsNullable && ReflectionUtils.IsNullableType(underlyingType)) ? Nullable.GetUnderlyingType(underlyingType) : underlyingType; - - CreatedType = NonNullableUnderlyingType; + _createdType = CreatedType = NonNullableUnderlyingType; IsConvertable = ConvertUtils.IsConvertible(NonNullableUnderlyingType); IsEnum = NonNullableUnderlyingType.IsEnum(); @@ -319,4 +324,5 @@ internal static SerializationErrorCallback CreateSerializationErrorCallback(Meth return (o, context, econtext) => callbackMethodInfo.Invoke(o, new object[] { context, econtext }); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonDictionaryContract.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonDictionaryContract.cs index dec3cb8a66..fbb6827a70 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonDictionaryContract.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonDictionaryContract.cs @@ -36,6 +36,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Contract details for a used by the . /// @@ -45,41 +46,41 @@ internal class JsonDictionaryContract : JsonContainerContract /// Gets or sets the dictionary key resolver. /// /// The dictionary key resolver. - public Func DictionaryKeyResolver { get; set; } + public Func? DictionaryKeyResolver { get; set; } /// /// Gets the of the dictionary keys. /// /// The of the dictionary keys. - public Type DictionaryKeyType { get; } + public Type? DictionaryKeyType { get; } /// /// Gets the of the dictionary values. /// /// The of the dictionary values. - public Type DictionaryValueType { get; } + public Type? DictionaryValueType { get; } - internal JsonContract KeyContract { get; set; } + internal JsonContract? KeyContract { get; set; } - private readonly Type _genericCollectionDefinitionType; + private readonly Type? _genericCollectionDefinitionType; - private Type _genericWrapperType; - private ObjectConstructor _genericWrapperCreator; + private Type? _genericWrapperType; + private ObjectConstructor? _genericWrapperCreator; - private Func _genericTemporaryDictionaryCreator; + private Func? _genericTemporaryDictionaryCreator; internal bool ShouldCreateWrapper { get; } - private readonly ConstructorInfo _parameterizedConstructor; + private readonly ConstructorInfo? _parameterizedConstructor; - private ObjectConstructor _overrideCreator; - private ObjectConstructor _parameterizedCreator; + private ObjectConstructor? _overrideCreator; + private ObjectConstructor? _parameterizedCreator; - internal ObjectConstructor ParameterizedCreator + internal ObjectConstructor? ParameterizedCreator { get { - if (_parameterizedCreator == null) + if (_parameterizedCreator == null && _parameterizedConstructor != null) { _parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(_parameterizedConstructor); } @@ -92,7 +93,7 @@ internal ObjectConstructor ParameterizedCreator /// Gets or sets the function used to create the object. When set this function will override . /// /// The function used to create the object. - public ObjectConstructor OverrideCreator + public ObjectConstructor? OverrideCreator { get => _overrideCreator; set => _overrideCreator = value; @@ -115,24 +116,24 @@ public JsonDictionaryContract(Type underlyingType) { ContractType = JsonContractType.Dictionary; - Type keyType; - Type valueType; + Type? keyType; + Type? valueType; - if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IDictionary<,>), out _genericCollectionDefinitionType)) + if (ReflectionUtils.ImplementsGenericDefinition(NonNullableUnderlyingType, typeof(IDictionary<,>), out _genericCollectionDefinitionType)) { keyType = _genericCollectionDefinitionType.GetGenericArguments()[0]; valueType = _genericCollectionDefinitionType.GetGenericArguments()[1]; - if (ReflectionUtils.IsGenericDefinition(UnderlyingType, typeof(IDictionary<,>))) + if (ReflectionUtils.IsGenericDefinition(NonNullableUnderlyingType, typeof(IDictionary<,>))) { CreatedType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType); } - else if (underlyingType.IsGenericType()) + else if (NonNullableUnderlyingType.IsGenericType()) { // ConcurrentDictionary<,> + IDictionary setter + null value = error // wrap to use generic setter - // https://github.com/JamesNK/Microsoft.IdentityModel.Json/issues/1582 - Type typeDefinition = underlyingType.GetGenericTypeDefinition(); + // https://github.com/JamesNK/Newtonsoft.Json/issues/1582 + Type typeDefinition = NonNullableUnderlyingType.GetGenericTypeDefinition(); if (typeDefinition.FullName == JsonTypeReflector.ConcurrentDictionaryTypeName) { ShouldCreateWrapper = true; @@ -140,17 +141,17 @@ public JsonDictionaryContract(Type underlyingType) } #if HAVE_READ_ONLY_COLLECTIONS - IsReadOnlyOrFixedSize = ReflectionUtils.InheritsGenericDefinition(underlyingType, typeof(ReadOnlyDictionary<,>)); + IsReadOnlyOrFixedSize = ReflectionUtils.InheritsGenericDefinition(NonNullableUnderlyingType, typeof(ReadOnlyDictionary<,>)); #endif } #if HAVE_READ_ONLY_COLLECTIONS - else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IReadOnlyDictionary<,>), out _genericCollectionDefinitionType)) + else if (ReflectionUtils.ImplementsGenericDefinition(NonNullableUnderlyingType, typeof(IReadOnlyDictionary<,>), out _genericCollectionDefinitionType)) { keyType = _genericCollectionDefinitionType.GetGenericArguments()[0]; valueType = _genericCollectionDefinitionType.GetGenericArguments()[1]; - if (ReflectionUtils.IsGenericDefinition(UnderlyingType, typeof(IReadOnlyDictionary<,>))) + if (ReflectionUtils.IsGenericDefinition(NonNullableUnderlyingType, typeof(IReadOnlyDictionary<,>))) { CreatedType = typeof(ReadOnlyDictionary<,>).MakeGenericType(keyType, valueType); } @@ -160,9 +161,9 @@ public JsonDictionaryContract(Type underlyingType) #endif else { - ReflectionUtils.GetDictionaryKeyValueTypes(UnderlyingType, out keyType, out valueType); + ReflectionUtils.GetDictionaryKeyValueTypes(NonNullableUnderlyingType, out keyType, out valueType); - if (UnderlyingType == typeof(IDictionary)) + if (NonNullableUnderlyingType == typeof(IDictionary)) { CreatedType = typeof(Dictionary); } @@ -176,10 +177,10 @@ public JsonDictionaryContract(Type underlyingType) typeof(IDictionary<,>).MakeGenericType(keyType, valueType)); #if HAVE_FSHARP_TYPES - if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpMapTypeName) + if (!HasParameterizedCreatorInternal && NonNullableUnderlyingType.Name == FSharpUtils.FSharpMapTypeName) { - FSharpUtils.EnsureInitialized(underlyingType.Assembly()); - _parameterizedCreator = FSharpUtils.CreateMap(keyType, valueType); + FSharpUtils.EnsureInitialized(NonNullableUnderlyingType.Assembly()); + _parameterizedCreator = FSharpUtils.Instance.CreateMap(keyType, valueType); } #endif } @@ -204,12 +205,14 @@ public JsonDictionaryContract(Type underlyingType) } #endif - if (ImmutableCollectionsUtils.TryBuildImmutableForDictionaryContract( - underlyingType, - DictionaryKeyType, - DictionaryValueType, - out Type immutableCreatedType, - out ObjectConstructor immutableParameterizedCreator)) + if (DictionaryKeyType != null && + DictionaryValueType != null && + ImmutableCollectionsUtils.TryBuildImmutableForDictionaryContract( + NonNullableUnderlyingType, + DictionaryKeyType, + DictionaryValueType, + out Type? immutableCreatedType, + out ObjectConstructor? immutableParameterizedCreator)) { CreatedType = immutableCreatedType; _parameterizedCreator = immutableParameterizedCreator; @@ -221,9 +224,9 @@ internal IWrappedDictionary CreateWrapper(object dictionary) { if (_genericWrapperCreator == null) { - _genericWrapperType = typeof(DictionaryWrapper<,>).MakeGenericType(DictionaryKeyType, DictionaryValueType); + _genericWrapperType = typeof(DictionaryWrapper<,>).MakeGenericType(DictionaryKeyType!, DictionaryValueType!); - ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType }); + ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType! })!; _genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(genericWrapperConstructor); } @@ -242,4 +245,5 @@ internal IDictionary CreateTemporaryDictionary() return (IDictionary)_genericTemporaryDictionaryCreator(); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonDynamicContract.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonDynamicContract.cs index 55b7b0133d..c438d0384d 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonDynamicContract.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonDynamicContract.cs @@ -31,6 +31,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Contract details for a used by the . /// @@ -46,13 +47,13 @@ internal class JsonDynamicContract : JsonContainerContract /// Gets or sets the property name resolver. /// /// The property name resolver. - public Func PropertyNameResolver { get; set; } + public Func? PropertyNameResolver { get; set; } private readonly ThreadSafeStore>> _callSiteGetters = new ThreadSafeStore>>(CreateCallSiteGetter); - private readonly ThreadSafeStore>> _callSiteSetters = - new ThreadSafeStore>>(CreateCallSiteSetter); + private readonly ThreadSafeStore>> _callSiteSetters = + new ThreadSafeStore>>(CreateCallSiteSetter); private static CallSite> CreateCallSiteGetter(string name) { @@ -61,11 +62,11 @@ private static CallSite> CreateCallSiteGetter(str return CallSite>.Create(new NoThrowGetBinderMember(getMemberBinder)); } - private static CallSite> CreateCallSiteSetter(string name) + private static CallSite> CreateCallSiteSetter(string name) { SetMemberBinder binder = (SetMemberBinder)DynamicUtils.BinderWrapper.SetMember(name, typeof(DynamicUtils)); - return CallSite>.Create(new NoThrowSetBinderMember(binder)); + return CallSite>.Create(new NoThrowSetBinderMember(binder)); } /// @@ -80,7 +81,7 @@ public JsonDynamicContract(Type underlyingType) Properties = new JsonPropertyCollection(UnderlyingType); } - internal bool TryGetMember(IDynamicMetaObjectProvider dynamicProvider, string name, out object value) + internal bool TryGetMember(IDynamicMetaObjectProvider dynamicProvider, string name, out object? value) { ValidationUtils.ArgumentNotNull(dynamicProvider, nameof(dynamicProvider)); @@ -100,17 +101,18 @@ internal bool TryGetMember(IDynamicMetaObjectProvider dynamicProvider, string na } } - internal bool TrySetMember(IDynamicMetaObjectProvider dynamicProvider, string name, object value) + internal bool TrySetMember(IDynamicMetaObjectProvider dynamicProvider, string name, object? value) { ValidationUtils.ArgumentNotNull(dynamicProvider, nameof(dynamicProvider)); - CallSite> callSite = _callSiteSetters.Get(name); + CallSite> callSite = _callSiteSetters.Get(name); object result = callSite.Target(callSite, dynamicProvider, value); return !ReferenceEquals(result, NoThrowExpressionVisitor.ErrorResult); } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonFormatterConverter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonFormatterConverter.cs index b8b879fd70..4e6858a865 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonFormatterConverter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonFormatterConverter.cs @@ -32,13 +32,14 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable internal class JsonFormatterConverter : IFormatterConverter { private readonly JsonSerializerInternalReader _reader; private readonly JsonISerializableContract _contract; - private readonly JsonProperty _member; + private readonly JsonProperty? _member; - public JsonFormatterConverter(JsonSerializerInternalReader reader, JsonISerializableContract contract, JsonProperty member) + public JsonFormatterConverter(JsonSerializerInternalReader reader, JsonISerializableContract contract, JsonProperty? member) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); ValidationUtils.ArgumentNotNull(contract, nameof(contract)); @@ -53,7 +54,7 @@ private T GetTokenValue(object value) ValidationUtils.ArgumentNotNull(value, nameof(value)); JValue v = (JValue)value; - return (T)System.Convert.ChangeType(v.Value, typeof(T), CultureInfo.InvariantCulture); + return (T)System.Convert.ChangeType(v.Value, typeof(T), CultureInfo.InvariantCulture)!; } public object Convert(object value, Type type) @@ -65,19 +66,16 @@ public object Convert(object value, Type type) throw new ArgumentException("Value is not a JToken.", nameof(value)); } - return _reader.CreateISerializableItem(token, type, _contract, _member); + return _reader.CreateISerializableItem(token, type, _contract, _member)!; } public object Convert(object value, TypeCode typeCode) { ValidationUtils.ArgumentNotNull(value, nameof(value)); - if (value is JValue v) - { - value = v.Value; - } + object? resolvedValue = (value is JValue v) ? v.Value : value; - return System.Convert.ChangeType(value, typeCode, CultureInfo.InvariantCulture); + return System.Convert.ChangeType(resolvedValue, typeCode, CultureInfo.InvariantCulture)!; } public bool ToBoolean(object value) @@ -155,6 +153,7 @@ public ulong ToUInt64(object value) return GetTokenValue(value); } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonISerializableContract.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonISerializableContract.cs index e086f06036..29870f42b1 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonISerializableContract.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonISerializableContract.cs @@ -29,6 +29,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Contract details for a used by the . /// @@ -38,7 +39,7 @@ internal class JsonISerializableContract : JsonContainerContract /// Gets or sets the object constructor. /// /// The object constructor. - public ObjectConstructor ISerializableCreator { get; set; } + public ObjectConstructor? ISerializableCreator { get; set; } /// /// Initializes a new instance of the class. @@ -50,6 +51,7 @@ public JsonISerializableContract(Type underlyingType) ContractType = JsonContractType.Serializable; } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonLinqContract.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonLinqContract.cs index 46484f91cb..b69d856acb 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonLinqContract.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonLinqContract.cs @@ -42,4 +42,4 @@ public JsonLinqContract(Type underlyingType) ContractType = JsonContractType.Linq; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonObjectContract.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonObjectContract.cs index e8a0b593e1..082f09307f 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonObjectContract.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonObjectContract.cs @@ -33,6 +33,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Contract details for a used by the . /// @@ -44,6 +45,12 @@ internal class JsonObjectContract : JsonContainerContract /// The member object serialization. public MemberSerialization MemberSerialization { get; set; } + /// + /// Gets or sets the missing member handling used when deserializing this object. + /// + /// The missing member handling. + public MissingMemberHandling? MissingMemberHandling { get; set; } + /// /// Gets or sets a value that indicates whether the object's properties are required. /// @@ -85,13 +92,13 @@ public JsonPropertyCollection CreatorParameters /// This function is called with a collection of arguments which are defined by the collection. /// /// The function used to create the object. - public ObjectConstructor OverrideCreator + public ObjectConstructor? OverrideCreator { get => _overrideCreator; set => _overrideCreator = value; } - internal ObjectConstructor ParameterizedCreator + internal ObjectConstructor? ParameterizedCreator { get => _parameterizedCreator; set => _parameterizedCreator = value; @@ -100,17 +107,17 @@ internal ObjectConstructor ParameterizedCreator /// /// Gets or sets the extension data setter. /// - public ExtensionDataSetter ExtensionDataSetter { get; set; } + public ExtensionDataSetter? ExtensionDataSetter { get; set; } /// /// Gets or sets the extension data getter. /// - public ExtensionDataGetter ExtensionDataGetter { get; set; } + public ExtensionDataGetter? ExtensionDataGetter { get; set; } /// /// Gets or sets the extension data value type. /// - public Type ExtensionDataValueType + public Type? ExtensionDataValueType { get => _extensionDataValueType; set @@ -124,14 +131,14 @@ public Type ExtensionDataValueType /// Gets or sets the extension data name resolver. /// /// The extension data name resolver. - public Func ExtensionDataNameResolver { get; set; } + public Func? ExtensionDataNameResolver { get; set; } internal bool ExtensionDataIsJToken; private bool? _hasRequiredOrDefaultValueProperties; - private ObjectConstructor _overrideCreator; - private ObjectConstructor _parameterizedCreator; - private JsonPropertyCollection _creatorParameters; - private Type _extensionDataValueType; + private ObjectConstructor? _overrideCreator; + private ObjectConstructor? _parameterizedCreator; + private JsonPropertyCollection? _creatorParameters; + private Type? _extensionDataValueType; internal bool HasRequiredOrDefaultValueProperties { @@ -190,4 +197,5 @@ internal object GetUninitializedObject() } #endif } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonPrimitiveContract.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonPrimitiveContract.cs index 1a15e7935d..df0219dbf9 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonPrimitiveContract.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonPrimitiveContract.cs @@ -72,4 +72,4 @@ public JsonPrimitiveContract(Type underlyingType) [typeof(long)] = ReadType.ReadAsInt64 }; } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonProperty.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonProperty.cs index eb1c9b59d3..05a690c64b 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonProperty.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonProperty.cs @@ -24,6 +24,7 @@ #endregion using System; +using System.Diagnostics; using System.Reflection; using Microsoft.IdentityModel.Json.Utilities; @@ -33,6 +34,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Maps a JSON property to a .NET member or constructor parameter. /// @@ -41,20 +43,20 @@ internal class JsonProperty internal Required? _required; internal bool _hasExplicitDefaultValue; - private object _defaultValue; + private object? _defaultValue; private bool _hasGeneratedDefaultValue; - private string _propertyName; + private string? _propertyName; internal bool _skipPropertyNameEscape; - private Type _propertyType; + private Type? _propertyType; // use to cache contract during deserialization - internal JsonContract PropertyContract { get; set; } + internal JsonContract? PropertyContract { get; set; } /// /// Gets or sets the name of the property. /// /// The name of the property. - public string PropertyName + public string? PropertyName { get => _propertyName; set @@ -68,7 +70,7 @@ public string PropertyName /// Gets or sets the type that declared this property. /// /// The type that declared this property. - public Type DeclaringType { get; set; } + public Type? DeclaringType { get; set; } /// /// Gets or sets the order of serialization of a member. @@ -80,25 +82,25 @@ public string PropertyName /// Gets or sets the name of the underlying member or parameter. /// /// The name of the underlying member or parameter. - public string UnderlyingName { get; set; } + public string? UnderlyingName { get; set; } /// /// Gets the that will get and set the during serialization. /// /// The that will get and set the during serialization. - public IValueProvider ValueProvider { get; set; } + public IValueProvider? ValueProvider { get; set; } /// /// Gets or sets the for this property. /// /// The for this property. - public IAttributeProvider AttributeProvider { get; set; } + public IAttributeProvider? AttributeProvider { get; set; } /// /// Gets or sets the type of the property. /// /// The type of the property. - public Type PropertyType + public Type? PropertyType { get => _propertyType; set @@ -116,14 +118,14 @@ public Type PropertyType /// If set this converter takes precedence over the contract converter for the property type. /// /// The converter. - public JsonConverter Converter { get; set; } + public JsonConverter? Converter { get; set; } /// /// Gets or sets the member converter. /// /// The member converter. [Obsolete("MemberConverter is obsolete. Use Converter instead.")] - public JsonConverter MemberConverter + public JsonConverter? MemberConverter { get => Converter; set => Converter = value; @@ -157,7 +159,7 @@ public JsonConverter MemberConverter /// Gets the default value. /// /// The default value. - public object DefaultValue + public object? DefaultValue { get { @@ -175,7 +177,7 @@ public object DefaultValue } } - internal object GetResolvedDefaultValue() + internal object? GetResolvedDefaultValue() { if (_propertyType == null) { @@ -184,7 +186,7 @@ internal object GetResolvedDefaultValue() if (!_hasExplicitDefaultValue && !_hasGeneratedDefaultValue) { - _defaultValue = ReflectionUtils.GetDefaultValue(PropertyType); + _defaultValue = ReflectionUtils.GetDefaultValue(_propertyType); _hasGeneratedDefaultValue = true; } @@ -201,6 +203,11 @@ public Required Required set => _required = value; } + /// + /// Gets a value indicating whether has a value specified. + /// + public bool IsRequiredSpecified => _required != null; + /// /// Gets or sets a value indicating whether this property preserves object references. /// @@ -243,25 +250,25 @@ public Required Required /// Gets or sets a predicate used to determine whether the property should be serialized. /// /// A predicate used to determine whether the property should be serialized. - public Predicate ShouldSerialize { get; set; } + public Predicate? ShouldSerialize { get; set; } /// /// Gets or sets a predicate used to determine whether the property should be deserialized. /// /// A predicate used to determine whether the property should be deserialized. - public Predicate ShouldDeserialize { get; set; } + public Predicate? ShouldDeserialize { get; set; } /// /// Gets or sets a predicate used to determine whether the property should be serialized. /// /// A predicate used to determine whether the property should be serialized. - public Predicate GetIsSpecified { get; set; } + public Predicate? GetIsSpecified { get; set; } /// /// Gets or sets an action used to set whether the property has been deserialized. /// /// An action used to set whether the property has been deserialized. - public Action SetIsSpecified { get; set; } + public Action? SetIsSpecified { get; set; } /// /// Returns a that represents this instance. @@ -271,14 +278,14 @@ public Required Required /// public override string ToString() { - return PropertyName; + return PropertyName ?? string.Empty; } /// /// Gets or sets the converter used when serializing the property's collection items. /// /// The collection's items converter. - public JsonConverter ItemConverter { get; set; } + public JsonConverter? ItemConverter { get; set; } /// /// Gets or sets whether this property's collection items are serialized as a reference. @@ -300,14 +307,18 @@ public override string ToString() internal void WritePropertyName(JsonWriter writer) { + string? propertyName = PropertyName; + MiscellaneousUtils.Assert(propertyName != null); + if (_skipPropertyNameEscape) { - writer.WritePropertyName(PropertyName, false); + writer.WritePropertyName(propertyName, false); } else { - writer.WritePropertyName(PropertyName); + writer.WritePropertyName(propertyName); } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonPropertyCollection.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonPropertyCollection.cs index 3ae224054e..23853c9de4 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonPropertyCollection.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonPropertyCollection.cs @@ -29,9 +29,13 @@ using System.Collections.ObjectModel; using Microsoft.IdentityModel.Json.Utilities; using System.Globalization; +using System.Runtime.CompilerServices; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// A collection of objects. /// @@ -61,7 +65,7 @@ public JsonPropertyCollection(Type type) /// The key for the specified element. protected override string GetKeyForItem(JsonProperty item) { - return item.PropertyName; + return item.PropertyName!; } /// @@ -70,6 +74,8 @@ protected override string GetKeyForItem(JsonProperty item) /// The property to add to the collection. public void AddProperty(JsonProperty property) { + MiscellaneousUtils.Assert(property.PropertyName != null); + if (Contains(property.PropertyName)) { // don't overwrite existing property with ignored property @@ -104,7 +110,7 @@ public void AddProperty(JsonProperty property) // current property is hidden by the existing so don't add it return; } - + if (_type.ImplementInterface(existingProperty.DeclaringType) && _type.ImplementInterface(property.DeclaringType)) { // current property was already defined on another interface @@ -129,9 +135,9 @@ public void AddProperty(JsonProperty property) /// /// Name of the property. /// A matching property if found. - public JsonProperty GetClosestMatchProperty(string propertyName) + public JsonProperty? GetClosestMatchProperty(string propertyName) { - JsonProperty property = GetProperty(propertyName, StringComparison.Ordinal); + JsonProperty? property = GetProperty(propertyName, StringComparison.Ordinal); if (property == null) { property = GetProperty(propertyName, StringComparison.OrdinalIgnoreCase); @@ -140,9 +146,7 @@ public JsonProperty GetClosestMatchProperty(string propertyName) return property; } -#pragma warning disable CS0108 // Member hides inherited member; missing new keyword - private bool TryGetValue(string key, out JsonProperty item) -#pragma warning restore CS0108 // Member hides inherited member; missing new keyword + private bool TryGetProperty(string key, [NotNullWhen(true)]out JsonProperty? item) { if (Dictionary == null) { @@ -159,12 +163,12 @@ private bool TryGetValue(string key, out JsonProperty item) /// The name of the property to get. /// Type property name string comparison. /// A matching property if found. - public JsonProperty GetProperty(string propertyName, StringComparison comparisonType) + public JsonProperty? GetProperty(string propertyName, StringComparison comparisonType) { // KeyedCollection has an ordinal comparer if (comparisonType == StringComparison.Ordinal) { - if (TryGetValue(propertyName, out JsonProperty property)) + if (TryGetProperty(propertyName, out JsonProperty? property)) { return property; } @@ -184,4 +188,5 @@ public JsonProperty GetProperty(string propertyName, StringComparison comparison return null; } } +#nullable disable } diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerInternalBase.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerInternalBase.cs index e216a23f7c..6529804f4c 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerInternalBase.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerInternalBase.cs @@ -31,11 +31,12 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable internal abstract class JsonSerializerInternalBase { private class ReferenceEqualsEqualityComparer : IEqualityComparer { - bool IEqualityComparer.Equals(object x, object y) + bool IEqualityComparer.Equals(object? x, object? y) { return ReferenceEquals(x, y); } @@ -47,12 +48,12 @@ int IEqualityComparer.GetHashCode(object obj) } } - private ErrorContext _currentErrorContext; - private BidirectionalDictionary _mappings; + private ErrorContext? _currentErrorContext; + private BidirectionalDictionary? _mappings; internal readonly JsonSerializer Serializer; - internal readonly ITraceWriter TraceWriter; - protected JsonSerializerProxy InternalSerializer; + internal readonly ITraceWriter? TraceWriter; + protected JsonSerializerProxy? InternalSerializer; protected JsonSerializerInternalBase(JsonSerializer serializer) { @@ -81,7 +82,7 @@ internal BidirectionalDictionary DefaultReferenceMappings } } - protected NullValueHandling ResolvedNullValueHandling(JsonObjectContract containerContract, JsonProperty property) + protected NullValueHandling ResolvedNullValueHandling(JsonObjectContract? containerContract, JsonProperty property) { NullValueHandling resolvedNullValueHandling = property.NullValueHandling @@ -91,7 +92,7 @@ protected NullValueHandling ResolvedNullValueHandling(JsonObjectContract contain return resolvedNullValueHandling; } - private ErrorContext GetErrorContext(object currentObject, object member, string path, Exception error) + private ErrorContext GetErrorContext(object? currentObject, object? member, string path, Exception error) { if (_currentErrorContext == null) { @@ -116,7 +117,7 @@ protected void ClearErrorContext() _currentErrorContext = null; } - protected bool IsErrorHandled(object currentObject, JsonContract contract, object keyValue, IJsonLineInfo lineInfo, string path, Exception ex) + protected bool IsErrorHandled(object? currentObject, JsonContract? contract, object? keyValue, IJsonLineInfo? lineInfo, string path, Exception ex) { ErrorContext errorContext = GetErrorContext(currentObject, keyValue, path, ex); @@ -156,4 +157,5 @@ protected bool IsErrorHandled(object currentObject, JsonContract contract, objec return errorContext.Handled; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerInternalReader.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerInternalReader.cs index fdd27afe63..3b48c63fe6 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerInternalReader.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerInternalReader.cs @@ -40,15 +40,17 @@ using System.Runtime.Serialization; using Microsoft.IdentityModel.Json.Linq; using Microsoft.IdentityModel.Json.Utilities; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else using System.Linq; - #endif namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable internal class JsonSerializerInternalReader : JsonSerializerInternalBase { internal enum PropertyPresence @@ -93,10 +95,10 @@ public void Populate(JsonReader reader, object target) { reader.ReadAndAssert(); - string id = null; + string? id = null; if (Serializer.MetadataPropertyHandling != MetadataPropertyHandling.Ignore && reader.TokenType == JsonToken.PropertyName - && string.Equals(reader.Value.ToString(), JsonTypeReflector.IdPropertyName, StringComparison.Ordinal)) + && string.Equals(reader.Value!.ToString(), JsonTypeReflector.IdPropertyName, StringComparison.Ordinal)) { reader.ReadAndAssert(); id = reader.Value?.ToString(); @@ -123,28 +125,33 @@ public void Populate(JsonReader reader, object target) } } - private JsonContract GetContractSafe(Type type) + private JsonContract? GetContractSafe(Type? type) { if (type == null) { return null; } + return GetContract(type); + } + + private JsonContract GetContract(Type type) + { return Serializer._contractResolver.ResolveContract(type); } - public object Deserialize(JsonReader reader, Type objectType, bool checkAdditionalContent) + public object? Deserialize(JsonReader reader, Type? objectType, bool checkAdditionalContent) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } - JsonContract contract = GetContractSafe(objectType); + JsonContract? contract = GetContractSafe(objectType); try { - JsonConverter converter = GetConverter(contract, null, null, null); + JsonConverter? converter = GetConverter(contract, null, null, null); if (reader.TokenType == JsonToken.None && !reader.ReadForType(contract, converter != null)) { @@ -156,11 +163,11 @@ public object Deserialize(JsonReader reader, Type objectType, bool checkAddition return null; } - object deserializedValue; + object? deserializedValue; if (converter != null && converter.CanRead) { - deserializedValue = DeserializeConvertable(converter, reader, objectType, null); + deserializedValue = DeserializeConvertable(converter, reader, objectType!, null); } else { @@ -208,7 +215,7 @@ private JsonSerializerProxy GetInternalSerializer() return InternalSerializer; } - private JToken CreateJToken(JsonReader reader, JsonContract contract) + private JToken? CreateJToken(JsonReader reader, JsonContract? contract) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); @@ -225,13 +232,22 @@ private JToken CreateJToken(JsonReader reader, JsonContract contract) } } - JToken token; + JToken? token; using (JTokenWriter writer = new JTokenWriter()) { writer.WriteToken(reader); token = writer.Token; } + if (contract != null && token != null) + { + if (!contract.UnderlyingType.IsAssignableFrom(token.GetType())) + { + throw JsonSerializationException.Create(reader, "Deserialized JSON type '{0}' is not compatible with expected type '{1}'." + .FormatWith(CultureInfo.InvariantCulture, token.GetType().FullName, contract.UnderlyingType.FullName)); + } + } + return token; } @@ -248,7 +264,7 @@ private JToken CreateJObject(JsonReader reader) { if (reader.TokenType == JsonToken.PropertyName) { - string propertyName = (string)reader.Value; + string propertyName = (string)reader.Value!; if (!reader.ReadAndMoveToContent()) { break; @@ -269,7 +285,7 @@ private JToken CreateJObject(JsonReader reader) else { writer.WriteEndObject(); - return writer.Token; + return writer.Token!; } } while (reader.Read()); @@ -277,7 +293,7 @@ private JToken CreateJObject(JsonReader reader) } } - private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue) + private object? CreateValueInternal(JsonReader reader, Type? objectType, JsonContract? contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerMember, object? existingValue) { if (contract != null && contract.ContractType == JsonContractType.Linq) { @@ -301,7 +317,7 @@ private object CreateValueInternal(JsonReader reader, Type objectType, JsonContr case JsonToken.Bytes: return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType); case JsonToken.String: - string s = (string)reader.Value; + string s = (string)reader.Value!; // string that needs to be returned as a byte array should be base 64 decoded if (objectType == typeof(byte[])) @@ -317,7 +333,7 @@ private object CreateValueInternal(JsonReader reader, Type objectType, JsonContr return EnsureType(reader, s, CultureInfo.InvariantCulture, contract, objectType); case JsonToken.StartConstructor: - string constructorName = reader.Value.ToString(); + string constructorName = reader.Value!.ToString()!; return EnsureType(reader, constructorName, CultureInfo.InvariantCulture, contract, objectType); case JsonToken.Null: @@ -331,7 +347,7 @@ private object CreateValueInternal(JsonReader reader, Type objectType, JsonContr return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType); case JsonToken.Raw: - return new JRaw((string)reader.Value); + return new JRaw((string?)reader.Value); case JsonToken.Comment: // ignore break; @@ -343,9 +359,9 @@ private object CreateValueInternal(JsonReader reader, Type objectType, JsonContr throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object."); } - private static bool CoerceEmptyStringToNull(Type objectType, JsonContract contract, string s) + private static bool CoerceEmptyStringToNull(Type? objectType, JsonContract? contract, string s) { - return string.IsNullOrEmpty(s) && objectType != null && objectType != typeof(string) && objectType != typeof(object) && contract != null && contract.IsNullable; + return StringUtils.IsNullOrEmpty(s) && objectType != null && objectType != typeof(string) && objectType != typeof(object) && contract != null && contract.IsNullable; } internal string GetExpectedDescription(JsonContract contract) @@ -372,9 +388,9 @@ internal string GetExpectedDescription(JsonContract contract) } } - private JsonConverter GetConverter(JsonContract contract, JsonConverter memberConverter, JsonContainerContract containerContract, JsonProperty containerProperty) + private JsonConverter? GetConverter(JsonContract? contract, JsonConverter? memberConverter, JsonContainerContract? containerContract, JsonProperty? containerProperty) { - JsonConverter converter = null; + JsonConverter? converter = null; if (memberConverter != null) { // member attribute converter @@ -390,13 +406,12 @@ private JsonConverter GetConverter(JsonContract contract, JsonConverter memberCo } else if (contract != null) { - JsonConverter matchingConverter; if (contract.Converter != null) { // class attribute converter converter = contract.Converter; } - else if ((matchingConverter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null) + else if (Serializer.GetMatchingConverter(contract.UnderlyingType) is JsonConverter matchingConverter) { // passed in converters converter = matchingConverter; @@ -410,10 +425,10 @@ private JsonConverter GetConverter(JsonContract contract, JsonConverter memberCo return converter; } - private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue) + private object? CreateObject(JsonReader reader, Type? objectType, JsonContract? contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerMember, object? existingValue) { - string id; - Type resolvedObjectType = objectType; + string? id; + Type? resolvedObjectType = objectType; if (Serializer.MetadataPropertyHandling == MetadataPropertyHandling.Ignore) { @@ -440,7 +455,7 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con reader = tokenReader; } - if (ReadMetadataPropertiesToken(tokenReader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out object newValue, out id)) + if (ReadMetadataPropertiesToken(tokenReader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out object? newValue, out id)) { return newValue; } @@ -448,7 +463,7 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con else { reader.ReadAndAssert(); - if (ReadMetadataProperties(reader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out object newValue, out id)) + if (ReadMetadataProperties(reader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out object? newValue, out id)) { return newValue; } @@ -459,6 +474,9 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con return CreateJObject(reader); } + MiscellaneousUtils.Assert(resolvedObjectType != null); + MiscellaneousUtils.Assert(contract != null); + switch (contract.ContractType) { case JsonContractType.Object: @@ -490,7 +508,7 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con // if the content is inside $value then read past it if (Serializer.MetadataPropertyHandling != MetadataPropertyHandling.Ignore && reader.TokenType == JsonToken.PropertyName - && string.Equals(reader.Value.ToString(), JsonTypeReflector.ValuePropertyName, StringComparison.Ordinal)) + && string.Equals(reader.Value!.ToString(), JsonTypeReflector.ValuePropertyName, StringComparison.Ordinal)) { reader.ReadAndAssert(); @@ -501,7 +519,7 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con throw JsonSerializationException.Create(reader, "Unexpected token when deserializing primitive value: " + reader.TokenType); } - object value = CreateValueInternal(reader, resolvedObjectType, primitiveContract, member, null, null, existingValue); + object? value = CreateValueInternal(reader, resolvedObjectType, primitiveContract, member, null, null, existingValue); reader.ReadAndAssert(); return value; @@ -544,7 +562,7 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con if (createdFromNonDefaultCreator) { - ObjectConstructor creator = dictionaryContract.OverrideCreator ?? dictionaryContract.ParameterizedCreator; + ObjectConstructor creator = (dictionaryContract.OverrideCreator ?? dictionaryContract.ParameterizedCreator)!; return creator(dictionary); } @@ -553,8 +571,8 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con return wrappedDictionary.UnderlyingDictionary; } - targetDictionary = dictionary; - } + targetDictionary = dictionary; + } else { targetDictionary = PopulateDictionary(dictionaryContract.ShouldCreateWrapper || !(existingValue is IDictionary) ? dictionaryContract.CreateWrapper(existingValue) : (IDictionary)existingValue, reader, dictionaryContract, member, id); @@ -581,38 +599,29 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con throw JsonSerializationException.Create(reader, message); } - private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id) + private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type? objectType, ref JsonContract? contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerMember, object? existingValue, out object? newValue, out string? id) { id = null; newValue = null; if (reader.TokenType == JsonToken.StartObject) { - JObject current = (JObject)reader.CurrentToken; + JObject current = (JObject)reader.CurrentToken!; - JToken refToken = current[JsonTypeReflector.RefPropertyName]; - if (refToken != null) + JProperty? refProperty = current.Property(JsonTypeReflector.RefPropertyName, StringComparison.Ordinal); + if (refProperty != null) { + JToken refToken = refProperty.Value; if (refToken.Type != JTokenType.String && refToken.Type != JTokenType.Null) { throw JsonSerializationException.Create(refToken, refToken.Path, "JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName), null); } - JToken property = refToken.Parent; - JToken additionalContent = null; - if (property.Next != null) - { - additionalContent = property.Next; - } - else if (property.Previous != null) - { - additionalContent = property.Previous; - } - - string reference = (string)refToken; + string? reference = (string?)refProperty; if (reference != null) { + JToken? additionalContent = refProperty.Next ?? refProperty.Previous; if (additionalContent != null) { throw JsonSerializationException.Create(additionalContent, additionalContent.Path, "Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName), null); @@ -629,15 +638,15 @@ private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type objectTyp return true; } } - JToken typeToken = current[JsonTypeReflector.TypePropertyName]; + JToken? typeToken = current[JsonTypeReflector.TypePropertyName]; if (typeToken != null) { - string qualifiedTypeName = (string)typeToken; + string? qualifiedTypeName = (string?)typeToken; JsonReader typeTokenReader = typeToken.CreateReader(); typeTokenReader.ReadAndAssert(); - ResolveTypeName(typeTokenReader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName); + ResolveTypeName(typeTokenReader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName!); - JToken valueToken = current[JsonTypeReflector.ValuePropertyName]; + JToken? valueToken = current[JsonTypeReflector.ValuePropertyName]; if (valueToken != null) { while (true) @@ -645,7 +654,7 @@ private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type objectTyp reader.ReadAndAssert(); if (reader.TokenType == JsonToken.PropertyName) { - if ((string)reader.Value == JsonTypeReflector.ValuePropertyName) + if ((string)reader.Value! == JsonTypeReflector.ValuePropertyName) { return false; } @@ -656,12 +665,12 @@ private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type objectTyp } } } - JToken idToken = current[JsonTypeReflector.IdPropertyName]; + JToken? idToken = current[JsonTypeReflector.IdPropertyName]; if (idToken != null) { - id = (string)idToken; + id = (string?)idToken; } - JToken valuesToken = current[JsonTypeReflector.ArrayValuesPropertyName]; + JToken? valuesToken = current[JsonTypeReflector.ArrayValuesPropertyName]; if (valuesToken != null) { JsonReader listReader = valuesToken.CreateReader(); @@ -677,14 +686,14 @@ private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type objectTyp return false; } - private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id) + private bool ReadMetadataProperties(JsonReader reader, ref Type? objectType, ref JsonContract? contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerMember, object? existingValue, out object? newValue, out string? id) { id = null; newValue = null; if (reader.TokenType == JsonToken.PropertyName) { - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; if (propertyName.Length > 0 && propertyName[0] == '$') { @@ -694,7 +703,7 @@ private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref do { - propertyName = reader.Value.ToString(); + propertyName = reader.Value!.ToString()!; if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal)) { @@ -704,7 +713,7 @@ private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref throw JsonSerializationException.Create(reader, "JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName)); } - string reference = reader.Value?.ToString(); + string? reference = reader.Value?.ToString(); reader.ReadAndAssert(); @@ -719,7 +728,7 @@ private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) { - TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved object reference '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, reference, newValue.GetType())), null); + TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved object reference '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, reference, newValue!.GetType())), null); } return true; @@ -732,7 +741,7 @@ private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal)) { reader.ReadAndAssert(); - string qualifiedTypeName = reader.Value.ToString(); + string qualifiedTypeName = reader.Value!.ToString()!; ResolveTypeName(reader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName); @@ -752,7 +761,7 @@ private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal)) { reader.ReadAndAssert(); - object list = CreateList(reader, objectType, contract, member, existingValue, id); + object? list = CreateList(reader, objectType, contract, member, existingValue, id); reader.ReadAndAssert(); newValue = list; return true; @@ -767,7 +776,7 @@ private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref return false; } - private void ResolveTypeName(JsonReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, string qualifiedTypeName) + private void ResolveTypeName(JsonReader reader, ref Type? objectType, ref JsonContract? contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerMember, string qualifiedTypeName) { TypeNameHandling resolvedTypeNameHandling = member?.TypeNameHandling @@ -777,7 +786,7 @@ private void ResolveTypeName(JsonReader reader, ref Type objectType, ref JsonCon if (resolvedTypeNameHandling != TypeNameHandling.None) { - StructMultiKey typeNameKey = ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName); + StructMultiKey typeNameKey = ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName); Type specifiedType; try @@ -809,7 +818,7 @@ private void ResolveTypeName(JsonReader reader, ref Type objectType, ref JsonCon } objectType = specifiedType; - contract = GetContractSafe(specifiedType); + contract = GetContract(specifiedType); } } @@ -832,15 +841,18 @@ private JsonArrayContract EnsureArrayContract(JsonReader reader, Type objectType return arrayContract; } - private object CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string id) + private object? CreateList(JsonReader reader, Type? objectType, JsonContract? contract, JsonProperty? member, object? existingValue, string? id) { - object value; + object? value; if (HasNoDefinedType(contract)) { return CreateJToken(reader, contract); } + MiscellaneousUtils.Assert(objectType != null); + MiscellaneousUtils.Assert(contract != null); + JsonArrayContract arrayContract = EnsureArrayContract(reader, objectType, contract); if (existingValue == null) @@ -883,17 +895,17 @@ private object CreateList(JsonReader reader, Type objectType, JsonContract contr { if (arrayContract.IsMultidimensionalArray) { - list = CollectionUtils.ToMultidimensionalArray(list, arrayContract.CollectionItemType, contract.CreatedType.GetArrayRank()); + list = CollectionUtils.ToMultidimensionalArray(list, arrayContract.CollectionItemType!, contract.CreatedType.GetArrayRank()); } else if (arrayContract.IsArray) { - Array a = Array.CreateInstance(arrayContract.CollectionItemType, list.Count); + Array a = Array.CreateInstance(arrayContract.CollectionItemType!, list.Count); list.CopyTo(a, 0); list = a; } else { - ObjectConstructor creator = arrayContract.OverrideCreator ?? arrayContract.ParameterizedCreator; + ObjectConstructor creator = (arrayContract.OverrideCreator ?? arrayContract.ParameterizedCreator)!; return creator(list); } @@ -918,7 +930,7 @@ private object CreateList(JsonReader reader, Type objectType, JsonContract contr return value; } - private bool HasNoDefinedType(JsonContract contract) + private bool HasNoDefinedType(JsonContract? contract) { return (contract == null || contract.UnderlyingType == typeof(object) || contract.ContractType == JsonContractType.Linq #if HAVE_DYNAMIC @@ -927,14 +939,15 @@ private bool HasNoDefinedType(JsonContract contract) ); } - private object EnsureType(JsonReader reader, object value, CultureInfo culture, JsonContract contract, Type targetType) + private object? EnsureType(JsonReader reader, object? value, CultureInfo culture, JsonContract? contract, Type? targetType) { if (targetType == null) { return value; } - Type valueType = ReflectionUtils.GetObjectType(value); + MiscellaneousUtils.Assert(contract != null); + Type? valueType = ReflectionUtils.GetObjectType(value); // type of value and type of target don't match // attempt to convert value's type to target's type @@ -955,11 +968,15 @@ private object EnsureType(JsonReader reader, object value, CultureInfo culture, { if (value is string s) { - return EnumUtils.ParseEnum(contract.NonNullableUnderlyingType, null, s, false); + return EnumUtils.ParseEnum( + contract.NonNullableUnderlyingType, + null, + s, + false); } if (ConvertUtils.IsInteger(primitiveContract.TypeCode)) { - return Enum.ToObject(contract.NonNullableUnderlyingType, value); + return Enum.ToObject(contract.NonNullableUnderlyingType, value!); } } else if (contract.NonNullableUnderlyingType == typeof(DateTime)) @@ -993,7 +1010,7 @@ private object EnsureType(JsonReader reader, object value, CultureInfo culture, return value; } - private bool SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target) + private bool SetPropertyValue(JsonProperty property, JsonConverter? propertyConverter, JsonContainerContract? containerContract, JsonProperty? containerProperty, JsonReader reader, object target) { bool skipSettingProperty = CalculatePropertyDetails( property, @@ -1003,8 +1020,8 @@ private bool SetPropertyValue(JsonProperty property, JsonConverter propertyConve reader, target, out bool useExistingValue, - out object currentValue, - out JsonContract propertyContract, + out object? currentValue, + out JsonContract? propertyContract, out bool gottenCurrentValue, out bool ignoredValue); @@ -1020,16 +1037,16 @@ private bool SetPropertyValue(JsonProperty property, JsonConverter propertyConve return false; } - object value; + object? value; if (propertyConverter != null && propertyConverter.CanRead) { - if (!gottenCurrentValue && target != null && property.Readable) + if (!gottenCurrentValue && property.Readable) { - currentValue = property.ValueProvider.GetValue(target); + currentValue = property.ValueProvider!.GetValue(target); } - value = DeserializeConvertable(propertyConverter, reader, property.PropertyType, currentValue); + value = DeserializeConvertable(propertyConverter, reader, property.PropertyType!, currentValue); } else { @@ -1042,7 +1059,7 @@ private bool SetPropertyValue(JsonProperty property, JsonConverter propertyConve if ((!useExistingValue || value != currentValue) && ShouldSetPropertyValue(property, containerContract as JsonObjectContract, value)) { - property.ValueProvider.SetValue(target, value); + property.ValueProvider!.SetValue(target, value); if (property.SetIsSpecified != null) { @@ -1063,14 +1080,14 @@ private bool SetPropertyValue(JsonProperty property, JsonConverter propertyConve private bool CalculatePropertyDetails( JsonProperty property, - ref JsonConverter propertyConverter, - JsonContainerContract containerContract, - JsonProperty containerProperty, + ref JsonConverter? propertyConverter, + JsonContainerContract? containerContract, + JsonProperty? containerProperty, JsonReader reader, object target, out bool useExistingValue, - out object currentValue, - out JsonContract propertyContract, + out object? currentValue, + out JsonContract? propertyContract, out bool gottenCurrentValue, out bool ignoredValue) { @@ -1097,14 +1114,15 @@ private bool CalculatePropertyDetails( if ((objectCreationHandling != ObjectCreationHandling.Replace) && (tokenType == JsonToken.StartArray || tokenType == JsonToken.StartObject || propertyConverter != null) - && property.Readable) + && property.Readable + && property.PropertyContract?.ContractType != JsonContractType.Linq) { - currentValue = property.ValueProvider.GetValue(target); + currentValue = property.ValueProvider!.GetValue(target); gottenCurrentValue = true; if (currentValue != null) { - propertyContract = GetContractSafe(currentValue.GetType()); + propertyContract = GetContract(currentValue.GetType()); useExistingValue = (!propertyContract.IsReadOnlyOrFixedSize && !propertyContract.UnderlyingType.IsValueType()); } @@ -1143,7 +1161,7 @@ private bool CalculatePropertyDetails( } else { - propertyContract = GetContractSafe(currentValue.GetType()); + propertyContract = GetContract(currentValue.GetType()); if (propertyContract != property.PropertyContract) { @@ -1176,7 +1194,7 @@ private bool HasFlag(DefaultValueHandling value, DefaultValueHandling flag) return ((value & flag) == flag); } - private bool ShouldSetPropertyValue(JsonProperty property, JsonObjectContract contract, object value) + private bool ShouldSetPropertyValue(JsonProperty property, JsonObjectContract? contract, object? value) { if (value == null && ResolvedNullValueHandling(contract, property) == NullValueHandling.Ignore) { @@ -1334,7 +1352,7 @@ private void OnDeserialized(JsonReader reader, JsonContract contract, object val contract.InvokeOnDeserialized(value, Serializer._context); } - private object PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, string id) + private object PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty? containerProperty, string? id) { object underlyingDictionary = dictionary is IWrappedDictionary wrappedDictionary ? wrappedDictionary.UnderlyingDictionary : dictionary; @@ -1357,7 +1375,7 @@ private object PopulateDictionary(IDictionary dictionary, JsonReader reader, Jso contract.ItemContract = GetContractSafe(contract.DictionaryValueType); } - JsonConverter dictionaryValueConverter = contract.ItemConverter ?? GetConverter(contract.ItemContract, null, contract, containerProperty); + JsonConverter? dictionaryValueConverter = contract.ItemConverter ?? GetConverter(contract.ItemContract, null, contract, containerProperty); PrimitiveTypeCode keyTypeCode = (contract.KeyContract is JsonPrimitiveContract keyContract) ? keyContract.TypeCode : PrimitiveTypeCode.Empty; bool finished = false; @@ -1366,8 +1384,8 @@ private object PopulateDictionary(IDictionary dictionary, JsonReader reader, Jso switch (reader.TokenType) { case JsonToken.PropertyName: - object keyValue = reader.Value; - if (CheckPropertyName(reader, keyValue.ToString())) + object keyValue = reader.Value!; + if (CheckPropertyName(reader, keyValue.ToString()!)) { continue; } @@ -1382,23 +1400,25 @@ private object PopulateDictionary(IDictionary dictionary, JsonReader reader, Jso case PrimitiveTypeCode.DateTime: case PrimitiveTypeCode.DateTimeNullable: { - keyValue = DateTimeUtils.TryParseDateTime(keyValue.ToString(), reader.DateTimeZoneHandling, reader.DateFormatString, reader.Culture, out DateTime dt) + keyValue = DateTimeUtils.TryParseDateTime(keyValue.ToString()!, reader.DateTimeZoneHandling, reader.DateFormatString, reader.Culture, out DateTime dt) ? dt - : EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType); + : EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType)!; break; } #if HAVE_DATE_TIME_OFFSET case PrimitiveTypeCode.DateTimeOffset: case PrimitiveTypeCode.DateTimeOffsetNullable: { - keyValue = DateTimeUtils.TryParseDateTimeOffset(keyValue.ToString(), reader.DateFormatString, reader.Culture, out DateTimeOffset dt) + keyValue = DateTimeUtils.TryParseDateTimeOffset(keyValue.ToString()!, reader.DateFormatString, reader.Culture, out DateTimeOffset dt) ? dt - : EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType); + : EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType)!; break; } #endif default: - keyValue = EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType); + keyValue = contract.KeyContract != null && contract.KeyContract.IsEnum + ? EnumUtils.ParseEnum(contract.KeyContract.NonNullableUnderlyingType, (Serializer._contractResolver as DefaultContractResolver)?.NamingStrategy, keyValue.ToString()!, false) + : EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType)!; break; } } @@ -1412,10 +1432,10 @@ private object PopulateDictionary(IDictionary dictionary, JsonReader reader, Jso throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object."); } - object itemValue; + object? itemValue; if (dictionaryValueConverter != null && dictionaryValueConverter.CanRead) { - itemValue = DeserializeConvertable(dictionaryValueConverter, reader, contract.DictionaryValueType, null); + itemValue = DeserializeConvertable(dictionaryValueConverter, reader, contract.DictionaryValueType!, null); } else { @@ -1455,7 +1475,7 @@ private object PopulateDictionary(IDictionary dictionary, JsonReader reader, Jso return underlyingDictionary; } - private object PopulateMultidimensionalArray(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id) + private object PopulateMultidimensionalArray(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty? containerProperty, string? id) { int rank = contract.UnderlyingType.GetArrayRank(); @@ -1466,8 +1486,8 @@ private object PopulateMultidimensionalArray(IList list, JsonReader reader, Json OnDeserializing(reader, contract, list); - JsonContract collectionItemContract = GetContractSafe(contract.CollectionItemType); - JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null, contract, containerProperty); + JsonContract? collectionItemContract = GetContractSafe(contract.CollectionItemType); + JsonConverter? collectionItemConverter = GetConverter(collectionItemContract, null, contract, containerProperty); int? previousErrorIndex = null; Stack listStack = new Stack(); @@ -1495,11 +1515,11 @@ private object PopulateMultidimensionalArray(IList list, JsonReader reader, Json case JsonToken.Comment: break; default: - object value; + object? value; if (collectionItemConverter != null && collectionItemConverter.CanRead) { - value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType, null); + value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType!, null); } else { @@ -1586,7 +1606,7 @@ private object PopulateMultidimensionalArray(IList list, JsonReader reader, Json return list; } - private void ThrowUnexpectedEndException(JsonReader reader, JsonContract contract, object currentObject, string message) + private void ThrowUnexpectedEndException(JsonReader reader, JsonContract contract, object? currentObject, string message) { try { @@ -1605,8 +1625,9 @@ private void ThrowUnexpectedEndException(JsonReader reader, JsonContract contrac } } - private object PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id) + private object PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty? containerProperty, string? id) { +#pragma warning disable CS8600, CS8602, CS8603, CS8604 object underlyingList = list is IWrappedCollection wrappedCollection ? wrappedCollection.UnderlyingCollection : list; if (id != null) @@ -1630,7 +1651,7 @@ private object PopulateList(IList list, JsonReader reader, JsonArrayContract con contract.ItemContract = GetContractSafe(contract.CollectionItemType); } - JsonConverter collectionItemConverter = GetConverter(contract.ItemContract, null, contract, containerProperty); + JsonConverter? collectionItemConverter = GetConverter(contract.ItemContract, null, contract, containerProperty); int? previousErrorIndex = null; @@ -1649,7 +1670,7 @@ private object PopulateList(IList list, JsonReader reader, JsonArrayContract con case JsonToken.Comment: break; default: - object value; + object? value; if (collectionItemConverter != null && collectionItemConverter.CanRead) { @@ -1702,10 +1723,11 @@ private object PopulateList(IList list, JsonReader reader, JsonArrayContract con OnDeserialized(reader, contract, underlyingList); return underlyingList; +#pragma warning restore CS8600, CS8602, CS8603, CS8604 } #if HAVE_BINARY_SERIALIZATION - private object CreateISerializable(JsonReader reader, JsonISerializableContract contract, JsonProperty member, string id) + private object CreateISerializable(JsonReader reader, JsonISerializableContract contract, JsonProperty? member, string? id) { Type objectType = contract.UnderlyingType; @@ -1731,7 +1753,7 @@ private object CreateISerializable(JsonReader reader, JsonISerializableContract switch (reader.TokenType) { case JsonToken.PropertyName: - string memberName = reader.Value.ToString(); + string memberName = reader.Value!.ToString()!; if (!reader.Read()) { throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); @@ -1777,15 +1799,15 @@ private object CreateISerializable(JsonReader reader, JsonISerializableContract return createdObject; } - internal object CreateISerializableItem(JToken token, Type type, JsonISerializableContract contract, JsonProperty member) + internal object? CreateISerializableItem(JToken token, Type type, JsonISerializableContract contract, JsonProperty? member) { - JsonContract itemContract = GetContractSafe(type); - JsonConverter itemConverter = GetConverter(itemContract, null, contract, member); + JsonContract? itemContract = GetContractSafe(type); + JsonConverter? itemConverter = GetConverter(itemContract, null, contract, member); JsonReader tokenReader = token.CreateReader(); tokenReader.ReadAndAssert(); // Move to first token - object result; + object? result; if (itemConverter != null && itemConverter.CanRead) { result = DeserializeConvertable(itemConverter, tokenReader, type, null); @@ -1800,7 +1822,7 @@ internal object CreateISerializableItem(JToken token, Type type, JsonISerializab #endif #if HAVE_DYNAMIC - private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, JsonProperty member, string id) + private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, JsonProperty? member, string? id) { IDynamicMetaObjectProvider newObject; @@ -1834,7 +1856,7 @@ private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, Js switch (reader.TokenType) { case JsonToken.PropertyName: - string memberName = reader.Value.ToString(); + string memberName = reader.Value!.ToString()!; try { @@ -1844,7 +1866,7 @@ private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, Js } // first attempt to find a settable property, otherwise fall back to a dynamic set without type - JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName); + JsonProperty? property = contract.Properties.GetClosestMatchProperty(memberName); if (property != null && property.Writable && !property.Ignored) { @@ -1853,7 +1875,7 @@ private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, Js property.PropertyContract = GetContractSafe(property.PropertyType); } - JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.Converter, null, null); + JsonConverter? propertyConverter = GetConverter(property.PropertyContract, property.Converter, null, null); if (!SetPropertyValue(property, propertyConverter, null, member, reader, newObject)) { @@ -1862,15 +1884,15 @@ private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, Js } else { - Type t = (JsonTokenUtils.IsPrimitiveToken(reader.TokenType)) ? reader.ValueType : typeof(IDynamicMetaObjectProvider); + Type t = (JsonTokenUtils.IsPrimitiveToken(reader.TokenType)) ? reader.ValueType! : typeof(IDynamicMetaObjectProvider); - JsonContract dynamicMemberContract = GetContractSafe(t); - JsonConverter dynamicMemberConverter = GetConverter(dynamicMemberContract, null, null, member); + JsonContract? dynamicMemberContract = GetContractSafe(t); + JsonConverter? dynamicMemberConverter = GetConverter(dynamicMemberContract, null, null, member); - object value; + object? value; if (dynamicMemberConverter != null && dynamicMemberConverter.CanRead) { - value = DeserializeConvertable(dynamicMemberConverter, reader, t, null); + value = DeserializeConvertable(dynamicMemberConverter!, reader, t, null); } else { @@ -1913,15 +1935,20 @@ private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, Js internal class CreatorPropertyContext { - public string Name; - public JsonProperty Property; - public JsonProperty ConstructorProperty; + public readonly string Name; + public JsonProperty? Property; + public JsonProperty? ConstructorProperty; public PropertyPresence? Presence; - public object Value; + public object? Value; public bool Used; + + public CreatorPropertyContext(string name) + { + Name = name; + } } - private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor creator, string id) + private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty? containerProperty, ObjectConstructor creator, string? id) { ValidationUtils.ArgumentNotNull(creator, nameof(creator)); @@ -1949,10 +1976,9 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj { if (propertyContexts.All(p => p.Property != property)) { - propertyContexts.Add(new CreatorPropertyContext + propertyContexts.Add(new CreatorPropertyContext(property.PropertyName!) { Property = property, - Name = property.PropertyName, Presence = PropertyPresence.None }); } @@ -1960,7 +1986,7 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj } } - object[] creatorParameterValues = new object[contract.CreatorParameters.Count]; + object?[] creatorParameterValues = new object?[contract.CreatorParameters.Count]; foreach (CreatorPropertyContext context in propertyContexts) { @@ -1969,7 +1995,7 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj { if (context.Property != null && context.Presence == null) { - object v = context.Value; + object? v = context.Value; PropertyPresence propertyPresence; if (v == null) { @@ -1990,10 +2016,10 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj } } - JsonProperty constructorProperty = context.ConstructorProperty; + JsonProperty? constructorProperty = context.ConstructorProperty; if (constructorProperty == null && context.Property != null) { - constructorProperty = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName, context.Property.UnderlyingName); + constructorProperty = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName!, context.Property.UnderlyingName!); } if (constructorProperty != null && !constructorProperty.Ignored) @@ -2015,7 +2041,7 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj reader, constructorProperty.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, - constructorProperty.PropertyContract, + constructorProperty.PropertyContract!, constructorProperty.PropertyType); } } @@ -2049,17 +2075,17 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj } JsonProperty property = context.Property; - object value = context.Value; + object? value = context.Value; if (ShouldSetPropertyValue(property, contract, value)) { - property.ValueProvider.SetValue(createdObject, value); + property.ValueProvider!.SetValue(createdObject, value); context.Used = true; } else if (!property.Writable && value != null) { // handle readonly collection/dictionary properties - JsonContract propertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType); + JsonContract propertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType!); if (propertyContract.ContractType == JsonContractType.Array) { @@ -2067,15 +2093,22 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj if (propertyArrayContract.CanDeserialize && !propertyArrayContract.IsReadOnlyOrFixedSize) { - object createdObjectCollection = property.ValueProvider.GetValue(createdObject); + object? createdObjectCollection = property.ValueProvider!.GetValue(createdObject); if (createdObjectCollection != null) { + propertyArrayContract = (JsonArrayContract)GetContract(createdObjectCollection.GetType()); + IList createdObjectCollectionWrapper = (propertyArrayContract.ShouldCreateWrapper) ? propertyArrayContract.CreateWrapper(createdObjectCollection) : (IList)createdObjectCollection; - IList newValues = (propertyArrayContract.ShouldCreateWrapper) ? propertyArrayContract.CreateWrapper(value) : (IList)value; - foreach (object newValue in newValues) + // Don't attempt to populate array/read-only list + if (!createdObjectCollectionWrapper.IsFixedSize) { - createdObjectCollectionWrapper.Add(newValue); + IList newValues = (propertyArrayContract.ShouldCreateWrapper) ? propertyArrayContract.CreateWrapper(value) : (IList)value; + + foreach (object newValue in newValues) + { + createdObjectCollectionWrapper.Add(newValue); + } } } } @@ -2086,7 +2119,7 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj if (!dictionaryContract.IsReadOnlyOrFixedSize) { - object createdObjectDictionary = property.ValueProvider.GetValue(createdObject); + object? createdObjectDictionary = property.ValueProvider!.GetValue(createdObject); if (createdObjectDictionary != null) { IDictionary targetDictionary = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(createdObjectDictionary) : (IDictionary)createdObjectDictionary; @@ -2149,14 +2182,14 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj return createdObject; } - private object DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, object existingValue) + private object? DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, object? existingValue) { if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) { TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Started deserializing {0} with converter {1}.".FormatWith(CultureInfo.InvariantCulture, objectType, converter.GetType())), null); } - object value = converter.ReadJson(reader, objectType, existingValue, GetInternalSerializer()); + object? value = converter.ReadJson(reader, objectType, existingValue, GetInternalSerializer()); if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) { @@ -2166,7 +2199,7 @@ private object DeserializeConvertable(JsonConverter converter, JsonReader reader return value; } - private List ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType) + private List ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty? containerProperty, JsonReader reader, Type objectType) { List propertyValues = new List(); bool exit = false; @@ -2175,41 +2208,43 @@ private List ResolvePropertyAndCreatorValues(JsonObjectC switch (reader.TokenType) { case JsonToken.PropertyName: - string memberName = reader.Value.ToString(); + string memberName = reader.Value!.ToString()!; - CreatorPropertyContext creatorPropertyContext = new CreatorPropertyContext + CreatorPropertyContext creatorPropertyContext = new CreatorPropertyContext(memberName) { - Name = reader.Value.ToString(), ConstructorProperty = contract.CreatorParameters.GetClosestMatchProperty(memberName), Property = contract.Properties.GetClosestMatchProperty(memberName) }; propertyValues.Add(creatorPropertyContext); - JsonProperty property = creatorPropertyContext.ConstructorProperty ?? creatorPropertyContext.Property; - if (property != null && !property.Ignored) + JsonProperty? property = creatorPropertyContext.ConstructorProperty ?? creatorPropertyContext.Property; + if (property != null) { - if (property.PropertyContract == null) + if (!property.Ignored) { - property.PropertyContract = GetContractSafe(property.PropertyType); - } + if (property.PropertyContract == null) + { + property.PropertyContract = GetContractSafe(property.PropertyType); + } - JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.Converter, contract, containerProperty); + JsonConverter? propertyConverter = GetConverter(property.PropertyContract, property.Converter, contract, containerProperty); - if (!reader.ReadForType(property.PropertyContract, propertyConverter != null)) - { - throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); - } + if (!reader.ReadForType(property.PropertyContract, propertyConverter != null)) + { + throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); + } - if (propertyConverter != null && propertyConverter.CanRead) - { - creatorPropertyContext.Value = DeserializeConvertable(propertyConverter, reader, property.PropertyType, null); - } - else - { - creatorPropertyContext.Value = CreateValueInternal(reader, property.PropertyType, property.PropertyContract, property, contract, containerProperty, null); + if (propertyConverter != null && propertyConverter.CanRead) + { + creatorPropertyContext.Value = DeserializeConvertable(propertyConverter, reader, property.PropertyType!, null); + } + else + { + creatorPropertyContext.Value = CreateValueInternal(reader, property.PropertyType, property.PropertyContract, property, contract, containerProperty, null); + } + + continue; } - - continue; } else { @@ -2223,7 +2258,7 @@ private List ResolvePropertyAndCreatorValues(JsonObjectC TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Could not find member '{0}' on {1}.".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType)), null); } - if (Serializer._missingMemberHandling == MissingMemberHandling.Error) + if ((contract.MissingMemberHandling ?? Serializer._missingMemberHandling) == MissingMemberHandling.Error) { throw JsonSerializationException.Create(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, objectType.Name)); } @@ -2256,9 +2291,9 @@ private List ResolvePropertyAndCreatorValues(JsonObjectC return propertyValues; } - public object CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, string id, out bool createdFromNonDefaultCreator) + public object CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty? containerMember, JsonProperty? containerProperty, string? id, out bool createdFromNonDefaultCreator) { - object newObject = null; + object? newObject = null; if (objectContract.OverrideCreator != null) { @@ -2299,12 +2334,12 @@ public object CreateNewObject(JsonReader reader, JsonObjectContract objectContra return newObject; } - private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id) + private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty? member, string? id) { OnDeserializing(reader, contract, newObject); // only need to keep a track of properties' presence if they are required or a value should be defaulted if missing - Dictionary propertiesPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer._defaultValueHandling, DefaultValueHandling.Populate)) + Dictionary? propertiesPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer._defaultValueHandling, DefaultValueHandling.Populate)) ? contract.Properties.ToDictionary(m => m, m => PropertyPresence.None) : null; @@ -2322,7 +2357,7 @@ private object PopulateObject(object newObject, JsonReader reader, JsonObjectCon { case JsonToken.PropertyName: { - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; if (CheckPropertyName(reader, propertyName)) { @@ -2333,7 +2368,7 @@ private object PopulateObject(object newObject, JsonReader reader, JsonObjectCon { // attempt exact case match first // then try match ignoring case - JsonProperty property = contract.Properties.GetClosestMatchProperty(propertyName); + JsonProperty? property = contract.Properties.GetClosestMatchProperty(propertyName); if (property == null) { @@ -2342,7 +2377,7 @@ private object PopulateObject(object newObject, JsonReader reader, JsonObjectCon TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Could not find member '{0}' on {1}".FormatWith(CultureInfo.InvariantCulture, propertyName, contract.UnderlyingType)), null); } - if (Serializer._missingMemberHandling == MissingMemberHandling.Error) + if ((contract.MissingMemberHandling ?? Serializer._missingMemberHandling) == MissingMemberHandling.Error) { throw JsonSerializationException.Create(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, propertyName, contract.UnderlyingType.Name)); } @@ -2373,7 +2408,7 @@ private object PopulateObject(object newObject, JsonReader reader, JsonObjectCon property.PropertyContract = GetContractSafe(property.PropertyType); } - JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.Converter, contract, member); + JsonConverter? propertyConverter = GetConverter(property.PropertyContract, property.Converter, contract, member); if (!reader.ReadForType(property.PropertyContract, propertyConverter != null)) { @@ -2467,13 +2502,13 @@ private bool CheckPropertyName(JsonReader reader, string memberName) return false; } - private void SetExtensionData(JsonObjectContract contract, JsonProperty member, JsonReader reader, string memberName, object o) + private void SetExtensionData(JsonObjectContract contract, JsonProperty? member, JsonReader reader, string memberName, object o) { if (contract.ExtensionDataSetter != null) { try { - object value = ReadExtensionDataValue(contract, member, reader); + object? value = ReadExtensionDataValue(contract, member, reader); contract.ExtensionDataSetter(o, memberName, value); } @@ -2488,9 +2523,9 @@ private void SetExtensionData(JsonObjectContract contract, JsonProperty member, } } - private object ReadExtensionDataValue(JsonObjectContract contract, JsonProperty member, JsonReader reader) + private object? ReadExtensionDataValue(JsonObjectContract contract, JsonProperty? member, JsonReader reader) { - object value; + object? value; if (contract.ExtensionDataIsJToken) { value = JToken.ReadFrom(reader); @@ -2527,7 +2562,7 @@ private void EndProcessProperty(object newObject, JsonReader reader, JsonObjectC if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate) && property.Writable) { - property.ValueProvider.SetValue(newObject, EnsureType(reader, property.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, property.PropertyContract, property.PropertyType)); + property.ValueProvider!.SetValue(newObject, EnsureType(reader, property.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, property.PropertyContract!, property.PropertyType)); } } break; @@ -2557,7 +2592,7 @@ private void EndProcessProperty(object newObject, JsonReader reader, JsonObjectC } } - private void SetPropertyPresence(JsonReader reader, JsonProperty property, Dictionary requiredProperties) + private void SetPropertyPresence(JsonReader reader, JsonProperty property, Dictionary? requiredProperties) { if (property != null && requiredProperties != null) { @@ -2565,7 +2600,7 @@ private void SetPropertyPresence(JsonReader reader, JsonProperty property, Dicti switch (reader.TokenType) { case JsonToken.String: - propertyPresence = (CoerceEmptyStringToNull(property.PropertyType, property.PropertyContract, (string)reader.Value)) + propertyPresence = (CoerceEmptyStringToNull(property.PropertyType, property.PropertyContract, (string)reader.Value!)) ? PropertyPresence.Null : PropertyPresence.Value; break; @@ -2600,4 +2635,5 @@ private void HandleError(JsonReader reader, bool readPastError, int initialDepth } } } +#nullable disable } diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerInternalWriter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerInternalWriter.cs index 32759f7784..e95b84c53f 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerInternalWriter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerInternalWriter.cs @@ -37,18 +37,20 @@ using Microsoft.IdentityModel.Json.Linq; using Microsoft.IdentityModel.Json.Utilities; using System.Runtime.Serialization; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else using System.Linq; - #endif namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable internal class JsonSerializerInternalWriter : JsonSerializerInternalBase { - private Type _rootType; + private Type? _rootType; private int _rootLevel; private readonly List _serializeStack = new List(); @@ -57,7 +59,7 @@ public JsonSerializerInternalWriter(JsonSerializer serializer) { } - public void Serialize(JsonWriter jsonWriter, object value, Type objectType) + public void Serialize(JsonWriter jsonWriter, object? value, Type? objectType) { if (jsonWriter == null) { @@ -67,13 +69,13 @@ public void Serialize(JsonWriter jsonWriter, object value, Type objectType) _rootType = objectType; _rootLevel = _serializeStack.Count + 1; - JsonContract contract = GetContractSafe(value); + JsonContract? contract = GetContractSafe(value); try { if (ShouldWriteReference(value, null, contract, null, null)) { - WriteReference(jsonWriter, value); + WriteReference(jsonWriter, value!); } else { @@ -113,17 +115,22 @@ private JsonSerializerProxy GetInternalSerializer() return InternalSerializer; } - private JsonContract GetContractSafe(object value) + private JsonContract? GetContractSafe(object? value) { if (value == null) { return null; } + return GetContract(value); + } + + private JsonContract GetContract(object value) + { return Serializer._contractResolver.ResolveContract(value.GetType()); } - private void SerializePrimitive(JsonWriter writer, object value, JsonPrimitiveContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) + private void SerializePrimitive(JsonWriter writer, object value, JsonPrimitiveContract contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerProperty) { if (contract.TypeCode == PrimitiveTypeCode.Bytes) { @@ -145,7 +152,7 @@ private void SerializePrimitive(JsonWriter writer, object value, JsonPrimitiveCo JsonWriter.WriteValue(writer, contract.TypeCode, value); } - private void SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) + private void SerializeValue(JsonWriter writer, object? value, JsonContract? valueContract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerProperty) { if (value == null) { @@ -153,7 +160,9 @@ private void SerializeValue(JsonWriter writer, object value, JsonContract valueC return; } - JsonConverter converter = + MiscellaneousUtils.Assert(valueContract != null); + + JsonConverter? converter = member?.Converter ?? containerProperty?.ItemConverter ?? containerContract?.ItemConverter ?? @@ -209,7 +218,7 @@ private void SerializeValue(JsonWriter writer, object value, JsonContract valueC } } - private bool? ResolveIsReference(JsonContract contract, JsonProperty property, JsonContainerContract collectionContract, JsonProperty containerProperty) + private bool? ResolveIsReference(JsonContract contract, JsonProperty? property, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { bool? isReference = null; @@ -237,12 +246,15 @@ private void SerializeValue(JsonWriter writer, object value, JsonContract valueC return isReference; } - private bool ShouldWriteReference(object value, JsonProperty property, JsonContract valueContract, JsonContainerContract collectionContract, JsonProperty containerProperty) + private bool ShouldWriteReference(object? value, JsonProperty? property, JsonContract? valueContract, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { if (value == null) { return false; } + + MiscellaneousUtils.Assert(valueContract != null); + if (valueContract.ContractType == JsonContractType.Primitive || valueContract.ContractType == JsonContractType.String) { return false; @@ -270,7 +282,7 @@ private bool ShouldWriteReference(object value, JsonProperty property, JsonContr return Serializer.GetReferenceResolver().IsReferenced(this, value); } - private bool ShouldWriteProperty(object memberValue, JsonObjectContract containerContract, JsonProperty property) + private bool ShouldWriteProperty(object? memberValue, JsonObjectContract? containerContract, JsonProperty property) { if (memberValue == null && ResolvedNullValueHandling(containerContract, property) == NullValueHandling.Ignore) { @@ -286,9 +298,16 @@ private bool ShouldWriteProperty(object memberValue, JsonObjectContract containe return true; } - private bool CheckForCircularReference(JsonWriter writer, object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty) + private bool CheckForCircularReference(JsonWriter writer, object? value, JsonProperty? property, JsonContract? contract, JsonContainerContract? containerContract, JsonProperty? containerProperty) { - if (value == null || contract.ContractType == JsonContractType.Primitive || contract.ContractType == JsonContractType.String) + if (value == null) + { + return true; + } + + MiscellaneousUtils.Assert(contract != null); + + if (contract.ContractType == JsonContractType.Primitive || contract.ContractType == JsonContractType.String) { return true; } @@ -376,12 +395,25 @@ private string GetReference(JsonWriter writer, object value) } } - internal static bool TryConvertToString(object value, Type type, out string s) + internal static bool TryConvertToString(object value, Type type, [NotNullWhen(true)]out string? s) { +#if HAVE_DATE_ONLY + if (value is DateOnly dateOnly) + { + s = dateOnly.ToString("yyyy'-'MM'-'dd", CultureInfo.InvariantCulture); + return true; + } + if (value is TimeOnly timeOnly) + { + s = timeOnly.ToString("HH':'mm':'ss.FFFFFFF", CultureInfo.InvariantCulture); + return true; + } +#endif + #if HAVE_TYPE_DESCRIPTOR if (JsonTypeReflector.CanTypeDescriptorConvertString(type, out TypeConverter converter)) { - s = converter.ConvertToInvariantString(value); + s = converter.ConvertToInvariantString(value)!; return true; } #endif @@ -394,10 +426,9 @@ internal static bool TryConvertToString(object value, Type type, out string s) } #endif - type = value as Type; - if (type != null) + if (value is Type t) { - s = type.AssemblyQualifiedName; + s = t.AssemblyQualifiedName!; return true; } @@ -409,7 +440,7 @@ private void SerializeString(JsonWriter writer, object value, JsonStringContract { OnSerializing(writer, contract, value); - TryConvertToString(value, contract.UnderlyingType, out string s); + TryConvertToString(value, contract.UnderlyingType, out string? s); writer.WriteValue(s); OnSerialized(writer, contract, value); @@ -435,7 +466,7 @@ private void OnSerialized(JsonWriter writer, JsonContract contract, object value contract.InvokeOnSerialized(value, Serializer._context); } - private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { OnSerializing(writer, contract, value); @@ -450,7 +481,7 @@ private void SerializeObject(JsonWriter writer, object value, JsonObjectContract JsonProperty property = contract.Properties[index]; try { - if (!CalculatePropertyValues(writer, value, contract, member, property, out JsonContract memberContract, out object memberValue)) + if (!CalculatePropertyValues(writer, value, contract, member, property, out JsonContract? memberContract, out object? memberValue)) { continue; } @@ -471,13 +502,13 @@ private void SerializeObject(JsonWriter writer, object value, JsonObjectContract } } - IEnumerable> extensionData = contract.ExtensionDataGetter?.Invoke(value); + IEnumerable>? extensionData = contract.ExtensionDataGetter?.Invoke(value); if (extensionData != null) { foreach (KeyValuePair e in extensionData) { - JsonContract keyContract = GetContractSafe(e.Key); - JsonContract valueContract = GetContractSafe(e.Value); + JsonContract keyContract = GetContract(e.Key); + JsonContract? valueContract = GetContractSafe(e.Value); string propertyName = GetPropertyName(writer, e.Key, keyContract, out _); @@ -488,7 +519,7 @@ private void SerializeObject(JsonWriter writer, object value, JsonObjectContract if (ShouldWriteReference(e.Value, null, valueContract, contract, member)) { writer.WritePropertyName(propertyName); - WriteReference(writer, e.Value); + WriteReference(writer, e.Value!); } else { @@ -511,16 +542,16 @@ private void SerializeObject(JsonWriter writer, object value, JsonObjectContract OnSerialized(writer, contract, value); } - private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, out JsonContract memberContract, out object memberValue) + private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContainerContract contract, JsonProperty? member, JsonProperty property, [NotNullWhen(true)]out JsonContract? memberContract, out object? memberValue) { if (!property.Ignored && property.Readable && ShouldSerialize(writer, property, value) && IsSpecified(writer, property, value)) { if (property.PropertyContract == null) { - property.PropertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType); + property.PropertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType!); } - memberValue = property.ValueProvider.GetValue(value); + memberValue = property.ValueProvider!.GetValue(value); memberContract = (property.PropertyContract.IsSealed) ? property.PropertyContract : GetContractSafe(memberValue); if (ShouldWriteProperty(memberValue, contract as JsonObjectContract, property)) @@ -528,7 +559,7 @@ private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContai if (ShouldWriteReference(memberValue, property, memberContract, contract, member)) { property.WritePropertyName(writer); - WriteReference(writer, memberValue); + WriteReference(writer, memberValue!); return false; } @@ -539,7 +570,7 @@ private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContai if (memberValue == null) { - JsonObjectContract objectContract = contract as JsonObjectContract; + JsonObjectContract? objectContract = contract as JsonObjectContract; Required resolvedRequired = property._required ?? objectContract?.ItemRequired ?? Required.Default; if (resolvedRequired == Required.Always) { @@ -551,7 +582,9 @@ private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContai } } +#pragma warning disable CS8762 // Parameter must have a non-null value when exiting in some condition. return true; +#pragma warning restore CS8762 // Parameter must have a non-null value when exiting in some condition. } } @@ -560,7 +593,7 @@ private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContai return false; } - private void WriteObjectStart(JsonWriter writer, object value, JsonContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void WriteObjectStart(JsonWriter writer, object value, JsonContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { writer.WriteStartObject(); @@ -576,14 +609,14 @@ private void WriteObjectStart(JsonWriter writer, object value, JsonContract cont } } - private bool HasCreatorParameter(JsonContainerContract contract, JsonProperty property) + private bool HasCreatorParameter(JsonContainerContract? contract, JsonProperty property) { if (!(contract is JsonObjectContract objectContract)) { return false; } - return objectContract.CreatorParameters.Contains(property.PropertyName); + return objectContract.CreatorParameters.Contains(property.PropertyName!); } private void WriteReferenceIdProperty(JsonWriter writer, Type type, object value) @@ -627,7 +660,7 @@ private bool HasFlag(TypeNameHandling value, TypeNameHandling flag) return ((value & flag) == flag); } - private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value, JsonContract contract, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value, JsonContract contract, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { if (ShouldWriteReference(value, null, contract, collectionContract, containerProperty)) { @@ -658,7 +691,7 @@ private void SerializeConvertable(JsonWriter writer, JsonConverter converter, ob } } - private void SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { object underlyingList = values is IWrappedCollection wrappedCollection ? wrappedCollection.UnderlyingCollection : values; @@ -678,7 +711,7 @@ private void SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContr { try { - JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value); + JsonContract? valueContract = contract.FinalItemContract ?? GetContractSafe(value); if (ShouldWriteReference(value, null, valueContract, contract, member)) { @@ -721,7 +754,7 @@ private void SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContr OnSerialized(writer, contract, underlyingList); } - private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { OnSerializing(writer, contract, values); @@ -741,7 +774,7 @@ private void SerializeMultidimensionalArray(JsonWriter writer, Array values, Jso OnSerialized(writer, contract, values); } - private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty member, int initialDepth, int[] indices) + private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty? member, int initialDepth, int[] indices) { int dimension = indices.Length; int[] newIndices = new int[dimension + 1]; @@ -759,11 +792,11 @@ private void SerializeMultidimensionalArray(JsonWriter writer, Array values, Jso if (isTopLevel) { - object value = values.GetValue(newIndices); + object value = values.GetValue(newIndices)!; try { - JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value); + JsonContract? valueContract = contract.FinalItemContract ?? GetContractSafe(value); if (ShouldWriteReference(value, null, valueContract, contract, member)) { @@ -798,7 +831,7 @@ private void SerializeMultidimensionalArray(JsonWriter writer, Array values, Jso writer.WriteEndArray(); } - private bool WriteStartArray(JsonWriter writer, object values, JsonArrayContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) + private bool WriteStartArray(JsonWriter writer, object values, JsonArrayContract contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerProperty) { bool isReference = ResolveIsReference(contract, member, containerContract, containerProperty) ?? HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Arrays); // don't make readonly fields that aren't creator parameters the referenced value because they can't be deserialized to @@ -834,7 +867,7 @@ private bool WriteStartArray(JsonWriter writer, object values, JsonArrayContract #if HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE [SecuritySafeCritical] #endif - private void SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { if (!JsonTypeReflector.FullyTrusted) { @@ -855,12 +888,12 @@ private void SerializeISerializable(JsonWriter writer, ISerializable value, Json foreach (SerializationEntry serializationEntry in serializationInfo) { - JsonContract valueContract = GetContractSafe(serializationEntry.Value); + JsonContract? valueContract = GetContractSafe(serializationEntry.Value); if (ShouldWriteReference(serializationEntry.Value, null, valueContract, contract, member)) { writer.WritePropertyName(serializationEntry.Name); - WriteReference(writer, serializationEntry.Value); + WriteReference(writer, serializationEntry.Value!); } else if (CheckForCircularReference(writer, serializationEntry.Value, null, valueContract, contract, member)) { @@ -877,7 +910,7 @@ private void SerializeISerializable(JsonWriter writer, ISerializable value, Json #endif #if HAVE_DYNAMIC - private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider value, JsonDynamicContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider value, JsonDynamicContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { OnSerializing(writer, contract, value); _serializeStack.Add(value); @@ -895,7 +928,7 @@ private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider valu { try { - if (!CalculatePropertyValues(writer, value, contract, member, property, out JsonContract memberContract, out object memberValue)) + if (!CalculatePropertyValues(writer, value, contract, member, property, out JsonContract? memberContract, out object? memberValue)) { continue; } @@ -919,11 +952,11 @@ private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider valu foreach (string memberName in value.GetDynamicMemberNames()) { - if (contract.TryGetMember(value, memberName, out object memberValue)) + if (contract.TryGetMember(value, memberName, out object? memberValue)) { try { - JsonContract valueContract = GetContractSafe(memberValue); + JsonContract? valueContract = GetContractSafe(memberValue); if (!ShouldWriteDynamicProperty(memberValue)) { @@ -961,7 +994,7 @@ private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider valu } #endif - private bool ShouldWriteDynamicProperty(object memberValue) + private bool ShouldWriteDynamicProperty(object? memberValue) { if (Serializer._nullValueHandling == NullValueHandling.Ignore && memberValue == null) { @@ -977,7 +1010,7 @@ private bool ShouldWriteDynamicProperty(object memberValue) return true; } - private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) + private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerProperty) { TypeNameHandling resolvedTypeNameHandling = member?.TypeNameHandling @@ -995,7 +1028,7 @@ private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract { if (member != null) { - if (contract.NonNullableUnderlyingType != member.PropertyContract.CreatedType) + if (contract.NonNullableUnderlyingType != member.PropertyContract!.CreatedType) { return true; } @@ -1021,8 +1054,9 @@ private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract return false; } - private void SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { +#pragma warning disable CS8600, CS8602, CS8604 object underlyingDictionary = values is IWrappedDictionary wrappedDictionary ? wrappedDictionary.UnderlyingDictionary : values; OnSerializing(writer, contract, underlyingDictionary); @@ -1059,7 +1093,7 @@ private void SerializeDictionary(JsonWriter writer, IDictionary values, JsonDict try { object value = entry.Value; - JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value); + JsonContract? valueContract = contract.FinalItemContract ?? GetContractSafe(value); if (ShouldWriteReference(value, null, valueContract, contract, member)) { @@ -1101,6 +1135,7 @@ private void SerializeDictionary(JsonWriter writer, IDictionary values, JsonDict _serializeStack.RemoveAt(_serializeStack.Count - 1); OnSerialized(writer, contract, underlyingDictionary); +#pragma warning restore CS8600, CS8602, CS8604 } private string GetPropertyName(JsonWriter writer, object name, JsonContract contract, out bool escape) @@ -1150,16 +1185,16 @@ private string GetPropertyName(JsonWriter writer, object name, JsonContract cont { escape = true; - if (primitiveContract.IsEnum && EnumUtils.TryToString(primitiveContract.NonNullableUnderlyingType, name, null, out string enumName)) + if (primitiveContract.IsEnum && EnumUtils.TryToString(primitiveContract.NonNullableUnderlyingType, name, null, out string? enumName)) { return enumName; } - return Convert.ToString(name, CultureInfo.InvariantCulture); + return Convert.ToString(name, CultureInfo.InvariantCulture)!; } } } - else if (TryConvertToString(name, name.GetType(), out string propertyName)) + else if (TryConvertToString(name, name.GetType(), out string? propertyName)) { escape = true; return propertyName; @@ -1167,7 +1202,7 @@ private string GetPropertyName(JsonWriter writer, object name, JsonContract cont else { escape = true; - return name.ToString(); + return name.ToString()!; } } @@ -1220,4 +1255,5 @@ private bool IsSpecified(JsonWriter writer, JsonProperty property, object target return isSpecified; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerProxy.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerProxy.cs index 30fdb0bfaf..7023e1290a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerProxy.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonSerializerProxy.cs @@ -32,31 +32,32 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable internal class JsonSerializerProxy : JsonSerializer { - private readonly JsonSerializerInternalReader _serializerReader; - private readonly JsonSerializerInternalWriter _serializerWriter; - private readonly JsonSerializer _serializer; + private readonly JsonSerializerInternalReader? _serializerReader; + private readonly JsonSerializerInternalWriter? _serializerWriter; + internal readonly JsonSerializer _serializer; - public override event EventHandler Error + public override event EventHandler? Error { add => _serializer.Error += value; remove => _serializer.Error -= value; } - public override IReferenceResolver ReferenceResolver + public override IReferenceResolver? ReferenceResolver { get => _serializer.ReferenceResolver; set => _serializer.ReferenceResolver = value; } - public override ITraceWriter TraceWriter + public override ITraceWriter? TraceWriter { get => _serializer.TraceWriter; set => _serializer.TraceWriter = value; } - public override IEqualityComparer EqualityComparer + public override IEqualityComparer? EqualityComparer { get => _serializer.EqualityComparer; set => _serializer.EqualityComparer = value; @@ -137,12 +138,12 @@ public override ConstructorHandling ConstructorHandling set => _serializer.ConstructorHandling = value; } - //[Obsolete("Binder is obsolete. Use SerializationBinder instead.")] - //public override SerializationBinder Binder - //{ - // get => _serializer.Binder; - // set => _serializer.Binder = value; - //} + [Obsolete("Binder is obsolete. Use SerializationBinder instead.")] + public override SerializationBinder Binder + { + get => _serializer.Binder; + set => _serializer.Binder = value; + } public override ISerializationBinder SerializationBinder { @@ -230,7 +231,7 @@ internal JsonSerializerInternalBase GetInternalSerializer() } else { - return _serializerWriter; + return _serializerWriter!; } } @@ -250,7 +251,7 @@ public JsonSerializerProxy(JsonSerializerInternalWriter serializerWriter) _serializer = serializerWriter.Serializer; } - internal override object DeserializeInternal(JsonReader reader, Type objectType) + internal override object? DeserializeInternal(JsonReader reader, Type? objectType) { if (_serializerReader != null) { @@ -274,7 +275,7 @@ internal override void PopulateInternal(JsonReader reader, object target) } } - internal override void SerializeInternal(JsonWriter jsonWriter, object value, Type rootType) + internal override void SerializeInternal(JsonWriter jsonWriter, object? value, Type? rootType) { if (_serializerWriter != null) { @@ -286,4 +287,5 @@ internal override void SerializeInternal(JsonWriter jsonWriter, object value, Ty } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonStringContract.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonStringContract.cs index ea4ec0c1ee..d743ccdc6a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonStringContract.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonStringContract.cs @@ -42,4 +42,4 @@ public JsonStringContract(Type underlyingType) ContractType = JsonContractType.String; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonTypeReflector.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonTypeReflector.cs index 680074d6f6..a2089741e1 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonTypeReflector.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/JsonTypeReflector.cs @@ -33,6 +33,7 @@ using System.Security.Permissions; #endif using Microsoft.IdentityModel.Json.Utilities; +using System.Runtime.CompilerServices; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else @@ -42,6 +43,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable internal static class JsonTypeReflector { private static bool? _dynamicCodeGeneration; @@ -58,15 +60,15 @@ internal static class JsonTypeReflector public const string ConcurrentDictionaryTypeName = "System.Collections.Concurrent.ConcurrentDictionary`2"; - private static readonly ThreadSafeStore> CreatorCache = - new ThreadSafeStore>(GetCreator); + private static readonly ThreadSafeStore> CreatorCache = + new ThreadSafeStore>(GetCreator); #if !(NET20 || DOTNET) - private static readonly ThreadSafeStore AssociatedMetadataTypesCache = new ThreadSafeStore(GetAssociateMetadataTypeFromAttribute); - private static ReflectionObject _metadataTypeAttributeReflectionObject; + private static readonly ThreadSafeStore AssociatedMetadataTypesCache = new ThreadSafeStore(GetAssociateMetadataTypeFromAttribute); + private static ReflectionObject? _metadataTypeAttributeReflectionObject; #endif - public static T GetCachedAttribute(object attributeProvider) where T : Attribute + public static T? GetCachedAttribute(object attributeProvider) where T : Attribute { return CachedAttributeGetter.GetAttribute(attributeProvider); } @@ -96,14 +98,14 @@ public static bool CanTypeDescriptorConvertString(Type type, out TypeConverter t #endif #if HAVE_DATA_CONTRACTS - public static DataContractAttribute GetDataContractAttribute(Type type) + public static DataContractAttribute? GetDataContractAttribute(Type type) { // DataContractAttribute does not have inheritance - Type currentType = type; + Type? currentType = type; while (currentType != null) { - DataContractAttribute result = CachedAttributeGetter.GetAttribute(currentType); + DataContractAttribute? result = CachedAttributeGetter.GetAttribute(currentType); if (result != null) { return result; @@ -115,7 +117,7 @@ public static DataContractAttribute GetDataContractAttribute(Type type) return null; } - public static DataMemberAttribute GetDataMemberAttribute(MemberInfo memberInfo) + public static DataMemberAttribute? GetDataMemberAttribute(MemberInfo memberInfo) { // DataMemberAttribute does not have inheritance @@ -127,16 +129,16 @@ public static DataMemberAttribute GetDataMemberAttribute(MemberInfo memberInfo) // search property and then search base properties if nothing is returned and the property is virtual PropertyInfo propertyInfo = (PropertyInfo)memberInfo; - DataMemberAttribute result = CachedAttributeGetter.GetAttribute(propertyInfo); + DataMemberAttribute? result = CachedAttributeGetter.GetAttribute(propertyInfo); if (result == null) { if (propertyInfo.IsVirtual()) { - Type currentType = propertyInfo.DeclaringType; + Type? currentType = propertyInfo.DeclaringType; while (result == null && currentType != null) { - PropertyInfo baseProperty = (PropertyInfo)ReflectionUtils.GetMemberInfoFromType(currentType, propertyInfo); + PropertyInfo? baseProperty = (PropertyInfo?)ReflectionUtils.GetMemberInfoFromType(currentType, propertyInfo); if (baseProperty != null && baseProperty.IsVirtual()) { result = CachedAttributeGetter.GetAttribute(baseProperty); @@ -153,14 +155,14 @@ public static DataMemberAttribute GetDataMemberAttribute(MemberInfo memberInfo) public static MemberSerialization GetObjectMemberSerialization(Type objectType, bool ignoreSerializableAttribute) { - JsonObjectAttribute objectAttribute = GetCachedAttribute(objectType); + JsonObjectAttribute? objectAttribute = GetCachedAttribute(objectType); if (objectAttribute != null) { return objectAttribute.MemberSerialization; } #if HAVE_DATA_CONTRACTS - DataContractAttribute dataContractAttribute = GetDataContractAttribute(objectType); + DataContractAttribute? dataContractAttribute = GetDataContractAttribute(objectType); if (dataContractAttribute != null) { return MemberSerialization.OptIn; @@ -178,13 +180,13 @@ public static MemberSerialization GetObjectMemberSerialization(Type objectType, return MemberSerialization.OptOut; } - public static JsonConverter GetJsonConverter(object attributeProvider) + public static JsonConverter? GetJsonConverter(object attributeProvider) { - JsonConverterAttribute converterAttribute = GetCachedAttribute(attributeProvider); + JsonConverterAttribute? converterAttribute = GetCachedAttribute(attributeProvider); if (converterAttribute != null) { - Func creator = CreatorCache.Get(converterAttribute.ConverterType); + Func creator = CreatorCache.Get(converterAttribute.ConverterType); if (creator != null) { return (JsonConverter)creator(converterAttribute.ConverterParameters); @@ -200,19 +202,19 @@ public static JsonConverter GetJsonConverter(object attributeProvider) /// The type to create. /// Optional arguments to pass to an initializing constructor of the JsonConverter. /// If null, the default constructor is used. - public static JsonConverter CreateJsonConverterInstance(Type converterType, object[] args) + public static JsonConverter CreateJsonConverterInstance(Type converterType, object[]? args) { - Func converterCreator = CreatorCache.Get(converterType); + Func converterCreator = CreatorCache.Get(converterType); return (JsonConverter)converterCreator(args); } - public static NamingStrategy CreateNamingStrategyInstance(Type namingStrategyType, object[] args) + public static NamingStrategy CreateNamingStrategyInstance(Type namingStrategyType, object[]? args) { - Func converterCreator = CreatorCache.Get(namingStrategyType); + Func converterCreator = CreatorCache.Get(namingStrategyType); return (NamingStrategy)converterCreator(args); } - public static NamingStrategy GetContainerNamingStrategy(JsonContainerAttribute containerAttribute) + public static NamingStrategy? GetContainerNamingStrategy(JsonContainerAttribute containerAttribute) { if (containerAttribute.NamingStrategyInstance == null) { @@ -227,9 +229,9 @@ public static NamingStrategy GetContainerNamingStrategy(JsonContainerAttribute c return containerAttribute.NamingStrategyInstance; } - private static Func GetCreator(Type type) + private static Func GetCreator(Type type) { - Func defaultConstructor = (ReflectionUtils.HasDefaultConstructor(type, false)) + Func? defaultConstructor = (ReflectionUtils.HasDefaultConstructor(type, false)) ? ReflectionDelegateFactory.CreateDefaultConstructor(type) : null; @@ -248,7 +250,7 @@ private static Func GetCreator(Type type) return param.GetType(); }).ToArray(); - ConstructorInfo parameterizedConstructorInfo = type.GetConstructor(paramTypes); + ConstructorInfo? parameterizedConstructorInfo = type.GetConstructor(paramTypes); if (parameterizedConstructorInfo != null) { @@ -276,12 +278,12 @@ private static Func GetCreator(Type type) } #if !(NET20 || DOTNET) - private static Type GetAssociatedMetadataType(Type type) + private static Type? GetAssociatedMetadataType(Type type) { return AssociatedMetadataTypesCache.Get(type); } - private static Type GetAssociateMetadataTypeFromAttribute(Type type) + private static Type? GetAssociateMetadataTypeFromAttribute(Type type) { Attribute[] customAttributes = ReflectionUtils.GetAttributes(type, null, true); @@ -300,7 +302,7 @@ private static Type GetAssociateMetadataTypeFromAttribute(Type type) _metadataTypeAttributeReflectionObject = ReflectionObject.Create(attributeType, metadataClassTypeName); } - return (Type)_metadataTypeAttributeReflectionObject.GetValue(attribute, metadataClassTypeName); + return (Type?)_metadataTypeAttributeReflectionObject.GetValue(attribute, metadataClassTypeName); } } @@ -308,12 +310,12 @@ private static Type GetAssociateMetadataTypeFromAttribute(Type type) } #endif - private static T GetAttribute(Type type) where T : Attribute + private static T? GetAttribute(Type type) where T : Attribute { - T attribute; + T? attribute; #if !(NET20 || DOTNET) - Type metadataType = GetAssociatedMetadataType(type); + Type? metadataType = GetAssociatedMetadataType(type); if (metadataType != null) { attribute = ReflectionUtils.GetAttribute(metadataType, true); @@ -342,15 +344,15 @@ private static T GetAttribute(Type type) where T : Attribute return null; } - private static T GetAttribute(MemberInfo memberInfo) where T : Attribute + private static T? GetAttribute(MemberInfo memberInfo) where T : Attribute { - T attribute; + T? attribute; #if !(NET20 || DOTNET) - Type metadataType = GetAssociatedMetadataType(memberInfo.DeclaringType); + Type? metadataType = GetAssociatedMetadataType(memberInfo.DeclaringType!); if (metadataType != null) { - MemberInfo metadataTypeMemberInfo = ReflectionUtils.GetMemberInfoFromType(metadataType, memberInfo); + MemberInfo? metadataTypeMemberInfo = ReflectionUtils.GetMemberInfoFromType(metadataType, memberInfo); if (metadataTypeMemberInfo != null) { @@ -373,7 +375,7 @@ private static T GetAttribute(MemberInfo memberInfo) where T : Attribute { foreach (Type typeInterface in memberInfo.DeclaringType.GetInterfaces()) { - MemberInfo interfaceTypeMemberInfo = ReflectionUtils.GetMemberInfoFromType(typeInterface, memberInfo); + MemberInfo? interfaceTypeMemberInfo = ReflectionUtils.GetMemberInfoFromType(typeInterface, memberInfo); if (interfaceTypeMemberInfo != null) { @@ -423,7 +425,7 @@ public static bool IsSerializable(object provider) } #endif - public static T GetAttribute(object provider) where T : Attribute + public static T? GetAttribute(object provider) where T : Attribute { if (provider is Type type) { @@ -459,7 +461,9 @@ public static bool DynamicCodeGeneration { if (_dynamicCodeGeneration == null) { -#if HAVE_CAS +#if HAVE_DYNAMIC_CODE_COMPILED + _dynamicCodeGeneration = RuntimeFeature.IsDynamicCodeCompiled; +#elif HAVE_CAS try { new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Demand(); @@ -528,4 +532,5 @@ public static ReflectionDelegateFactory ReflectionDelegateFactory } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/KebabCaseNamingStrategy.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/KebabCaseNamingStrategy.cs new file mode 100644 index 0000000000..9730f81260 --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/KebabCaseNamingStrategy.cs @@ -0,0 +1,84 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using Microsoft.IdentityModel.Json.Utilities; + +namespace Microsoft.IdentityModel.Json.Serialization +{ + /// + /// A kebab case naming strategy. + /// + internal class KebabCaseNamingStrategy : NamingStrategy + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A flag indicating whether dictionary keys should be processed. + /// + /// + /// A flag indicating whether explicitly specified property names should be processed, + /// e.g. a property name customized with a . + /// + public KebabCaseNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames) + { + ProcessDictionaryKeys = processDictionaryKeys; + OverrideSpecifiedNames = overrideSpecifiedNames; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A flag indicating whether dictionary keys should be processed. + /// + /// + /// A flag indicating whether explicitly specified property names should be processed, + /// e.g. a property name customized with a . + /// + /// + /// A flag indicating whether extension data names should be processed. + /// + public KebabCaseNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames, bool processExtensionDataNames) + : this(processDictionaryKeys, overrideSpecifiedNames) + { + ProcessExtensionDataNames = processExtensionDataNames; + } + + /// + /// Initializes a new instance of the class. + /// + public KebabCaseNamingStrategy() + { + } + + /// + /// Resolves the specified property name. + /// + /// The property name to resolve. + /// The resolved property name. + protected override string ResolvePropertyName(string name) => StringUtils.ToKebabCase(name); + } +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/MemoryTraceWriter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/MemoryTraceWriter.cs index e20cf22fc3..560c3aeb2b 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/MemoryTraceWriter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/MemoryTraceWriter.cs @@ -6,6 +6,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Represents a trace writer that writes to memory. When the trace message limit is /// reached then old trace messages will be removed as new messages are added. @@ -41,7 +42,7 @@ public MemoryTraceWriter() /// The at which to write this trace. /// The trace message. /// The trace exception. This parameter is optional. - public void Trace(TraceLevel level, string message, Exception ex) + public void Trace(TraceLevel level, string message, Exception? ex) { StringBuilder sb = new StringBuilder(); sb.Append(DateTime.Now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff", CultureInfo.InvariantCulture)); @@ -97,4 +98,5 @@ public override string ToString() } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/NamingStrategy.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/NamingStrategy.cs index ea33c906c2..6e003ff832 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/NamingStrategy.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/NamingStrategy.cs @@ -25,6 +25,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// A base class for resolving how property names and dictionary keys are serialized. /// @@ -101,5 +102,47 @@ public virtual string GetDictionaryKey(string key) /// The property name to resolve. /// The resolved property name. protected abstract string ResolvePropertyName(string name); + + /// + /// Hash code calculation + /// + /// + public override int GetHashCode() + { + unchecked + { + var hashCode = GetType().GetHashCode(); // make sure different types do not result in equal values + hashCode = (hashCode * 397) ^ ProcessDictionaryKeys.GetHashCode(); + hashCode = (hashCode * 397) ^ ProcessExtensionDataNames.GetHashCode(); + hashCode = (hashCode * 397) ^ OverrideSpecifiedNames.GetHashCode(); + return hashCode; + } + } + + /// + /// Object equality implementation + /// + /// + /// + public override bool Equals(object? obj) => Equals(obj as NamingStrategy); + + /// + /// Compare to another NamingStrategy + /// + /// + /// + protected bool Equals(NamingStrategy? other) + { + if (other == null) + { + return false; + } + + return GetType() == other.GetType() && + ProcessDictionaryKeys == other.ProcessDictionaryKeys && + ProcessExtensionDataNames == other.ProcessExtensionDataNames && + OverrideSpecifiedNames == other.OverrideSpecifiedNames; + } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ObjectConstructor.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ObjectConstructor.cs index 4279a2223b..32d606a371 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ObjectConstructor.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ObjectConstructor.cs @@ -25,9 +25,11 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Represents a method that constructs an object. /// /// The object type to create. - internal delegate object ObjectConstructor(params object[] args); -} \ No newline at end of file + internal delegate object ObjectConstructor(params object?[] args); +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/OnErrorAttribute.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/OnErrorAttribute.cs index 5d02ee4830..ae2fe0ddf3 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/OnErrorAttribute.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/OnErrorAttribute.cs @@ -34,4 +34,4 @@ namespace Microsoft.IdentityModel.Json.Serialization internal sealed class OnErrorAttribute : Attribute { } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ReflectionAttributeProvider.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ReflectionAttributeProvider.cs index c662e47dc2..8200d5a2ad 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ReflectionAttributeProvider.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ReflectionAttributeProvider.cs @@ -68,4 +68,4 @@ public IList GetAttributes(Type attributeType, bool inherit) return ReflectionUtils.GetAttributes(_attributeProvider, attributeType, inherit); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ReflectionValueProvider.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ReflectionValueProvider.cs index 241d347a08..7b24289481 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ReflectionValueProvider.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/ReflectionValueProvider.cs @@ -30,6 +30,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable /// /// Get and set values for a using reflection. /// @@ -52,7 +53,7 @@ public ReflectionValueProvider(MemberInfo memberInfo) /// /// The target to set the value on. /// The value to set on the target. - public void SetValue(object target, object value) + public void SetValue(object target, object? value) { try { @@ -69,7 +70,7 @@ public void SetValue(object target, object value) /// /// The target to get the value from. /// The value. - public object GetValue(object target) + public object? GetValue(object target) { try { @@ -87,4 +88,5 @@ public object GetValue(object target) } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/SerializationBinderAdapter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/SerializationBinderAdapter.cs index 04318e76a3..3d7a2e9907 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/SerializationBinderAdapter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/SerializationBinderAdapter.cs @@ -28,6 +28,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable internal class SerializationBinderAdapter : ISerializationBinder { #pragma warning disable 618 @@ -41,12 +42,12 @@ public SerializationBinderAdapter(SerializationBinder serializationBinder) } #pragma warning restore 618 - public Type BindToType(string assemblyName, string typeName) + public Type BindToType(string? assemblyName, string typeName) { - return SerializationBinder.BindToType(assemblyName, typeName); + return SerializationBinder.BindToType(assemblyName!, typeName)!; } - public void BindToName(Type serializedType, out string assemblyName, out string typeName) + public void BindToName(Type serializedType, out string? assemblyName, out string? typeName) { #if HAVE_SERIALIZATION_BINDER_BIND_TO_NAME SerializationBinder.BindToName(serializedType, out assemblyName, out typeName); @@ -56,4 +57,5 @@ public void BindToName(Type serializedType, out string assemblyName, out string #endif } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/SnakeCaseNamingStrategy.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/SnakeCaseNamingStrategy.cs index a0726ef65d..90c8b55da3 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/SnakeCaseNamingStrategy.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/SnakeCaseNamingStrategy.cs @@ -84,4 +84,4 @@ protected override string ResolvePropertyName(string name) return StringUtils.ToSnakeCase(name); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/TraceJsonReader.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/TraceJsonReader.cs index 5ff194b787..e147fe3796 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/TraceJsonReader.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/TraceJsonReader.cs @@ -31,6 +31,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable internal class TraceJsonReader : JsonReader, IJsonLineInfo { private readonly JsonReader _innerReader; @@ -68,16 +69,16 @@ public override bool Read() return value; } - public override string ReadAsString() + public override string? ReadAsString() { - string value = _innerReader.ReadAsString(); + string? value = _innerReader.ReadAsString(); WriteCurrentToken(); return value; } - public override byte[] ReadAsBytes() + public override byte[]? ReadAsBytes() { - byte[] value = _innerReader.ReadAsBytes(); + byte[]? value = _innerReader.ReadAsBytes(); WriteCurrentToken(); return value; } @@ -136,9 +137,9 @@ public override char QuoteChar public override JsonToken TokenType => _innerReader.TokenType; - public override object Value => _innerReader.Value; + public override object? Value => _innerReader.Value; - public override Type ValueType => _innerReader.ValueType; + public override Type? ValueType => _innerReader.ValueType; public override void Close() { @@ -154,4 +155,5 @@ bool IJsonLineInfo.HasLineInfo() int IJsonLineInfo.LinePosition => (_innerReader is IJsonLineInfo lineInfo) ? lineInfo.LinePosition : 0; } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/TraceJsonWriter.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/TraceJsonWriter.cs index 1cbd8476ea..4aaa093110 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/TraceJsonWriter.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Serialization/TraceJsonWriter.cs @@ -32,6 +32,7 @@ namespace Microsoft.IdentityModel.Json.Serialization { +#nullable enable internal class TraceJsonWriter : JsonWriter { private readonly JsonWriter _innerWriter; @@ -144,7 +145,7 @@ public override void WriteValue(char? value) } } - public override void WriteValue(byte[] value) + public override void WriteValue(byte[]? value) { _textWriter.WriteValue(value); _innerWriter.WriteValue(value); @@ -321,7 +322,7 @@ public override void WriteValue(long? value) } } - public override void WriteValue(object value) + public override void WriteValue(object? value) { #if HAVE_BIG_INTEGER if (value is BigInteger) @@ -389,7 +390,7 @@ public override void WriteValue(short? value) } } - public override void WriteValue(string value) + public override void WriteValue(string? value) { _textWriter.WriteValue(value); _innerWriter.WriteValue(value); @@ -459,7 +460,7 @@ public override void WriteValue(ulong? value) } } - public override void WriteValue(Uri value) + public override void WriteValue(Uri? value) { _textWriter.WriteValue(value); _innerWriter.WriteValue(value); @@ -501,7 +502,7 @@ public override void WriteWhitespace(string ws) base.WriteWhitespace(ws); } - public override void WriteComment(string text) + public override void WriteComment(string? text) { _textWriter.WriteComment(text); _innerWriter.WriteComment(text); @@ -566,7 +567,7 @@ public override void WriteEndObject() base.WriteEndObject(); } - public override void WriteRawValue(string json) + public override void WriteRawValue(string? json) { _textWriter.WriteRawValue(json); _innerWriter.WriteRawValue(json); @@ -575,7 +576,7 @@ public override void WriteRawValue(string json) InternalWriteValue(JsonToken.Undefined); } - public override void WriteRaw(string json) + public override void WriteRaw(string? json) { _textWriter.WriteRaw(json); _innerWriter.WriteRaw(json); @@ -595,4 +596,5 @@ public override void Flush() _innerWriter.Flush(); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/SerializationBinder.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/SerializationBinder.cs index 62744685f8..61f6ec3b60 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/SerializationBinder.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/SerializationBinder.cs @@ -17,7 +17,7 @@ internal abstract class SerializationBinder /// Specifies the name of the serialized object. /// Specifies the name of the serialized object /// The type of the object the formatter creates a new instance of. - public abstract Type BindToType(string assemblyName, string typeName); + public abstract Type BindToType(string? assemblyName, string typeName); /// /// When overridden in a derived class, controls the binding of a serialized object to a type. @@ -25,7 +25,7 @@ internal abstract class SerializationBinder /// The type of the object the formatter creates a new instance of. /// Specifies the name of the serialized object. /// Specifies the name of the serialized object. - public virtual void BindToName(Type serializedType, out string assemblyName, out string typeName) + public virtual void BindToName(Type serializedType, out string? assemblyName, out string? typeName) { assemblyName = null; typeName = null; @@ -33,4 +33,4 @@ public virtual void BindToName(Type serializedType, out string assemblyName, out } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/StringEscapeHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/StringEscapeHandling.cs index e1adbdf189..8895785e11 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/StringEscapeHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/StringEscapeHandling.cs @@ -45,4 +45,4 @@ internal enum StringEscapeHandling /// EscapeHtml = 2 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/TraceLevel.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/TraceLevel.cs index 068fec52da..91ef45330a 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/TraceLevel.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/TraceLevel.cs @@ -36,4 +36,4 @@ internal enum TraceLevel } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/TypeNameAssemblyFormatHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/TypeNameAssemblyFormatHandling.cs index d87a4c3e90..9d430a51f6 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/TypeNameAssemblyFormatHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/TypeNameAssemblyFormatHandling.cs @@ -40,4 +40,4 @@ internal enum TypeNameAssemblyFormatHandling /// Full = 1 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/TypeNameHandling.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/TypeNameHandling.cs index dab3b0fa98..7e85fb14d8 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/TypeNameHandling.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/TypeNameHandling.cs @@ -67,4 +67,4 @@ internal enum TypeNameHandling /// Auto = 4 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/AsyncUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/AsyncUtils.cs index 756d863789..c8d49c0dbd 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/AsyncUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/AsyncUtils.cs @@ -32,6 +32,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal static class AsyncUtils { // Pre-allocate to avoid wasted allocations. @@ -40,33 +41,30 @@ internal static class AsyncUtils internal static Task ToAsync(this bool value) => value ? True : False; - public static Task CancelIfRequestedAsync(this CancellationToken cancellationToken) + public static Task? CancelIfRequestedAsync(this CancellationToken cancellationToken) { return cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : null; } - public static Task CancelIfRequestedAsync(this CancellationToken cancellationToken) + public static Task? CancelIfRequestedAsync(this CancellationToken cancellationToken) { return cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : null; } - // From 4.6 on we could use Task.FromCanceled(), but we need an equivalent for // previous frameworks. -#pragma warning disable UseAsyncSuffix // Use Async suffix public static Task FromCanceled(this CancellationToken cancellationToken) -#pragma warning restore UseAsyncSuffix // Use Async suffix { - Debug.Assert(cancellationToken.IsCancellationRequested); + MiscellaneousUtils.Assert(cancellationToken.IsCancellationRequested); return new Task(() => {}, cancellationToken); } -#pragma warning disable UseAsyncSuffix // Use Async suffix public static Task FromCanceled(this CancellationToken cancellationToken) -#pragma warning restore UseAsyncSuffix // Use Async suffix { - Debug.Assert(cancellationToken.IsCancellationRequested); + MiscellaneousUtils.Assert(cancellationToken.IsCancellationRequested); +#pragma warning disable CS8603 // Possible null reference return. return new Task(() => default, cancellationToken); +#pragma warning restore CS8603 // Possible null reference return. } // Task.Delay(0) is optimised as a cached task within the framework, and indeed @@ -76,38 +74,39 @@ public static Task FromCanceled(this CancellationToken cancellationToken) public static Task WriteAsync(this TextWriter writer, char value, CancellationToken cancellationToken) { - Debug.Assert(writer != null); + MiscellaneousUtils.Assert(writer != null); return cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : writer.WriteAsync(value); } - public static Task WriteAsync(this TextWriter writer, string value, CancellationToken cancellationToken) + public static Task WriteAsync(this TextWriter writer, string? value, CancellationToken cancellationToken) { - Debug.Assert(writer != null); + MiscellaneousUtils.Assert(writer != null); return cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : writer.WriteAsync(value); } public static Task WriteAsync(this TextWriter writer, char[] value, int start, int count, CancellationToken cancellationToken) { - Debug.Assert(writer != null); + MiscellaneousUtils.Assert(writer != null); return cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : writer.WriteAsync(value, start, count); } public static Task ReadAsync(this TextReader reader, char[] buffer, int index, int count, CancellationToken cancellationToken) { - Debug.Assert(reader != null); + MiscellaneousUtils.Assert(reader != null); return cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : reader.ReadAsync(buffer, index, count); } - public static bool IsCompletedSucessfully(this Task task) + public static bool IsCompletedSuccessfully(this Task task) { // IsCompletedSucessfully is the faster method, but only currently exposed on .NET Core 2.0 -#if NETCOREAPP2_0 - return task.IsCompletedSucessfully; +#if NETCOREAPP2_0_OR_GREATER + return task.IsCompletedSuccessfully; #else return task.Status == TaskStatus.RanToCompletion; #endif } } +#nullable disable } #endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/Base64Encoder.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/Base64Encoder.cs index 84c899266f..a932432b64 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/Base64Encoder.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/Base64Encoder.cs @@ -32,6 +32,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal class Base64Encoder { private const int Base64LineSize = 76; @@ -40,7 +41,7 @@ internal class Base64Encoder private readonly char[] _charsLine = new char[Base64LineSize]; private readonly TextWriter _writer; - private byte[] _leftOverBytes; + private byte[]? _leftOverBytes; private int _leftOverBytesCount; public Base64Encoder(TextWriter writer) @@ -78,12 +79,12 @@ public void Encode(byte[] buffer, int index, int count) if (_leftOverBytesCount > 0) { - if(FulfillFromLeftover(buffer, index, ref count)) + if (FulfillFromLeftover(buffer, index, ref count)) { return; } - int num2 = Convert.ToBase64CharArray(_leftOverBytes, 0, 3, _charsLine, 0); + int num2 = Convert.ToBase64CharArray(_leftOverBytes!, 0, 3, _charsLine, 0); WriteChars(_charsLine, 0, num2); } @@ -128,7 +129,7 @@ private bool FulfillFromLeftover(byte[] buffer, int index, ref int count) int leftOverBytesCount = _leftOverBytesCount; while (leftOverBytesCount < 3 && count > 0) { - _leftOverBytes[leftOverBytesCount++] = buffer[index++]; + _leftOverBytes![leftOverBytesCount++] = buffer[index++]; count--; } @@ -145,7 +146,7 @@ public void Flush() { if (_leftOverBytesCount > 0) { - int count = Convert.ToBase64CharArray(_leftOverBytes, 0, _leftOverBytesCount, _charsLine, 0); + int count = Convert.ToBase64CharArray(_leftOverBytes!, 0, _leftOverBytesCount, _charsLine, 0); WriteChars(_charsLine, 0, count); _leftOverBytesCount = 0; } @@ -169,7 +170,7 @@ public async Task EncodeAsync(byte[] buffer, int index, int count, CancellationT return; } - int num2 = Convert.ToBase64CharArray(_leftOverBytes, 0, 3, _charsLine, 0); + int num2 = Convert.ToBase64CharArray(_leftOverBytes!, 0, 3, _charsLine, 0); await WriteCharsAsync(_charsLine, 0, num2, cancellationToken).ConfigureAwait(false); } @@ -203,7 +204,7 @@ public Task FlushAsync(CancellationToken cancellationToken) if (_leftOverBytesCount > 0) { - int count = Convert.ToBase64CharArray(_leftOverBytes, 0, _leftOverBytesCount, _charsLine, 0); + int count = Convert.ToBase64CharArray(_leftOverBytes!, 0, _leftOverBytesCount, _charsLine, 0); _leftOverBytesCount = 0; return WriteCharsAsync(_charsLine, 0, count, cancellationToken); } @@ -214,4 +215,5 @@ public Task FlushAsync(CancellationToken cancellationToken) #endif } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/BidirectionalDictionary.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/BidirectionalDictionary.cs index e06ff12152..47d92b7077 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/BidirectionalDictionary.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/BidirectionalDictionary.cs @@ -25,11 +25,15 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal class BidirectionalDictionary + where TFirst : notnull + where TSecond : notnull { private readonly IDictionary _firstToSecond; private readonly IDictionary _secondToFirst; @@ -61,17 +65,17 @@ public BidirectionalDictionary(IEqualityComparer firstEqualityComparer, public void Set(TFirst first, TSecond second) { - if (_firstToSecond.TryGetValue(first, out TSecond existingSecond)) + if (_firstToSecond.TryGetValue(first, out TSecond? existingSecond)) { - if (!existingSecond.Equals(second)) + if (!existingSecond!.Equals(second)) { throw new ArgumentException(_duplicateFirstErrorMessage.FormatWith(CultureInfo.InvariantCulture, first)); } } - if (_secondToFirst.TryGetValue(second, out TFirst existingFirst)) + if (_secondToFirst.TryGetValue(second, out TFirst? existingFirst)) { - if (!existingFirst.Equals(first)) + if (!existingFirst!.Equals(first)) { throw new ArgumentException(_duplicateSecondErrorMessage.FormatWith(CultureInfo.InvariantCulture, second)); } @@ -81,14 +85,15 @@ public void Set(TFirst first, TSecond second) _secondToFirst.Add(second, first); } - public bool TryGetByFirst(TFirst first, out TSecond second) + public bool TryGetByFirst(TFirst first, [NotNullWhen(true)] out TSecond? second) { return _firstToSecond.TryGetValue(first, out second); } - public bool TryGetBySecond(TSecond second, out TFirst first) + public bool TryGetBySecond(TSecond second, [NotNullWhen(true)] out TFirst? first) { return _secondToFirst.TryGetValue(second, out first); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/BoxedPrimitives.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/BoxedPrimitives.cs new file mode 100644 index 0000000000..7ccb6f2c8b --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/BoxedPrimitives.cs @@ -0,0 +1,116 @@ +#region License +// Copyright (c) 2022 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Microsoft.IdentityModel.Json.Utilities +{ + internal static class BoxedPrimitives + { + internal static object Get(bool value) => value ? BooleanTrue : BooleanFalse; + + internal static readonly object BooleanTrue = true; + internal static readonly object BooleanFalse = false; + + internal static object Get(int value) => value switch + { + -1 => Int32_M1, + 0 => Int32_0, + 1 => Int32_1, + 2 => Int32_2, + 3 => Int32_3, + 4 => Int32_4, + 5 => Int32_5, + 6 => Int32_6, + 7 => Int32_7, + 8 => Int32_8, + _ => value, + }; + + // integers tend to be weighted towards a handful of low numbers; we could argue + // for days over the "correct" range to have special handling, but I'm arbitrarily + // mirroring the same decision as the IL opcodes, which has M1 thru 8 + internal static readonly object Int32_M1 = -1; + internal static readonly object Int32_0 = 0; + internal static readonly object Int32_1 = 1; + internal static readonly object Int32_2 = 2; + internal static readonly object Int32_3 = 3; + internal static readonly object Int32_4 = 4; + internal static readonly object Int32_5 = 5; + internal static readonly object Int32_6 = 6; + internal static readonly object Int32_7 = 7; + internal static readonly object Int32_8 = 8; + + internal static object Get(long value) => value switch + { + -1 => Int64_M1, + 0 => Int64_0, + 1 => Int64_1, + 2 => Int64_2, + 3 => Int64_3, + 4 => Int64_4, + 5 => Int64_5, + 6 => Int64_6, + 7 => Int64_7, + 8 => Int64_8, + _ => value, + }; + + internal static readonly object Int64_M1 = -1L; + internal static readonly object Int64_0 = 0L; + internal static readonly object Int64_1 = 1L; + internal static readonly object Int64_2 = 2L; + internal static readonly object Int64_3 = 3L; + internal static readonly object Int64_4 = 4L; + internal static readonly object Int64_5 = 5L; + internal static readonly object Int64_6 = 6L; + internal static readonly object Int64_7 = 7L; + internal static readonly object Int64_8 = 8L; + + internal static object Get(decimal value) => value == decimal.Zero ? DecimalZero : value; + + private static readonly object DecimalZero = decimal.Zero; + + internal static object Get(double value) + { + if (value == 0.0d) + { + return DoubleZero; + } + if (double.IsInfinity(value)) + { + return double.IsPositiveInfinity(value) ? DoublePositiveInfinity : DoubleNegativeInfinity; + } + if (double.IsNaN(value)) + { + return DoubleNaN; + } + return value; + } + + internal static readonly object DoubleNaN = double.NaN; + internal static readonly object DoublePositiveInfinity = double.PositiveInfinity; + internal static readonly object DoubleNegativeInfinity = double.NegativeInfinity; + internal static readonly object DoubleZero = (double)0; + } +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/CollectionUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/CollectionUtils.cs index c07a0338f2..f3c7eca167 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/CollectionUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/CollectionUtils.cs @@ -43,6 +43,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal static class CollectionUtils { /// @@ -116,17 +117,17 @@ public static bool IsDictionaryType(Type type) return false; } - public static ConstructorInfo ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType) + public static ConstructorInfo? ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType) { Type genericConstructorArgument = typeof(IList<>).MakeGenericType(collectionItemType); return ResolveEnumerableCollectionConstructor(collectionType, collectionItemType, genericConstructorArgument); } - public static ConstructorInfo ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType, Type constructorArgumentType) + public static ConstructorInfo? ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType, Type constructorArgumentType) { Type genericEnumerable = typeof(IEnumerable<>).MakeGenericType(collectionItemType); - ConstructorInfo match = null; + ConstructorInfo? match = null; foreach (ConstructorInfo constructor in collectionType.GetConstructors(BindingFlags.Public | BindingFlags.Instance)) { @@ -248,11 +249,12 @@ public static int IndexOfReference(this List list, T item) return i; } } + return -1; } #if HAVE_FAST_REVERSE - // faster reverse in .NET Framework with value types - https://github.com/JamesNK/Microsoft.IdentityModel.Json/issues/1430 + // faster reverse in .NET Framework with value types - https://github.com/JamesNK/Newtonsoft.Json/issues/1430 public static void FastReverse(this List list) { int i = 0; @@ -288,7 +290,7 @@ private static IList GetDimensions(IList values, int dimensionsCount) break; } - object v = currentArray[0]; + object? v = currentArray[0]; if (v is IList list) { currentArray = list; @@ -316,9 +318,7 @@ private static void CopyFromJaggedToMultidimensionalArray(IList values, Array mu int currentValuesLength = list.Count; if (currentValuesLength != dimensionLength) { -#pragma warning disable CA2201 // Do not raise reserved exception types throw new Exception("Cannot deserialize non-cubical array as multidimensional array."); -#pragma warning restore CA2201 // Do not raise reserved exception types } int[] newIndices = new int[dimension + 1]; @@ -342,11 +342,11 @@ private static object JaggedArrayGetValue(IList values, int[] indices) int index = indices[i]; if (i == indices.Length - 1) { - return currentList[index]; + return currentList[index]!; } else { - currentList = (IList)currentList[index]; + currentList = (IList)currentList[index]!; } } return currentList; @@ -367,25 +367,24 @@ public static Array ToMultidimensionalArray(IList values, Type type, int rank) return multidimensionalArray; } - // 4.6 has Array.Empty to return a cached empty array. Lacking that in other - // frameworks, Enumerable.Empty happens to be implemented as a cached empty - // array in all versions (in .NET Core the same instance as Array.Empty). - // This includes the internal Linq bridge for 2.0. - // Since this method is simple and only 11 bytes long in a release build it's - // pretty much guaranteed to be inlined, giving us fast access of that cached - // array. With 4.5 and up we use AggressiveInlining just to be sure, so it's - // effectively the same as calling Array.Empty even when not available. -#if HAVE_METHOD_IMPL_ATTRIBUTE - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif public static T[] ArrayEmpty() { - T[] array = Enumerable.Empty() as T[]; - Debug.Assert(array != null); - // Defensively guard against a version of Linq where Enumerable.Empty doesn't - // return an array, but throw in debug versions so a better strategy can be - // used if that ever happens. - return array ?? new T[0]; +#if !HAS_ARRAY_EMPTY + // Enumerable.Empty no longer returns an empty array in .NET Core 3.0 + return EmptyArrayContainer.Empty; +#else + return Array.Empty(); +#endif } + +#if !HAS_ARRAY_EMPTY + private static class EmptyArrayContainer + { +#pragma warning disable CA1825 // Avoid zero-length array allocations. + public static readonly T[] Empty = new T[0]; +#pragma warning restore CA1825 // Avoid zero-length array allocations. + } +#endif } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/CollectionWrapper.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/CollectionWrapper.cs index 697909f337..274a7cdb69 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/CollectionWrapper.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/CollectionWrapper.cs @@ -37,6 +37,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal interface IWrappedCollection : IList { object UnderlyingCollection { get; } @@ -44,9 +45,9 @@ internal interface IWrappedCollection : IList internal class CollectionWrapper : ICollection, IWrappedCollection { - private readonly IList _list; - private readonly ICollection _genericCollection; - private object _syncRoot; + private readonly IList? _list; + private readonly ICollection? _genericCollection; + private object? _syncRoot; public CollectionWrapper(IList list) { @@ -77,7 +78,7 @@ public virtual void Add(T item) } else { - _list.Add(item); + _list!.Add(item); } } @@ -89,7 +90,7 @@ public virtual void Clear() } else { - _list.Clear(); + _list!.Clear(); } } @@ -101,7 +102,7 @@ public virtual bool Contains(T item) } else { - return _list.Contains(item); + return _list!.Contains(item); } } @@ -113,7 +114,7 @@ public virtual void CopyTo(T[] array, int arrayIndex) } else { - _list.CopyTo(array, arrayIndex); + _list!.CopyTo(array, arrayIndex); } } @@ -127,7 +128,7 @@ public virtual int Count } else { - return _list.Count; + return _list!.Count; } } } @@ -142,7 +143,7 @@ public virtual bool IsReadOnly } else { - return _list.IsReadOnly; + return _list!.IsReadOnly; } } } @@ -155,11 +156,11 @@ public virtual bool Remove(T item) } else { - bool contains = _list.Contains(item); + bool contains = _list!.Contains(item); if (contains) { - _list.Remove(item); + _list!.Remove(item); } return contains; @@ -168,33 +169,33 @@ public virtual bool Remove(T item) public virtual IEnumerator GetEnumerator() { - return (_genericCollection ?? _list.Cast()).GetEnumerator(); + return (_genericCollection ?? _list!.Cast()).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { - return ((IEnumerable)_genericCollection ?? _list).GetEnumerator(); + return ((IEnumerable)_genericCollection! ?? _list!).GetEnumerator(); } - int IList.Add(object value) + int IList.Add(object? value) { VerifyValueType(value); - Add((T)value); + Add((T)value!); return (Count - 1); } - bool IList.Contains(object value) + bool IList.Contains(object? value) { if (IsCompatibleObject(value)) { - return Contains((T)value); + return Contains((T)value!); } return false; } - int IList.IndexOf(object value) + int IList.IndexOf(object? value) { if (_genericCollection != null) { @@ -203,7 +204,7 @@ int IList.IndexOf(object value) if (IsCompatibleObject(value)) { - return _list.IndexOf((T)value); + return _list!.IndexOf((T)value!); } return -1; @@ -216,10 +217,10 @@ void IList.RemoveAt(int index) throw new InvalidOperationException("Wrapped ICollection does not support RemoveAt."); } - _list.RemoveAt(index); + _list!.RemoveAt(index); } - void IList.Insert(int index, object value) + void IList.Insert(int index, object? value) { if (_genericCollection != null) { @@ -227,7 +228,7 @@ void IList.Insert(int index, object value) } VerifyValueType(value); - _list.Insert(index, (T)value); + _list!.Insert(index, (T)value!); } bool IList.IsFixedSize @@ -241,20 +242,20 @@ bool IList.IsFixedSize } else { - return _list.IsFixedSize; + return _list!.IsFixedSize; } } } - void IList.Remove(object value) + void IList.Remove(object? value) { if (IsCompatibleObject(value)) { - Remove((T)value); + Remove((T)value!); } } - object IList.this[int index] + object? IList.this[int index] { get { @@ -263,7 +264,7 @@ object IList.this[int index] throw new InvalidOperationException("Wrapped ICollection does not support indexer."); } - return _list[index]; + return _list![index]; } set { @@ -273,7 +274,7 @@ object IList.this[int index] } VerifyValueType(value); - _list[index] = (T)value; + _list![index] = (T?)value; } } @@ -297,7 +298,7 @@ object ICollection.SyncRoot } } - private static void VerifyValueType(object value) + private static void VerifyValueType(object? value) { if (!IsCompatibleObject(value)) { @@ -305,7 +306,7 @@ private static void VerifyValueType(object value) } } - private static bool IsCompatibleObject(object value) + private static bool IsCompatibleObject(object? value) { if (!(value is T) && (value != null || (typeof(T).IsValueType() && !ReflectionUtils.IsNullableType(typeof(T))))) { @@ -315,6 +316,7 @@ private static bool IsCompatibleObject(object value) return true; } - public object UnderlyingCollection => (object)_genericCollection ?? _list; + public object UnderlyingCollection => (object)_genericCollection! ?? _list!; } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ConvertUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ConvertUtils.cs index 59e6cbdbd5..e7d04d4dcd 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ConvertUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ConvertUtils.cs @@ -27,6 +27,7 @@ using System.Collections.Generic; using System.Globalization; using System.ComponentModel; +using System.Runtime.CompilerServices; #if HAVE_BIG_INTEGER using System.Numerics; #endif @@ -36,6 +37,7 @@ #endif using Microsoft.IdentityModel.Json.Serialization; using System.Reflection; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #endif @@ -46,6 +48,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal enum PrimitiveTypeCode { Empty = 0, @@ -94,8 +97,14 @@ internal enum PrimitiveTypeCode internal class TypeInformation { - public Type Type { get; set; } - public PrimitiveTypeCode TypeCode { get; set; } + public Type Type { get; } + public PrimitiveTypeCode TypeCode { get; } + + public TypeInformation(Type type, PrimitiveTypeCode typeCode) + { + Type = type; + TypeCode = typeCode; + } } internal enum ParseResult @@ -163,25 +172,25 @@ internal static class ConvertUtils private static readonly TypeInformation[] PrimitiveTypeCodes = { // need all of these. lookup against the index with TypeCode value - new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Empty }, - new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Object }, - new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.DBNull }, - new TypeInformation { Type = typeof(bool), TypeCode = PrimitiveTypeCode.Boolean }, - new TypeInformation { Type = typeof(char), TypeCode = PrimitiveTypeCode.Char }, - new TypeInformation { Type = typeof(sbyte), TypeCode = PrimitiveTypeCode.SByte }, - new TypeInformation { Type = typeof(byte), TypeCode = PrimitiveTypeCode.Byte }, - new TypeInformation { Type = typeof(short), TypeCode = PrimitiveTypeCode.Int16 }, - new TypeInformation { Type = typeof(ushort), TypeCode = PrimitiveTypeCode.UInt16 }, - new TypeInformation { Type = typeof(int), TypeCode = PrimitiveTypeCode.Int32 }, - new TypeInformation { Type = typeof(uint), TypeCode = PrimitiveTypeCode.UInt32 }, - new TypeInformation { Type = typeof(long), TypeCode = PrimitiveTypeCode.Int64 }, - new TypeInformation { Type = typeof(ulong), TypeCode = PrimitiveTypeCode.UInt64 }, - new TypeInformation { Type = typeof(float), TypeCode = PrimitiveTypeCode.Single }, - new TypeInformation { Type = typeof(double), TypeCode = PrimitiveTypeCode.Double }, - new TypeInformation { Type = typeof(decimal), TypeCode = PrimitiveTypeCode.Decimal }, - new TypeInformation { Type = typeof(DateTime), TypeCode = PrimitiveTypeCode.DateTime }, - new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Empty }, // no 17 in TypeCode for some reason - new TypeInformation { Type = typeof(string), TypeCode = PrimitiveTypeCode.String } + new TypeInformation(typeof(object), PrimitiveTypeCode.Empty), + new TypeInformation(typeof(object), PrimitiveTypeCode.Object), + new TypeInformation(typeof(object), PrimitiveTypeCode.DBNull), + new TypeInformation(typeof(bool), PrimitiveTypeCode.Boolean), + new TypeInformation(typeof(char), PrimitiveTypeCode.Char), + new TypeInformation(typeof(sbyte), PrimitiveTypeCode.SByte), + new TypeInformation(typeof(byte), PrimitiveTypeCode.Byte), + new TypeInformation(typeof(short), PrimitiveTypeCode.Int16), + new TypeInformation(typeof(ushort), PrimitiveTypeCode.UInt16), + new TypeInformation(typeof(int), PrimitiveTypeCode.Int32), + new TypeInformation(typeof(uint), PrimitiveTypeCode.UInt32), + new TypeInformation(typeof(long), PrimitiveTypeCode.Int64), + new TypeInformation(typeof(ulong), PrimitiveTypeCode.UInt64), + new TypeInformation(typeof(float), PrimitiveTypeCode.Single), + new TypeInformation(typeof(double), PrimitiveTypeCode.Double), + new TypeInformation(typeof(decimal), PrimitiveTypeCode.Decimal), + new TypeInformation(typeof(DateTime), PrimitiveTypeCode.DateTime), + new TypeInformation(typeof(object), PrimitiveTypeCode.Empty), // no 17 in TypeCode for some reason + new TypeInformation(typeof(string), PrimitiveTypeCode.String) }; #endif @@ -207,7 +216,7 @@ public static PrimitiveTypeCode GetTypeCode(Type t, out bool isEnum) // performance? if (ReflectionUtils.IsNullableType(t)) { - Type nonNullable = Nullable.GetUnderlyingType(t); + Type nonNullable = Nullable.GetUnderlyingType(t)!; if (nonNullable.IsEnum()) { Type nullableUnderlyingType = typeof(Nullable<>).MakeGenericType(Enum.GetUnderlyingType(nonNullable)); @@ -248,14 +257,14 @@ public static TimeSpan ParseTimeSpan(string input) #endif } - private static readonly ThreadSafeStore, Func> CastConverters = - new ThreadSafeStore, Func>(CreateCastConverter); + private static readonly ThreadSafeStore, Func?> CastConverters = + new ThreadSafeStore, Func?>(CreateCastConverter); - private static Func CreateCastConverter(StructMultiKey t) + private static Func? CreateCastConverter(StructMultiKey t) { Type initialType = t.Value1; Type targetType = t.Value2; - MethodInfo castMethodInfo = targetType.GetMethod("op_Implicit", new[] { initialType }) + MethodInfo? castMethodInfo = targetType.GetMethod("op_Implicit", new[] { initialType }) ?? targetType.GetMethod("op_Explicit", new[] { initialType }); if (castMethodInfo == null) @@ -263,7 +272,7 @@ private static Func CreateCastConverter(StructMultiKey call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(castMethodInfo); + MethodCall call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(castMethodInfo); return o => call(null, o); } @@ -363,14 +372,12 @@ internal enum ConvertResult public static object Convert(object initialValue, CultureInfo culture, Type targetType) { - switch (TryConvertInternal(initialValue, culture, targetType, out object value)) + switch (TryConvertInternal(initialValue, culture, targetType, out object? value)) { case ConvertResult.Success: - return value; + return value!; case ConvertResult.CannotConvertNull: -#pragma warning disable CA2201 // Do not raise reserved exception types throw new Exception("Can not convert null {0} into non-nullable {1}.".FormatWith(CultureInfo.InvariantCulture, initialValue.GetType(), targetType)); -#pragma warning restore CA2201 // Do not raise reserved exception types case ConvertResult.NotInstantiableType: throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), nameof(targetType)); case ConvertResult.NoValidConversion: @@ -380,7 +387,7 @@ public static object Convert(object initialValue, CultureInfo culture, Type targ } } - private static bool TryConvert(object initialValue, CultureInfo culture, Type targetType, out object value) + private static bool TryConvert(object? initialValue, CultureInfo culture, Type targetType, out object? value) { try { @@ -399,7 +406,7 @@ private static bool TryConvert(object initialValue, CultureInfo culture, Type ta } } - private static ConvertResult TryConvertInternal(object initialValue, CultureInfo culture, Type targetType, out object value) + private static ConvertResult TryConvertInternal(object? initialValue, CultureInfo culture, Type targetType, out object? value) { if (initialValue == null) { @@ -408,7 +415,7 @@ private static ConvertResult TryConvertInternal(object initialValue, CultureInfo if (ReflectionUtils.IsNullableType(targetType)) { - targetType = Nullable.GetUnderlyingType(targetType); + targetType = Nullable.GetUnderlyingType(targetType)!; } Type initialType = initialValue.GetType(); @@ -426,7 +433,7 @@ private static ConvertResult TryConvertInternal(object initialValue, CultureInfo { if (initialValue is string) { - value = Enum.Parse(targetType, initialValue.ToString(), true); + value = Enum.Parse(targetType, initialValue.ToString()!, true); return ConvertResult.Success; } else if (IsInteger(initialValue)) @@ -484,7 +491,7 @@ private static ConvertResult TryConvertInternal(object initialValue, CultureInfo } if (targetType == typeof(Version)) { - if (VersionTryParse(s, out Version result)) + if (VersionTryParse(s, out Version? result)) { value = result; return ConvertResult.Success; @@ -497,6 +504,18 @@ private static ConvertResult TryConvertInternal(object initialValue, CultureInfo value = Type.GetType(s, true); return ConvertResult.Success; } +#if HAVE_DATE_ONLY + if (targetType == typeof(DateOnly)) + { + value = DateOnly.ParseExact(s, "yyyy'-'MM'-'dd", CultureInfo.InvariantCulture); + return ConvertResult.Success; + } + if (targetType == typeof(TimeOnly)) + { + value = TimeOnly.ParseExact(s, "HH':'mm':'ss.FFFFFFF", CultureInfo.InvariantCulture); + return ConvertResult.Success; + } +#endif } #if HAVE_BIG_INTEGER @@ -569,7 +588,7 @@ private static ConvertResult TryConvertInternal(object initialValue, CultureInfo /// The converted type. If conversion was unsuccessful, the initial value /// is returned if assignable to the target type. /// - public static object ConvertOrCast(object initialValue, CultureInfo culture, Type targetType) + public static object? ConvertOrCast(object? initialValue, CultureInfo culture, Type targetType) { if (targetType == typeof(object)) { @@ -581,27 +600,27 @@ public static object ConvertOrCast(object initialValue, CultureInfo culture, Typ return null; } - if (TryConvert(initialValue, culture, targetType, out object convertedValue)) + if (TryConvert(initialValue, culture, targetType, out object? convertedValue)) { return convertedValue; } - return EnsureTypeAssignable(initialValue, ReflectionUtils.GetObjectType(initialValue), targetType); + return EnsureTypeAssignable(initialValue, ReflectionUtils.GetObjectType(initialValue)!, targetType); } #endregion - private static object EnsureTypeAssignable(object value, Type initialType, Type targetType) + private static object? EnsureTypeAssignable(object? value, Type initialType, Type targetType) { - Type valueType = value?.GetType(); - if (value != null) { + Type valueType = value.GetType(); + if (targetType.IsAssignableFrom(valueType)) { return value; } - Func castConverter = CastConverters.Get(new StructMultiKey(valueType, targetType)); + Func? castConverter = CastConverters.Get(new StructMultiKey(valueType, targetType)); if (castConverter != null) { return castConverter(value); @@ -618,7 +637,7 @@ private static object EnsureTypeAssignable(object value, Type initialType, Type throw new ArgumentException("Could not cast or convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, initialType?.ToString() ?? "{null}", targetType)); } - public static bool VersionTryParse(string input, out Version result) + public static bool VersionTryParse(string input, [NotNullWhen(true)]out Version? result) { #if HAVE_VERSION_TRY_PARSE return Version.TryParse(input, out result); @@ -1568,4 +1587,5 @@ public static bool TryHexTextToInt(char[] text, int start, int end, out int valu return true; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DateTimeUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DateTimeUtils.cs index 346f17da5d..585d15706f 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DateTimeUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DateTimeUtils.cs @@ -30,6 +30,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal static class DateTimeUtils { internal static readonly long InitialJavaScriptDateTicks = 621355968000000000; @@ -179,9 +180,9 @@ private static long ToUniversalTicks(DateTime dateTime, TimeSpan offset) internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime, TimeSpan offset) { - long universialTicks = ToUniversalTicks(dateTime, offset); + long universalTicks = ToUniversalTicks(dateTime, offset); - return UniversialTicksToJavaScriptTicks(universialTicks); + return UniversalTicksToJavaScriptTicks(universalTicks); } internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime) @@ -193,12 +194,12 @@ internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime, bool co { long ticks = (convertToUtc) ? ToUniversalTicks(dateTime) : dateTime.Ticks; - return UniversialTicksToJavaScriptTicks(ticks); + return UniversalTicksToJavaScriptTicks(ticks); } - private static long UniversialTicksToJavaScriptTicks(long universialTicks) + private static long UniversalTicksToJavaScriptTicks(long universalTicks) { - long javaScriptTicks = (universialTicks - InitialJavaScriptDateTicks) / 10000; + long javaScriptTicks = (universalTicks - InitialJavaScriptDateTicks) / 10000; return javaScriptTicks; } @@ -341,7 +342,7 @@ private static DateTime CreateDateTime(DateTimeParser dateTimeParser) return d; } - internal static bool TryParseDateTime(StringReference s, DateTimeZoneHandling dateTimeZoneHandling, string dateFormatString, CultureInfo culture, out DateTime dt) + internal static bool TryParseDateTime(StringReference s, DateTimeZoneHandling dateTimeZoneHandling, string? dateFormatString, CultureInfo culture, out DateTime dt) { if (s.Length > 0) { @@ -364,7 +365,7 @@ internal static bool TryParseDateTime(StringReference s, DateTimeZoneHandling da } } - if (!string.IsNullOrEmpty(dateFormatString)) + if (!StringUtils.IsNullOrEmpty(dateFormatString)) { if (TryParseDateTimeExact(s.ToString(), dateTimeZoneHandling, dateFormatString, culture, out dt)) { @@ -377,7 +378,7 @@ internal static bool TryParseDateTime(StringReference s, DateTimeZoneHandling da return false; } - internal static bool TryParseDateTime(string s, DateTimeZoneHandling dateTimeZoneHandling, string dateFormatString, CultureInfo culture, out DateTime dt) + internal static bool TryParseDateTime(string s, DateTimeZoneHandling dateTimeZoneHandling, string? dateFormatString, CultureInfo culture, out DateTime dt) { if (s.Length > 0) { @@ -400,7 +401,7 @@ internal static bool TryParseDateTime(string s, DateTimeZoneHandling dateTimeZon } } - if (!string.IsNullOrEmpty(dateFormatString)) + if (!StringUtils.IsNullOrEmpty(dateFormatString)) { if (TryParseDateTimeExact(s, dateTimeZoneHandling, dateFormatString, culture, out dt)) { @@ -414,7 +415,7 @@ internal static bool TryParseDateTime(string s, DateTimeZoneHandling dateTimeZon } #if HAVE_DATE_TIME_OFFSET - internal static bool TryParseDateTimeOffset(StringReference s, string dateFormatString, CultureInfo culture, out DateTimeOffset dt) + internal static bool TryParseDateTimeOffset(StringReference s, string? dateFormatString, CultureInfo culture, out DateTimeOffset dt) { if (s.Length > 0) { @@ -437,7 +438,7 @@ internal static bool TryParseDateTimeOffset(StringReference s, string dateFormat } } - if (!string.IsNullOrEmpty(dateFormatString)) + if (!StringUtils.IsNullOrEmpty(dateFormatString)) { if (TryParseDateTimeOffsetExact(s.ToString(), dateFormatString, culture, out dt)) { @@ -450,7 +451,7 @@ internal static bool TryParseDateTimeOffset(StringReference s, string dateFormat return false; } - internal static bool TryParseDateTimeOffset(string s, string dateFormatString, CultureInfo culture, out DateTimeOffset dt) + internal static bool TryParseDateTimeOffset(string s, string? dateFormatString, CultureInfo culture, out DateTimeOffset dt) { if (s.Length > 0) { @@ -475,7 +476,7 @@ internal static bool TryParseDateTimeOffset(string s, string dateFormatString, C } } - if (!string.IsNullOrEmpty(dateFormatString)) + if (!StringUtils.IsNullOrEmpty(dateFormatString)) { if (TryParseDateTimeOffsetExact(s, dateFormatString, culture, out dt)) { @@ -618,9 +619,9 @@ private static bool TryReadOffset(StringReference offsetText, int startIndex, ou #endregion #region Write - internal static void WriteDateTimeString(TextWriter writer, DateTime value, DateFormatHandling format, string formatString, CultureInfo culture) + internal static void WriteDateTimeString(TextWriter writer, DateTime value, DateFormatHandling format, string? formatString, CultureInfo culture) { - if (string.IsNullOrEmpty(formatString)) + if (StringUtils.IsNullOrEmpty(formatString)) { char[] chars = new char[64]; int pos = WriteDateTimeString(chars, 0, value, null, value.Kind, format); @@ -751,9 +752,9 @@ internal static int WriteDateTimeOffset(char[] chars, int start, TimeSpan offset } #if HAVE_DATE_TIME_OFFSET - internal static void WriteDateTimeOffsetString(TextWriter writer, DateTimeOffset value, DateFormatHandling format, string formatString, CultureInfo culture) + internal static void WriteDateTimeOffsetString(TextWriter writer, DateTimeOffset value, DateFormatHandling format, string? formatString, CultureInfo culture) { - if (string.IsNullOrEmpty(formatString)) + if (StringUtils.IsNullOrEmpty(formatString)) { char[] chars = new char[64]; int pos = WriteDateTimeString(chars, 0, (format == DateFormatHandling.IsoDateFormat) ? value.DateTime : value.UtcDateTime, value.Offset, DateTimeKind.Local, format); @@ -821,5 +822,6 @@ private static void GetDateValues(DateTime td, out int year, out int month, out // Return 1-based day-of-month day = n - days[m - 1] + 1; } +#nullable disable } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DictionaryWrapper.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DictionaryWrapper.cs index 82cb82bb80..28fc895469 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DictionaryWrapper.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DictionaryWrapper.cs @@ -27,15 +27,18 @@ using System.Collections.Generic; using System.Collections; using System.Threading; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else using System.Linq; - #endif namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal interface IWrappedDictionary : IDictionary { @@ -44,12 +47,12 @@ internal interface IWrappedDictionary internal class DictionaryWrapper : IDictionary, IWrappedDictionary { - private readonly IDictionary _dictionary; - private readonly IDictionary _genericDictionary; + private readonly IDictionary? _dictionary; + private readonly IDictionary? _genericDictionary; #if HAVE_READ_ONLY_COLLECTIONS - private readonly IReadOnlyDictionary _readOnlyDictionary; + private readonly IReadOnlyDictionary? _readOnlyDictionary; #endif - private object _syncRoot; + private object? _syncRoot; public DictionaryWrapper(IDictionary dictionary) { @@ -74,11 +77,20 @@ public DictionaryWrapper(IReadOnlyDictionary dictionary) } #endif + internal IDictionary GenericDictionary + { + get + { + MiscellaneousUtils.Assert(_genericDictionary != null); + return _genericDictionary; + } + } + public void Add(TKey key, TValue value) { if (_dictionary != null) { - _dictionary.Add(key, value); + _dictionary.Add(key!, value); } else if (_genericDictionary != null) { @@ -94,7 +106,7 @@ public bool ContainsKey(TKey key) { if (_dictionary != null) { - return _dictionary.Contains(key); + return _dictionary.Contains(key!); } #if HAVE_READ_ONLY_COLLECTIONS else if (_readOnlyDictionary != null) @@ -104,7 +116,7 @@ public bool ContainsKey(TKey key) #endif else { - return _genericDictionary.ContainsKey(key); + return GenericDictionary.ContainsKey(key); } } @@ -124,7 +136,7 @@ public ICollection Keys #endif else { - return _genericDictionary.Keys; + return GenericDictionary.Keys; } } } @@ -133,9 +145,9 @@ public bool Remove(TKey key) { if (_dictionary != null) { - if (_dictionary.Contains(key)) + if (_dictionary.Contains(key!)) { - _dictionary.Remove(key); + _dictionary.Remove(key!); return true; } else @@ -151,22 +163,26 @@ public bool Remove(TKey key) #endif else { - return _genericDictionary.Remove(key); + return GenericDictionary.Remove(key); } } - public bool TryGetValue(TKey key, out TValue value) +#pragma warning disable CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes). + public bool TryGetValue(TKey key, out TValue? value) +#pragma warning restore CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes). { if (_dictionary != null) { - if (!_dictionary.Contains(key)) + if (!_dictionary.Contains(key!)) { +#pragma warning disable CS8653 // A default expression introduces a null value for a type parameter. value = default; +#pragma warning restore CS8653 // A default expression introduces a null value for a type parameter. return false; } else { - value = (TValue)_dictionary[key]; + value = (TValue)_dictionary[key!]!; return true; } } @@ -178,7 +194,7 @@ public bool TryGetValue(TKey key, out TValue value) #endif else { - return _genericDictionary.TryGetValue(key, out value); + return GenericDictionary.TryGetValue(key, out value); } } @@ -198,7 +214,7 @@ public ICollection Values #endif else { - return _genericDictionary.Values; + return GenericDictionary.Values; } } } @@ -209,7 +225,7 @@ public TValue this[TKey key] { if (_dictionary != null) { - return (TValue)_dictionary[key]; + return (TValue)_dictionary[key!]!; } #if HAVE_READ_ONLY_COLLECTIONS else if (_readOnlyDictionary != null) @@ -219,14 +235,14 @@ public TValue this[TKey key] #endif else { - return _genericDictionary[key]; + return GenericDictionary[key]; } } set { if (_dictionary != null) { - _dictionary[key] = value; + _dictionary[key!] = value; } #if HAVE_READ_ONLY_COLLECTIONS else if (_readOnlyDictionary != null) @@ -236,7 +252,7 @@ public TValue this[TKey key] #endif else { - _genericDictionary[key] = value; + GenericDictionary[key] = value; } } } @@ -273,7 +289,7 @@ public void Clear() #endif else { - _genericDictionary.Clear(); + GenericDictionary.Clear(); } } @@ -291,7 +307,7 @@ public bool Contains(KeyValuePair item) #endif else { - return _genericDictionary.Contains(item); + return GenericDictionary.Contains(item); } } @@ -306,7 +322,7 @@ public void CopyTo(KeyValuePair[] array, int arrayIndex) while (e.MoveNext()) { DictionaryEntry entry = e.Entry; - array[arrayIndex++] = new KeyValuePair((TKey)entry.Key, (TValue)entry.Value); + array[arrayIndex++] = new KeyValuePair((TKey)entry.Key, (TValue)entry.Value!); } } finally @@ -322,7 +338,7 @@ public void CopyTo(KeyValuePair[] array, int arrayIndex) #endif else { - _genericDictionary.CopyTo(array, arrayIndex); + GenericDictionary.CopyTo(array, arrayIndex); } } @@ -342,7 +358,7 @@ public int Count #endif else { - return _genericDictionary.Count; + return GenericDictionary.Count; } } } @@ -363,7 +379,7 @@ public bool IsReadOnly #endif else { - return _genericDictionary.IsReadOnly; + return GenericDictionary.IsReadOnly; } } } @@ -372,13 +388,13 @@ public bool Remove(KeyValuePair item) { if (_dictionary != null) { - if (_dictionary.Contains(item.Key)) + if (_dictionary.Contains(item.Key!)) { - object value = _dictionary[item.Key]; + object? value = _dictionary[item.Key!]; if (Equals(value, item.Value)) { - _dictionary.Remove(item.Key); + _dictionary.Remove(item.Key!); return true; } else @@ -399,7 +415,7 @@ public bool Remove(KeyValuePair item) #endif else { - return _genericDictionary.Remove(item); + return GenericDictionary.Remove(item); } } @@ -407,7 +423,7 @@ public IEnumerator> GetEnumerator() { if (_dictionary != null) { - return _dictionary.Cast().Select(de => new KeyValuePair((TKey)de.Key, (TValue)de.Value)).GetEnumerator(); + return _dictionary.Cast().Select(de => new KeyValuePair((TKey)de.Key, (TValue)de.Value!)).GetEnumerator(); } #if HAVE_READ_ONLY_COLLECTIONS else if (_readOnlyDictionary != null) @@ -417,7 +433,7 @@ public IEnumerator> GetEnumerator() #endif else { - return _genericDictionary.GetEnumerator(); + return GenericDictionary.GetEnumerator(); } } @@ -426,7 +442,7 @@ IEnumerator IEnumerable.GetEnumerator() return GetEnumerator(); } - void IDictionary.Add(object key, object value) + void IDictionary.Add(object key, object? value) { if (_dictionary != null) { @@ -440,11 +456,11 @@ void IDictionary.Add(object key, object value) #endif else { - _genericDictionary.Add((TKey)key, (TValue)value); + GenericDictionary.Add((TKey)key, (TValue)value!); } } - object IDictionary.this[object key] + object? IDictionary.this[object key] { get { @@ -460,7 +476,7 @@ object IDictionary.this[object key] #endif else { - return _genericDictionary[(TKey)key]; + return GenericDictionary[(TKey)key]; } } set @@ -477,7 +493,13 @@ object IDictionary.this[object key] #endif else { - _genericDictionary[(TKey)key] = (TValue)value; + // Consider changing this code to call GenericDictionary.Remove when value is null. + // +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + GenericDictionary[(TKey)key] = (TValue)value; +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning restore CS8601 // Possible null reference assignment. } } } @@ -496,9 +518,9 @@ public DictionaryEnumerator(IEnumerator Entry.Key; - public object Value => Entry.Value; + public object? Value => Entry.Value; - public object Current => new DictionaryEntry(_e.Current.Key, _e.Current.Value); + public object Current => new DictionaryEntry(_e.Current.Key!, _e.Current.Value); public bool MoveNext() { @@ -525,7 +547,7 @@ IDictionaryEnumerator IDictionary.GetEnumerator() #endif else { - return new DictionaryEnumerator(_genericDictionary.GetEnumerator()); + return new DictionaryEnumerator(GenericDictionary.GetEnumerator()); } } @@ -543,7 +565,7 @@ bool IDictionary.Contains(object key) #endif else { - return _dictionary.Contains(key); + return _dictionary!.Contains(key); } } @@ -563,7 +585,7 @@ bool IDictionary.IsFixedSize #endif else { - return _dictionary.IsFixedSize; + return _dictionary!.IsFixedSize; } } } @@ -584,7 +606,7 @@ ICollection IDictionary.Keys #endif else { - return _dictionary.Keys; + return _dictionary!.Keys; } } } @@ -603,7 +625,7 @@ public void Remove(object key) #endif else { - _genericDictionary.Remove((TKey)key); + GenericDictionary.Remove((TKey)key); } } @@ -623,7 +645,7 @@ ICollection IDictionary.Values #endif else { - return _dictionary.Values; + return _dictionary!.Values; } } } @@ -642,7 +664,7 @@ void ICollection.CopyTo(Array array, int index) #endif else { - _genericDictionary.CopyTo((KeyValuePair[])array, index); + GenericDictionary.CopyTo((KeyValuePair[])array, index); } } @@ -690,9 +712,10 @@ public object UnderlyingDictionary #endif else { - return _genericDictionary; + return GenericDictionary; } } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicProxy.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicProxy.cs index 8daf1613e1..61236be7d0 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicProxy.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicProxy.cs @@ -29,6 +29,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal class DynamicProxy { public virtual IEnumerable GetDynamicMemberNames(T instance) @@ -36,19 +37,19 @@ public virtual IEnumerable GetDynamicMemberNames(T instance) return CollectionUtils.ArrayEmpty(); } - public virtual bool TryBinaryOperation(T instance, BinaryOperationBinder binder, object arg, out object result) + public virtual bool TryBinaryOperation(T instance, BinaryOperationBinder binder, object arg, out object? result) { result = null; return false; } - public virtual bool TryConvert(T instance, ConvertBinder binder, out object result) + public virtual bool TryConvert(T instance, ConvertBinder binder, out object? result) { result = null; return false; } - public virtual bool TryCreateInstance(T instance, CreateInstanceBinder binder, object[] args, out object result) + public virtual bool TryCreateInstance(T instance, CreateInstanceBinder binder, object[] args, out object? result) { result = null; return false; @@ -64,25 +65,25 @@ public virtual bool TryDeleteMember(T instance, DeleteMemberBinder binder) return false; } - public virtual bool TryGetIndex(T instance, GetIndexBinder binder, object[] indexes, out object result) + public virtual bool TryGetIndex(T instance, GetIndexBinder binder, object[] indexes, out object? result) { result = null; return false; } - public virtual bool TryGetMember(T instance, GetMemberBinder binder, out object result) + public virtual bool TryGetMember(T instance, GetMemberBinder binder, out object? result) { result = null; return false; } - public virtual bool TryInvoke(T instance, InvokeBinder binder, object[] args, out object result) + public virtual bool TryInvoke(T instance, InvokeBinder binder, object[] args, out object? result) { result = null; return false; } - public virtual bool TryInvokeMember(T instance, InvokeMemberBinder binder, object[] args, out object result) + public virtual bool TryInvokeMember(T instance, InvokeMemberBinder binder, object[] args, out object? result) { result = null; return false; @@ -98,12 +99,13 @@ public virtual bool TrySetMember(T instance, SetMemberBinder binder, object valu return false; } - public virtual bool TryUnaryOperation(T instance, UnaryOperationBinder binder, out object result) + public virtual bool TryUnaryOperation(T instance, UnaryOperationBinder binder, out object? result) { result = null; return false; } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicProxyMetaObject.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicProxyMetaObject.cs index 4d9591f11f..760b1b58a5 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicProxyMetaObject.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicProxyMetaObject.cs @@ -32,12 +32,13 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal sealed class DynamicProxyMetaObject : DynamicMetaObject { private readonly DynamicProxy _proxy; internal DynamicProxyMetaObject(Expression expression, T value, DynamicProxy proxy) - : base(expression, BindingRestrictions.Empty, value) + : base(expression, BindingRestrictions.Empty, value!) { _proxy = proxy; } @@ -109,7 +110,7 @@ public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, Dy new GetBinderAdapter(binder), NoArgs, fallback(null), - e => binder.FallbackInvoke(e, args, null) + e => binder.FallbackInvoke(e!, args, null) ), null ); @@ -164,7 +165,7 @@ public override DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, Dyna : base.BindDeleteIndex(binder, indexes); } - private delegate DynamicMetaObject Fallback(DynamicMetaObject errorSuggestion); + private delegate DynamicMetaObject Fallback(DynamicMetaObject? errorSuggestion); private static Expression[] NoArgs => CollectionUtils.ArrayEmpty(); @@ -197,7 +198,7 @@ private static ConstantExpression Constant(DynamicMetaObjectBinder binder) Type t = binder.GetType(); while (!t.IsVisible()) { - t = t.BaseType(); + t = t.BaseType()!; } return Expression.Constant(binder, t); } @@ -206,7 +207,7 @@ private static ConstantExpression Constant(DynamicMetaObjectBinder binder) /// Helper method for generating a MetaObject which calls a /// specific method on Dynamic that returns a result /// - private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, IEnumerable args, Fallback fallback, Fallback fallbackInvoke = null) + private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, IEnumerable args, Fallback fallback, Fallback? fallbackInvoke = null) { // // First, call fallback to do default binding @@ -217,7 +218,7 @@ private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObj return BuildCallMethodWithResult(methodName, binder, args, fallbackResult, fallbackInvoke); } - private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, IEnumerable args, DynamicMetaObject fallbackResult, Fallback fallbackInvoke) + private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, IEnumerable args, DynamicMetaObject fallbackResult, Fallback? fallbackInvoke) { // // Build a new expression like: @@ -256,7 +257,7 @@ private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMe Expression.Condition( Expression.Call( Expression.Constant(_proxy), - typeof(DynamicProxy).GetMethod(methodName), + typeof(DynamicProxy).GetMethod(methodName)!, callArgs ), resultMetaObject.Expression, @@ -304,7 +305,7 @@ private DynamicMetaObject CallMethodReturnLast(string methodName, DynamicMetaObj Expression.Condition( Expression.Call( Expression.Constant(_proxy), - typeof(DynamicProxy).GetMethod(methodName), + typeof(DynamicProxy).GetMethod(methodName)!, callArgs ), result, @@ -342,7 +343,7 @@ private DynamicMetaObject CallMethodNoResult(string methodName, DynamicMetaObjec Expression.Condition( Expression.Call( Expression.Constant(_proxy), - typeof(DynamicProxy).GetMethod(methodName), + typeof(DynamicProxy).GetMethod(methodName)!, callArgs ), Expression.Empty(), @@ -366,7 +367,7 @@ private BindingRestrictions GetRestrictions() public override IEnumerable GetDynamicMemberNames() { - return _proxy.GetDynamicMemberNames((T)Value); + return _proxy.GetDynamicMemberNames((T)Value!); } // It is okay to throw NotSupported from this binder. This object @@ -380,12 +381,13 @@ internal GetBinderAdapter(InvokeMemberBinder binder) : { } - public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) + public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject? errorSuggestion) { throw new NotSupportedException(); } } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicReflectionDelegateFactory.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicReflectionDelegateFactory.cs index 0e9c82a7b2..b2d50cca6d 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicReflectionDelegateFactory.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicReflectionDelegateFactory.cs @@ -36,11 +36,12 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal class DynamicReflectionDelegateFactory : ReflectionDelegateFactory { internal static DynamicReflectionDelegateFactory Instance { get; } = new DynamicReflectionDelegateFactory(); - private static DynamicMethod CreateDynamicMethod(string name, Type returnType, Type[] parameterTypes, Type owner) + private static DynamicMethod CreateDynamicMethod(string name, Type? returnType, Type[] parameterTypes, Type owner) { DynamicMethod dynamicMethod = !owner.IsInterface() ? new DynamicMethod(name, returnType, parameterTypes, owner, true) @@ -51,7 +52,7 @@ private static DynamicMethod CreateDynamicMethod(string name, Type returnType, T public override ObjectConstructor CreateParameterizedConstructor(MethodBase method) { - DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object[]) }, method.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString()!, typeof(object), new[] { typeof(object[]) }, method.DeclaringType!); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateMethodCallIL(method, generator, 0); @@ -59,14 +60,14 @@ public override ObjectConstructor CreateParameterizedConstructor(MethodB return (ObjectConstructor)dynamicMethod.CreateDelegate(typeof(ObjectConstructor)); } - public override MethodCall CreateMethodCall(MethodBase method) + public override MethodCall CreateMethodCall(MethodBase method) { - DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object), typeof(object[]) }, method.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString()!, typeof(object), new[] { typeof(object), typeof(object[]) }, method.DeclaringType!); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateMethodCallIL(method, generator, 1); - return (MethodCall)dynamicMethod.CreateDelegate(typeof(MethodCall)); + return (MethodCall)dynamicMethod.CreateDelegate(typeof(MethodCall)); } private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator, int argsIndex) @@ -80,19 +81,22 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator generator.Emit(OpCodes.Ldlen); generator.Emit(OpCodes.Ldc_I4, args.Length); generator.Emit(OpCodes.Beq, argsOk); - generator.Emit(OpCodes.Newobj, typeof(TargetParameterCountException).GetConstructor(ReflectionUtils.EmptyTypes)); + generator.Emit(OpCodes.Newobj, typeof(TargetParameterCountException).GetConstructor(ReflectionUtils.EmptyTypes)!); generator.Emit(OpCodes.Throw); generator.MarkLabel(argsOk); if (!method.IsConstructor && !method.IsStatic) { - generator.PushInstance(method.DeclaringType); + generator.PushInstance(method.DeclaringType!); } LocalBuilder localConvertible = generator.DeclareLocal(typeof(IConvertible)); LocalBuilder localObject = generator.DeclareLocal(typeof(object)); + OpCode variableAddressOpCode = args.Length < 256 ? OpCodes.Ldloca_S : OpCodes.Ldloca; + OpCode variableLoadOpCode = args.Length < 256 ? OpCodes.Ldloc_S : OpCodes.Ldloc; + for (int i = 0; i < args.Length; i++) { ParameterInfo parameter = args[i]; @@ -100,7 +104,7 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator if (parameterType.IsByRef) { - parameterType = parameterType.GetElementType(); + parameterType = parameterType.GetElementType()!; LocalBuilder localVariable = generator.DeclareLocal(parameterType); @@ -118,7 +122,7 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator generator.Emit(OpCodes.Brtrue_S, skipSettingDefault); // parameter has no value, initialize to default - generator.Emit(OpCodes.Ldloca_S, localVariable); + generator.Emit(variableAddressOpCode, localVariable); generator.Emit(OpCodes.Initobj, parameterType); generator.Emit(OpCodes.Br_S, finishedProcessingParameter); @@ -138,7 +142,7 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator } } - generator.Emit(OpCodes.Ldloca_S, localVariable); + generator.Emit(variableAddressOpCode, localVariable); } else if (parameterType.IsValueType()) { @@ -156,9 +160,9 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator // parameter has no value, initialize to default LocalBuilder localVariable = generator.DeclareLocal(parameterType); - generator.Emit(OpCodes.Ldloca_S, localVariable); + generator.Emit(variableAddressOpCode, localVariable); generator.Emit(OpCodes.Initobj, parameterType); - generator.Emit(OpCodes.Ldloc_S, localVariable); + generator.Emit(variableLoadOpCode, localVariable); generator.Emit(OpCodes.Br_S, finishedProcessingParameter); // argument has value, try to convert it to parameter type @@ -167,7 +171,7 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator if (parameterType.IsPrimitive()) { // for primitive types we need to handle type widening (e.g. short -> int) - MethodInfo toParameterTypeMethod = typeof(IConvertible) + MethodInfo? toParameterTypeMethod = typeof(IConvertible) .GetMethod("To" + parameterType.Name, new[] { typeof(IFormatProvider) }); if (toParameterTypeMethod != null) @@ -224,7 +228,7 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator } Type returnType = method.IsConstructor - ? method.DeclaringType + ? method.DeclaringType! : ((MethodInfo)method).ReturnType; if (returnType != typeof(void)) @@ -265,7 +269,7 @@ private void GenerateCreateDefaultConstructorIL(Type type, ILGenerator generator } else { - ConstructorInfo constructorInfo = + ConstructorInfo? constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, ReflectionUtils.EmptyTypes, null); if (constructorInfo == null) @@ -279,19 +283,19 @@ private void GenerateCreateDefaultConstructorIL(Type type, ILGenerator generator generator.Return(); } - public override Func CreateGet(PropertyInfo propertyInfo) + public override Func CreateGet(PropertyInfo propertyInfo) { - DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + propertyInfo.Name, typeof(object), new[] { typeof(T) }, propertyInfo.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + propertyInfo.Name, typeof(object), new[] { typeof(T) }, propertyInfo.DeclaringType!); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateGetPropertyIL(propertyInfo, generator); - return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private void GenerateCreateGetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator) { - MethodInfo getMethod = propertyInfo.GetGetMethod(true); + MethodInfo? getMethod = propertyInfo.GetGetMethod(true); if (getMethod == null) { throw new ArgumentException("Property '{0}' does not have a getter.".FormatWith(CultureInfo.InvariantCulture, propertyInfo.Name)); @@ -299,7 +303,7 @@ private void GenerateCreateGetPropertyIL(PropertyInfo propertyInfo, ILGenerator if (!getMethod.IsStatic) { - generator.PushInstance(propertyInfo.DeclaringType); + generator.PushInstance(propertyInfo.DeclaringType!); } generator.CallMethod(getMethod); @@ -307,28 +311,28 @@ private void GenerateCreateGetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator.Return(); } - public override Func CreateGet(FieldInfo fieldInfo) + public override Func CreateGet(FieldInfo fieldInfo) { if (fieldInfo.IsLiteral) { - object constantValue = fieldInfo.GetValue(null); - Func getter = o => constantValue; + object constantValue = fieldInfo.GetValue(null)!; + Func getter = o => constantValue; return getter; } - DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + fieldInfo.Name, typeof(T), new[] { typeof(object) }, fieldInfo.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + fieldInfo.Name, typeof(T), new[] { typeof(object) }, fieldInfo.DeclaringType!); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateGetFieldIL(fieldInfo, generator); - return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private void GenerateCreateGetFieldIL(FieldInfo fieldInfo, ILGenerator generator) { if (!fieldInfo.IsStatic) { - generator.PushInstance(fieldInfo.DeclaringType); + generator.PushInstance(fieldInfo.DeclaringType!); generator.Emit(OpCodes.Ldfld, fieldInfo); } else @@ -340,21 +344,21 @@ private void GenerateCreateGetFieldIL(FieldInfo fieldInfo, ILGenerator generator generator.Return(); } - public override Action CreateSet(FieldInfo fieldInfo) + public override Action CreateSet(FieldInfo fieldInfo) { - DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + fieldInfo.Name, null, new[] { typeof(T), typeof(object) }, fieldInfo.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + fieldInfo.Name, null, new[] { typeof(T), typeof(object) }, fieldInfo.DeclaringType!); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateSetFieldIL(fieldInfo, generator); - return (Action)dynamicMethod.CreateDelegate(typeof(Action)); + return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } internal static void GenerateCreateSetFieldIL(FieldInfo fieldInfo, ILGenerator generator) { if (!fieldInfo.IsStatic) { - generator.PushInstance(fieldInfo.DeclaringType); + generator.PushInstance(fieldInfo.DeclaringType!); } generator.Emit(OpCodes.Ldarg_1); @@ -372,22 +376,22 @@ internal static void GenerateCreateSetFieldIL(FieldInfo fieldInfo, ILGenerator g generator.Return(); } - public override Action CreateSet(PropertyInfo propertyInfo) + public override Action CreateSet(PropertyInfo propertyInfo) { - DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + propertyInfo.Name, null, new[] { typeof(T), typeof(object) }, propertyInfo.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + propertyInfo.Name, null, new[] { typeof(T), typeof(object) }, propertyInfo.DeclaringType!); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateSetPropertyIL(propertyInfo, generator); - return (Action)dynamicMethod.CreateDelegate(typeof(Action)); + return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } internal static void GenerateCreateSetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator) { - MethodInfo setMethod = propertyInfo.GetSetMethod(true); + MethodInfo setMethod = propertyInfo.GetSetMethod(true)!; if (!setMethod.IsStatic) { - generator.PushInstance(propertyInfo.DeclaringType); + generator.PushInstance(propertyInfo.DeclaringType!); } generator.Emit(OpCodes.Ldarg_1); @@ -396,6 +400,7 @@ internal static void GenerateCreateSetPropertyIL(PropertyInfo propertyInfo, ILGe generator.Return(); } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicUtils.cs index 98386f4957..1d6abfc3a1 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/DynamicUtils.cs @@ -38,9 +38,11 @@ using System.Text; using System.Globalization; using Microsoft.IdentityModel.Json.Serialization; +using System.Diagnostics; namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal static class DynamicUtils { internal static class BinderWrapper @@ -53,17 +55,17 @@ internal static class BinderWrapper private const string CSharpArgumentInfoFlagsTypeName = "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, " + CSharpAssemblyName; private const string CSharpBinderFlagsTypeName = "Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, " + CSharpAssemblyName; - private static object _getCSharpArgumentInfoArray; - private static object _setCSharpArgumentInfoArray; - private static MethodCall _getMemberCall; - private static MethodCall _setMemberCall; + private static object? _getCSharpArgumentInfoArray; + private static object? _setCSharpArgumentInfoArray; + private static MethodCall? _getMemberCall; + private static MethodCall? _setMemberCall; private static bool _init; private static void Init() { if (!_init) { - Type binderType = Type.GetType(BinderTypeName, false); + Type? binderType = Type.GetType(BinderTypeName, false); if (binderType == null) { throw new InvalidOperationException("Could not resolve type '{0}'. You may need to add a reference to Microsoft.CSharp.dll to work with dynamic types.".FormatWith(CultureInfo.InvariantCulture, BinderTypeName)); @@ -81,15 +83,15 @@ private static void Init() private static object CreateSharpArgumentInfoArray(params int[] values) { - Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName); - Type csharpArgumentInfoFlags = Type.GetType(CSharpArgumentInfoFlagsTypeName); + Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName, true)!; + Type csharpArgumentInfoFlags = Type.GetType(CSharpArgumentInfoFlagsTypeName, true)!; Array a = Array.CreateInstance(csharpArgumentInfoType, values.Length); for (int i = 0; i < values.Length; i++) { - MethodInfo createArgumentInfoMethod = csharpArgumentInfoType.GetMethod("Create", new[] { csharpArgumentInfoFlags, typeof(string) }); - object arg = createArgumentInfoMethod.Invoke(null, new object[] { 0, null }); + MethodInfo createArgumentInfoMethod = csharpArgumentInfoType.GetMethod("Create", new[] { csharpArgumentInfoFlags, typeof(string) })!; + object arg = createArgumentInfoMethod.Invoke(null, new object?[] { 0, null })!; a.SetValue(arg, i); } @@ -98,17 +100,17 @@ private static object CreateSharpArgumentInfoArray(params int[] values) private static void CreateMemberCalls() { - Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName, true); - Type csharpBinderFlagsType = Type.GetType(CSharpBinderFlagsTypeName, true); - Type binderType = Type.GetType(BinderTypeName, true); + Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName, true)!; + Type csharpBinderFlagsType = Type.GetType(CSharpBinderFlagsTypeName, true)!; + Type binderType = Type.GetType(BinderTypeName, true)!; Type csharpArgumentInfoTypeEnumerableType = typeof(IEnumerable<>).MakeGenericType(csharpArgumentInfoType); - MethodInfo getMemberMethod = binderType.GetMethod("GetMember", new[] { csharpBinderFlagsType, typeof(string), typeof(Type), csharpArgumentInfoTypeEnumerableType }); - _getMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(getMemberMethod); + MethodInfo getMemberMethod = binderType.GetMethod("GetMember", new[] { csharpBinderFlagsType, typeof(string), typeof(Type), csharpArgumentInfoTypeEnumerableType })!; + _getMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(getMemberMethod); - MethodInfo setMemberMethod = binderType.GetMethod("SetMember", new[] { csharpBinderFlagsType, typeof(string), typeof(Type), csharpArgumentInfoTypeEnumerableType }); - _setMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(setMemberMethod); + MethodInfo setMemberMethod = binderType.GetMethod("SetMember", new[] { csharpBinderFlagsType, typeof(string), typeof(Type), csharpArgumentInfoTypeEnumerableType })!; + _setMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(setMemberMethod); } #endif @@ -116,7 +118,9 @@ public static CallSiteBinder GetMember(string name, Type context) { #if !HAVE_REFLECTION_BINDER Init(); - return (CallSiteBinder)_getMemberCall(null, 0, name, context, _getCSharpArgumentInfoArray); + MiscellaneousUtils.Assert(_getMemberCall != null); + MiscellaneousUtils.Assert(_getCSharpArgumentInfoArray != null); + return (CallSiteBinder)_getMemberCall(null, 0, name, context, _getCSharpArgumentInfoArray)!; #else return Binder.GetMember( CSharpBinderFlags.None, name, context, new[] {CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)}); @@ -127,7 +131,9 @@ public static CallSiteBinder SetMember(string name, Type context) { #if !HAVE_REFLECTION_BINDER Init(); - return (CallSiteBinder)_setMemberCall(null, 0, name, context, _setCSharpArgumentInfoArray); + MiscellaneousUtils.Assert(_setMemberCall != null); + MiscellaneousUtils.Assert(_setCSharpArgumentInfoArray != null); + return (CallSiteBinder)_setMemberCall(null, 0, name, context, _setCSharpArgumentInfoArray)!; #else return Binder.SetMember( CSharpBinderFlags.None, name, context, new[] @@ -156,7 +162,7 @@ public NoThrowGetBinderMember(GetMemberBinder innerBinder) _innerBinder = innerBinder; } - public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) + public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject? errorSuggestion) { DynamicMetaObject retMetaObject = _innerBinder.Bind(target, CollectionUtils.ArrayEmpty()); @@ -178,7 +184,7 @@ public NoThrowSetBinderMember(SetMemberBinder innerBinder) _innerBinder = innerBinder; } - public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion) + public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject? errorSuggestion) { DynamicMetaObject retMetaObject = _innerBinder.Bind(target, new DynamicMetaObject[] { value }); @@ -205,6 +211,7 @@ protected override Expression VisitConditional(ConditionalExpression node) return base.VisitConditional(node); } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/EnumUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/EnumUtils.cs index 77bc52ef94..176904e26d 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/EnumUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/EnumUtils.cs @@ -36,35 +36,41 @@ using System.Reflection; using System.Text; using Microsoft.IdentityModel.Json.Serialization; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal static class EnumUtils { private const char EnumSeparatorChar = ','; private const string EnumSeparatorString = ", "; - private static readonly ThreadSafeStore, EnumInfo> ValuesAndNamesPerEnum = new ThreadSafeStore, EnumInfo>(InitializeValuesAndNames); + private static readonly ThreadSafeStore, EnumInfo> ValuesAndNamesPerEnum = new ThreadSafeStore, EnumInfo>(InitializeValuesAndNames); - private static EnumInfo InitializeValuesAndNames(StructMultiKey key) + private static EnumInfo InitializeValuesAndNames(StructMultiKey key) { Type enumType = key.Value1; string[] names = Enum.GetNames(enumType); string[] resolvedNames = new string[names.Length]; ulong[] values = new ulong[names.Length]; + bool hasSpecifiedName; for (int i = 0; i < names.Length; i++) { string name = names[i]; - FieldInfo f = enumType.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); - values[i] = ToUInt64(f.GetValue(null)); + FieldInfo f = enumType.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)!; + values[i] = ToUInt64(f.GetValue(null)!); string resolvedName; #if HAVE_DATA_CONTRACTS - resolvedName = f.GetCustomAttributes(typeof(EnumMemberAttribute), true) + string? specifiedName = f.GetCustomAttributes(typeof(EnumMemberAttribute), true) .Cast() .Select(a => a.Value) - .SingleOrDefault() ?? f.Name; + .SingleOrDefault(); + hasSpecifiedName = specifiedName != null; + resolvedName = specifiedName ?? name; if (Array.IndexOf(resolvedNames, resolvedName, 0, i) != -1) { @@ -72,10 +78,11 @@ private static EnumInfo InitializeValuesAndNames(StructMultiKey GetFlagsValues(T value) where T : struct return selectedFlagsValues; } - public static bool TryToString(Type enumType, object value, NamingStrategy namingStrategy, out string name) + // Used by Microsoft.IdentityModel.Json.Schema + private static CamelCaseNamingStrategy _camelCaseNamingStrategy = new CamelCaseNamingStrategy(); + public static bool TryToString(Type enumType, object value, bool camelCase, [NotNullWhen(true)]out string? name) { - EnumInfo enumInfo = ValuesAndNamesPerEnum.Get(new StructMultiKey(enumType, namingStrategy)); + return TryToString(enumType, value, camelCase ? _camelCaseNamingStrategy : null, out name); + } + + public static bool TryToString(Type enumType, object value, NamingStrategy? namingStrategy, [NotNullWhen(true)]out string? name) + { + EnumInfo enumInfo = ValuesAndNamesPerEnum.Get(new StructMultiKey(enumType, namingStrategy)); ulong v = ToUInt64(value); if (!enumInfo.IsFlags) @@ -142,7 +156,7 @@ public static bool TryToString(Type enumType, object value, NamingStrategy namin } } - private static string InternalFlagsFormat(EnumInfo entry, ulong result) + private static string? InternalFlagsFormat(EnumInfo entry, ulong result) { string[] resolvedNames = entry.ResolvedNames; ulong[] values = entry.Values; @@ -178,7 +192,7 @@ private static string InternalFlagsFormat(EnumInfo entry, ulong result) index--; } - string returnString; + string? returnString; if (result != 0) { // We were unable to represent this number as a bitwise or of valid flags @@ -206,7 +220,7 @@ private static string InternalFlagsFormat(EnumInfo entry, ulong result) public static EnumInfo GetEnumValuesAndNames(Type enumType) { - return ValuesAndNamesPerEnum.Get(new StructMultiKey(enumType, null)); + return ValuesAndNamesPerEnum.Get(new StructMultiKey(enumType, null)); } private static ulong ToUInt64(object value) @@ -242,7 +256,7 @@ private static ulong ToUInt64(object value) } } - public static object ParseEnum(Type enumType, NamingStrategy namingStrategy, string value, bool disallowNumber) + public static object ParseEnum(Type enumType, NamingStrategy? namingStrategy, string value, bool disallowNumber) { ValidationUtils.ArgumentNotNull(enumType, nameof(enumType)); ValidationUtils.ArgumentNotNull(value, nameof(value)); @@ -252,7 +266,7 @@ public static object ParseEnum(Type enumType, NamingStrategy namingStrategy, str throw new ArgumentException("Type provided must be an Enum.", nameof(enumType)); } - EnumInfo entry = ValuesAndNamesPerEnum.Get(new StructMultiKey(enumType, namingStrategy)); + EnumInfo entry = ValuesAndNamesPerEnum.Get(new StructMultiKey(enumType, namingStrategy)); string[] enumNames = entry.Names; string[] resolvedNames = entry.ResolvedNames; ulong[] enumValues = entry.Values; @@ -285,7 +299,7 @@ public static object ParseEnum(Type enumType, NamingStrategy namingStrategy, str Type underlyingType = Enum.GetUnderlyingType(enumType); value = value.Trim(); - object temp = null; + object? temp = null; try { @@ -391,4 +405,5 @@ public static object ParseEnum(Type enumType, NamingStrategy namingStrategy, str return null; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ExpressionReflectionDelegateFactory.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ExpressionReflectionDelegateFactory.cs index 357e654fc2..078112ca81 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ExpressionReflectionDelegateFactory.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ExpressionReflectionDelegateFactory.cs @@ -35,6 +35,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal class ExpressionReflectionDelegateFactory : ReflectionDelegateFactory { private static readonly ExpressionReflectionDelegateFactory _instance = new ExpressionReflectionDelegateFactory(); @@ -57,7 +58,7 @@ public override ObjectConstructor CreateParameterizedConstructor(MethodB return compiled; } - public override MethodCall CreateMethodCall(MethodBase method) + public override MethodCall CreateMethodCall(MethodBase method) { ValidationUtils.ArgumentNotNull(method, nameof(method)); @@ -70,7 +71,7 @@ public override MethodCall CreateMethodCall(MethodBase method) LambdaExpression lambdaExpression = Expression.Lambda(typeof(MethodCall), callExpression, targetParameterExpression, argsParameterExpression); - MethodCall compiled = (MethodCall)lambdaExpression.Compile(); + MethodCall compiled = (MethodCall)lambdaExpression.Compile(); return compiled; } @@ -79,9 +80,16 @@ private class ByRefParameter public Expression Value; public ParameterExpression Variable; public bool IsOut; + + public ByRefParameter(Expression value, ParameterExpression variable, bool isOut) + { + Value = value; + Variable = variable; + IsOut = isOut; + } } - private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpression targetParameterExpression, ParameterExpression argsParameterExpression) + private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpression? targetParameterExpression, ParameterExpression argsParameterExpression) { ParameterInfo[] parametersInfo = method.GetParameters(); @@ -104,7 +112,7 @@ private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpres bool isByRef = false; if (parameterType.IsByRef) { - parameterType = parameterType.GetElementType(); + parameterType = parameterType.GetElementType()!; isByRef = true; } @@ -117,7 +125,7 @@ private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpres if (isByRef) { ParameterExpression variable = Expression.Variable(parameterType); - refParameterMap.Add(new ByRefParameter {Value = argExpression, Variable = variable, IsOut = parameter.IsOut}); + refParameterMap.Add(new ByRefParameter(argExpression, variable, parameter.IsOut)); argExpression = variable; } @@ -137,7 +145,7 @@ private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpres } else { - Expression readParameter = EnsureCastExpression(targetParameterExpression, method.DeclaringType); + Expression readParameter = EnsureCastExpression(targetParameterExpression!, method.DeclaringType!); callExpression = Expression.Call(readParameter, (MethodInfo)method, argsExpression); } @@ -187,7 +195,7 @@ public override Func CreateDefaultConstructor(Type type) // avoid error from expressions compiler because of abstract class if (type.IsAbstract()) { - return () => (T)Activator.CreateInstance(type); + return () => (T)Activator.CreateInstance(type)!; } try @@ -207,11 +215,11 @@ public override Func CreateDefaultConstructor(Type type) { // an error can be thrown if constructor is not valid on Win8 // will have INVOCATION_FLAGS_NON_W8P_FX_API invocation flag - return () => (T)Activator.CreateInstance(type); + return () => (T)Activator.CreateInstance(type)!; } } - public override Func CreateGet(PropertyInfo propertyInfo) + public override Func CreateGet(PropertyInfo propertyInfo) { ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo)); @@ -221,7 +229,11 @@ public override Func CreateGet(PropertyInfo propertyInfo) ParameterExpression parameterExpression = Expression.Parameter(instanceType, "instance"); Expression resultExpression; - MethodInfo getMethod = propertyInfo.GetGetMethod(true); + MethodInfo? getMethod = propertyInfo.GetGetMethod(true); + if (getMethod == null) + { + throw new ArgumentException("Property does not have a getter."); + } if (getMethod.IsStatic) { @@ -229,7 +241,7 @@ public override Func CreateGet(PropertyInfo propertyInfo) } else { - Expression readParameter = EnsureCastExpression(parameterExpression, propertyInfo.DeclaringType); + Expression readParameter = EnsureCastExpression(parameterExpression, propertyInfo.DeclaringType!); resultExpression = Expression.MakeMemberAccess(readParameter, propertyInfo); } @@ -238,11 +250,11 @@ public override Func CreateGet(PropertyInfo propertyInfo) LambdaExpression lambdaExpression = Expression.Lambda(typeof(Func), resultExpression, parameterExpression); - Func compiled = (Func)lambdaExpression.Compile(); + Func compiled = (Func)lambdaExpression.Compile(); return compiled; } - public override Func CreateGet(FieldInfo fieldInfo) + public override Func CreateGet(FieldInfo fieldInfo) { ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo)); @@ -255,24 +267,24 @@ public override Func CreateGet(FieldInfo fieldInfo) } else { - Expression sourceExpression = EnsureCastExpression(sourceParameter, fieldInfo.DeclaringType); + Expression sourceExpression = EnsureCastExpression(sourceParameter, fieldInfo.DeclaringType!); fieldExpression = Expression.Field(sourceExpression, fieldInfo); } fieldExpression = EnsureCastExpression(fieldExpression, typeof(object)); - Func compiled = Expression.Lambda>(fieldExpression, sourceParameter).Compile(); + Func compiled = Expression.Lambda>(fieldExpression, sourceParameter).Compile(); return compiled; } - public override Action CreateSet(FieldInfo fieldInfo) + public override Action CreateSet(FieldInfo fieldInfo) { ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo)); // use reflection for structs // expression doesn't correctly set value - if (fieldInfo.DeclaringType.IsValueType() || fieldInfo.IsInitOnly) + if (fieldInfo.DeclaringType!.IsValueType() || fieldInfo.IsInitOnly) { return LateBoundReflectionDelegateFactory.Instance.CreateSet(fieldInfo); } @@ -287,7 +299,7 @@ public override Action CreateSet(FieldInfo fieldInfo) } else { - Expression sourceExpression = EnsureCastExpression(sourceParameterExpression, fieldInfo.DeclaringType); + Expression sourceExpression = EnsureCastExpression(sourceParameterExpression, fieldInfo.DeclaringType!); fieldExpression = Expression.Field(sourceExpression, fieldInfo); } @@ -298,17 +310,17 @@ public override Action CreateSet(FieldInfo fieldInfo) LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action), assignExpression, sourceParameterExpression, valueParameterExpression); - Action compiled = (Action)lambdaExpression.Compile(); + Action compiled = (Action)lambdaExpression.Compile(); return compiled; } - public override Action CreateSet(PropertyInfo propertyInfo) + public override Action CreateSet(PropertyInfo propertyInfo) { ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo)); // use reflection for structs // expression doesn't correctly set value - if (propertyInfo.DeclaringType.IsValueType()) + if (propertyInfo.DeclaringType!.IsValueType()) { return LateBoundReflectionDelegateFactory.Instance.CreateSet(propertyInfo); } @@ -321,7 +333,11 @@ public override Action CreateSet(PropertyInfo propertyInfo) ParameterExpression valueParameter = Expression.Parameter(valueType, "value"); Expression readValueParameter = EnsureCastExpression(valueParameter, propertyInfo.PropertyType); - MethodInfo setMethod = propertyInfo.GetSetMethod(true); + MethodInfo? setMethod = propertyInfo.GetSetMethod(true); + if (setMethod == null) + { + throw new ArgumentException("Property does not have a setter."); + } Expression setExpression; if (setMethod.IsStatic) @@ -330,14 +346,14 @@ public override Action CreateSet(PropertyInfo propertyInfo) } else { - Expression readInstanceParameter = EnsureCastExpression(instanceParameter, propertyInfo.DeclaringType); + Expression readInstanceParameter = EnsureCastExpression(instanceParameter, propertyInfo.DeclaringType!); setExpression = Expression.Call(readInstanceParameter, setMethod, readValueParameter); } - LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action), setExpression, instanceParameter, valueParameter); + LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action), setExpression, instanceParameter, valueParameter); - Action compiled = (Action)lambdaExpression.Compile(); + Action compiled = (Action)lambdaExpression.Compile(); return compiled; } @@ -357,7 +373,7 @@ private Expression EnsureCastExpression(Expression expression, Type targetType, if (allowWidening && targetType.IsPrimitive()) { - MethodInfo toTargetTypeMethod = typeof(Convert) + MethodInfo? toTargetTypeMethod = typeof(Convert) .GetMethod("To" + targetType.Name, new[] { typeof(object) }); if (toTargetTypeMethod != null) @@ -378,6 +394,7 @@ private Expression EnsureCastExpression(Expression expression, Type targetType, return Expression.Convert(expression, targetType); } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/FSharpUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/FSharpUtils.cs index 17794cfedb..b6a19e3f9e 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/FSharpUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/FSharpUtils.cs @@ -31,15 +31,17 @@ using System.Reflection; using System.Text; using Microsoft.IdentityModel.Json.Serialization; +using System.Diagnostics; namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal class FSharpFunction { - private readonly object _instance; - private readonly MethodCall _invoker; + private readonly object? _instance; + private readonly MethodCall _invoker; - public FSharpFunction(object instance, MethodCall invoker) + public FSharpFunction(object? instance, MethodCall invoker) { _instance = instance; _invoker = invoker; @@ -53,69 +55,78 @@ public object Invoke(params object[] args) } } - internal static class FSharpUtils + internal class FSharpUtils { - private static readonly object Lock = new object(); + private FSharpUtils(Assembly fsharpCoreAssembly) + { + FSharpCoreAssembly = fsharpCoreAssembly; - private static bool _initialized; - private static MethodInfo _ofSeq; - private static Type _mapType; - - public static Assembly FSharpCoreAssembly { get; private set; } - public static MethodCall IsUnion { get; private set; } - public static MethodCall GetUnionCases { get; private set; } - public static MethodCall PreComputeUnionTagReader { get; private set; } - public static MethodCall PreComputeUnionReader { get; private set; } - public static MethodCall PreComputeUnionConstructor { get; private set; } - public static Func GetUnionCaseInfoDeclaringType { get; private set; } - public static Func GetUnionCaseInfoName { get; private set; } - public static Func GetUnionCaseInfoTag { get; private set; } - public static MethodCall GetUnionCaseInfoFields { get; private set; } + Type fsharpType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpType")!; - public const string FSharpSetTypeName = "FSharpSet`1"; - public const string FSharpListTypeName = "FSharpList`1"; - public const string FSharpMapTypeName = "FSharpMap`2"; + MethodInfo isUnionMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "IsUnion", BindingFlags.Public | BindingFlags.Static); + IsUnion = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(isUnionMethodInfo)!; - public static void EnsureInitialized(Assembly fsharpCoreAssembly) - { - if (!_initialized) - { - lock (Lock) - { - if (!_initialized) - { - FSharpCoreAssembly = fsharpCoreAssembly; + MethodInfo getUnionCasesMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "GetUnionCases", BindingFlags.Public | BindingFlags.Static); + GetUnionCases = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(getUnionCasesMethodInfo)!; + + Type fsharpValue = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpValue")!; - Type fsharpType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpType"); + PreComputeUnionTagReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionTagReader"); + PreComputeUnionReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionReader"); + PreComputeUnionConstructor = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionConstructor"); - MethodInfo isUnionMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "IsUnion", BindingFlags.Public | BindingFlags.Static); - IsUnion = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(isUnionMethodInfo); + Type unionCaseInfo = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.UnionCaseInfo")!; - MethodInfo getUnionCasesMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "GetUnionCases", BindingFlags.Public | BindingFlags.Static); - GetUnionCases = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(getUnionCasesMethodInfo); + GetUnionCaseInfoName = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("Name")!)!; + GetUnionCaseInfoTag = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("Tag")!)!; + GetUnionCaseInfoDeclaringType = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("DeclaringType")!)!; + GetUnionCaseInfoFields = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(unionCaseInfo.GetMethod("GetFields")!); - Type fsharpValue = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpValue"); + Type listModule = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.ListModule")!; + _ofSeq = listModule.GetMethod("OfSeq")!; - PreComputeUnionTagReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionTagReader"); - PreComputeUnionReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionReader"); - PreComputeUnionConstructor = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionConstructor"); + _mapType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.FSharpMap`2")!; + } + + private static readonly object Lock = new object(); + private static FSharpUtils? _instance; - Type unionCaseInfo = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.UnionCaseInfo"); + public static FSharpUtils Instance + { + get + { + MiscellaneousUtils.Assert(_instance != null); + return _instance; + } + } - GetUnionCaseInfoName = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("Name")); - GetUnionCaseInfoTag = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("Tag")); - GetUnionCaseInfoDeclaringType = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("DeclaringType")); - GetUnionCaseInfoFields = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(unionCaseInfo.GetMethod("GetFields")); + private MethodInfo _ofSeq; + private Type _mapType; - Type listModule = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.ListModule"); - _ofSeq = listModule.GetMethod("OfSeq"); + public Assembly FSharpCoreAssembly { get; private set; } + public MethodCall IsUnion { get; private set; } + public MethodCall GetUnionCases { get; private set; } + public MethodCall PreComputeUnionTagReader { get; private set; } + public MethodCall PreComputeUnionReader { get; private set; } + public MethodCall PreComputeUnionConstructor { get; private set; } + public Func GetUnionCaseInfoDeclaringType { get; private set; } + public Func GetUnionCaseInfoName { get; private set; } + public Func GetUnionCaseInfoTag { get; private set; } + public MethodCall GetUnionCaseInfoFields { get; private set; } - _mapType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.FSharpMap`2"); + public const string FSharpSetTypeName = "FSharpSet`1"; + public const string FSharpListTypeName = "FSharpList`1"; + public const string FSharpMapTypeName = "FSharpMap`2"; -#if HAVE_MEMORY_BARRIER - Thread.MemoryBarrier(); -#endif - _initialized = true; + public static void EnsureInitialized(Assembly fsharpCoreAssembly) + { + if (_instance == null) + { + lock (Lock) + { + if (_instance == null) + { + _instance = new FSharpUtils(fsharpCoreAssembly); } } } @@ -123,31 +134,31 @@ public static void EnsureInitialized(Assembly fsharpCoreAssembly) private static MethodInfo GetMethodWithNonPublicFallback(Type type, string methodName, BindingFlags bindingFlags) { - MethodInfo methodInfo = type.GetMethod(methodName, bindingFlags); + MethodInfo methodInfo = type.GetMethod(methodName, bindingFlags)!; // if no matching method then attempt to find with nonpublic flag // this is required because in WinApps some methods are private but always using NonPublic breaks medium trust - // https://github.com/JamesNK/Microsoft.IdentityModel.Json/pull/649 - // https://github.com/JamesNK/Microsoft.IdentityModel.Json/issues/821 + // https://github.com/JamesNK/Newtonsoft.Json/pull/649 + // https://github.com/JamesNK/Newtonsoft.Json/issues/821 if (methodInfo == null && (bindingFlags & BindingFlags.NonPublic) != BindingFlags.NonPublic) { - methodInfo = type.GetMethod(methodName, bindingFlags | BindingFlags.NonPublic); + methodInfo = type.GetMethod(methodName, bindingFlags | BindingFlags.NonPublic)!; } - return methodInfo; + return methodInfo!; } - private static MethodCall CreateFSharpFuncCall(Type type, string methodName) + private static MethodCall CreateFSharpFuncCall(Type type, string methodName) { MethodInfo innerMethodInfo = GetMethodWithNonPublicFallback(type, methodName, BindingFlags.Public | BindingFlags.Static); - MethodInfo invokeFunc = innerMethodInfo.ReturnType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance); + MethodInfo invokeFunc = innerMethodInfo.ReturnType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance)!; - MethodCall call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(innerMethodInfo); - MethodCall invoke = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(invokeFunc); + MethodCall call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(innerMethodInfo); + MethodCall invoke = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(invokeFunc)!; - MethodCall createFunction = (target, args) => + MethodCall createFunction = (target, args) => { - object result = call(target, args); + object? result = call(target, args); FSharpFunction f = new FSharpFunction(result, invoke); return f; @@ -156,32 +167,32 @@ private static MethodCall CreateFSharpFuncCall(Type type, string return createFunction; } - public static ObjectConstructor CreateSeq(Type t) + public ObjectConstructor CreateSeq(Type t) { MethodInfo seqType = _ofSeq.MakeGenericMethod(t); return JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(seqType); } - public static ObjectConstructor CreateMap(Type keyType, Type valueType) + public ObjectConstructor CreateMap(Type keyType, Type valueType) { - MethodInfo creatorDefinition = typeof(FSharpUtils).GetMethod("BuildMapCreator"); + MethodInfo creatorDefinition = typeof(FSharpUtils).GetMethod("BuildMapCreator")!; MethodInfo creatorGeneric = creatorDefinition.MakeGenericMethod(keyType, valueType); - return (ObjectConstructor)creatorGeneric.Invoke(null, null); + return (ObjectConstructor)creatorGeneric.Invoke(this, null)!; } - public static ObjectConstructor BuildMapCreator() + public ObjectConstructor BuildMapCreator() { Type genericMapType = _mapType.MakeGenericType(typeof(TKey), typeof(TValue)); - ConstructorInfo ctor = genericMapType.GetConstructor(new[] { typeof(IEnumerable>) }); + ConstructorInfo ctor = genericMapType.GetConstructor(new[] { typeof(IEnumerable>) })!; ObjectConstructor ctorDelegate = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(ctor); ObjectConstructor creator = args => { // convert dictionary KeyValuePairs to Tuples - IEnumerable> values = (IEnumerable>)args[0]; + IEnumerable> values = (IEnumerable>)args[0]!; IEnumerable> tupleValues = values.Select(kv => new Tuple(kv.Key, kv.Value)); return ctorDelegate(tupleValues); @@ -190,6 +201,7 @@ public static ObjectConstructor BuildMapCreator() return creator; } } +#nullable disable } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ImmutableCollectionsUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ImmutableCollectionsUtils.cs index 7fc9e32a0b..1c07324a6c 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ImmutableCollectionsUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ImmutableCollectionsUtils.cs @@ -25,21 +25,24 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else using System.Linq; #endif using System.Reflection; +using System.Runtime.CompilerServices; using System.Text; using Microsoft.IdentityModel.Json.Serialization; namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable /// /// Helper class for serializing immutable collections. /// Note that this is used by all builds, even those that don't support immutable collections, in case the DLL is GACed - /// https://github.com/JamesNK/Microsoft.IdentityModel.Json/issues/652 + /// https://github.com/JamesNK/Newtonsoft.Json/issues/652 /// internal static class ImmutableCollectionsUtils { @@ -88,7 +91,7 @@ public ImmutableCollectionTypeInfo(string contractTypeName, string createdTypeNa new ImmutableCollectionTypeInfo(ImmutableQueueGenericTypeName, ImmutableQueueGenericTypeName, ImmutableQueueTypeName), new ImmutableCollectionTypeInfo(ImmutableStackGenericInterfaceTypeName, ImmutableStackGenericTypeName, ImmutableStackTypeName), new ImmutableCollectionTypeInfo(ImmutableStackGenericTypeName, ImmutableStackGenericTypeName, ImmutableStackTypeName), - new ImmutableCollectionTypeInfo(ImmutableSetGenericInterfaceTypeName, ImmutableSortedSetGenericTypeName, ImmutableSortedSetTypeName), + new ImmutableCollectionTypeInfo(ImmutableSetGenericInterfaceTypeName, ImmutableHashSetGenericTypeName, ImmutableHashSetTypeName), new ImmutableCollectionTypeInfo(ImmutableSortedSetGenericTypeName, ImmutableSortedSetGenericTypeName, ImmutableSortedSetTypeName), new ImmutableCollectionTypeInfo(ImmutableHashSetGenericTypeName, ImmutableHashSetGenericTypeName, ImmutableHashSetTypeName), new ImmutableCollectionTypeInfo(ImmutableArrayGenericTypeName, ImmutableArrayGenericTypeName, ImmutableArrayTypeName) @@ -104,27 +107,27 @@ public ImmutableCollectionTypeInfo(string contractTypeName, string createdTypeNa private static readonly IList DictionaryContractImmutableCollectionDefinitions = new List { - new ImmutableCollectionTypeInfo(ImmutableDictionaryGenericInterfaceTypeName, ImmutableSortedDictionaryGenericTypeName, ImmutableSortedDictionaryTypeName), + new ImmutableCollectionTypeInfo(ImmutableDictionaryGenericInterfaceTypeName, ImmutableDictionaryGenericTypeName, ImmutableDictionaryTypeName), new ImmutableCollectionTypeInfo(ImmutableSortedDictionaryGenericTypeName, ImmutableSortedDictionaryGenericTypeName, ImmutableSortedDictionaryTypeName), new ImmutableCollectionTypeInfo(ImmutableDictionaryGenericTypeName, ImmutableDictionaryGenericTypeName, ImmutableDictionaryTypeName) }; - internal static bool TryBuildImmutableForArrayContract(Type underlyingType, Type collectionItemType, out Type createdType, out ObjectConstructor parameterizedCreator) + internal static bool TryBuildImmutableForArrayContract(Type underlyingType, Type collectionItemType, [NotNullWhen(true)]out Type? createdType, [NotNullWhen(true)]out ObjectConstructor? parameterizedCreator) { if (underlyingType.IsGenericType()) { Type underlyingTypeDefinition = underlyingType.GetGenericTypeDefinition(); - string name = underlyingTypeDefinition.FullName; + string name = underlyingTypeDefinition.FullName!; - ImmutableCollectionTypeInfo definition = ArrayContractImmutableCollectionDefinitions.FirstOrDefault(d => d.ContractTypeName == name); + ImmutableCollectionTypeInfo? definition = ArrayContractImmutableCollectionDefinitions.FirstOrDefault(d => d.ContractTypeName == name); if (definition != null) { - Type createdTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.CreatedTypeName); - Type builderTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.BuilderTypeName); + Type? createdTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.CreatedTypeName); + Type? builderTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.BuilderTypeName); if (createdTypeDefinition != null && builderTypeDefinition != null) { - MethodInfo mb = builderTypeDefinition.GetMethods().FirstOrDefault(m => m.Name == "CreateRange" && m.GetParameters().Length == 1); + MethodInfo? mb = builderTypeDefinition.GetMethods().FirstOrDefault(m => m.Name == "CreateRange" && m.GetParameters().Length == 1); if (mb != null) { createdType = createdTypeDefinition.MakeGenericType(collectionItemType); @@ -141,22 +144,22 @@ internal static bool TryBuildImmutableForArrayContract(Type underlyingType, Type return false; } - internal static bool TryBuildImmutableForDictionaryContract(Type underlyingType, Type keyItemType, Type valueItemType, out Type createdType, out ObjectConstructor parameterizedCreator) + internal static bool TryBuildImmutableForDictionaryContract(Type underlyingType, Type keyItemType, Type valueItemType, [NotNullWhen(true)]out Type? createdType, [NotNullWhen(true)]out ObjectConstructor? parameterizedCreator) { if (underlyingType.IsGenericType()) { Type underlyingTypeDefinition = underlyingType.GetGenericTypeDefinition(); - string name = underlyingTypeDefinition.FullName; + string name = underlyingTypeDefinition.FullName!; - ImmutableCollectionTypeInfo definition = DictionaryContractImmutableCollectionDefinitions.FirstOrDefault(d => d.ContractTypeName == name); + ImmutableCollectionTypeInfo? definition = DictionaryContractImmutableCollectionDefinitions.FirstOrDefault(d => d.ContractTypeName == name); if (definition != null) { - Type createdTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.CreatedTypeName); - Type builderTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.BuilderTypeName); + Type? createdTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.CreatedTypeName); + Type? builderTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.BuilderTypeName); if (createdTypeDefinition != null && builderTypeDefinition != null) { - MethodInfo mb = builderTypeDefinition.GetMethods().FirstOrDefault(m => + MethodInfo? mb = builderTypeDefinition.GetMethods().FirstOrDefault(m => { ParameterInfo[] parameters = m.GetParameters(); @@ -178,4 +181,5 @@ internal static bool TryBuildImmutableForDictionaryContract(Type underlyingType, return false; } } +#nullable disable } diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/JavaScriptUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/JavaScriptUtils.cs index ee4ecf12e7..df9a7d5be6 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/JavaScriptUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/JavaScriptUtils.cs @@ -31,6 +31,8 @@ #endif using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else @@ -39,9 +41,10 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal static class BufferUtils { - public static char[] RentBuffer(IArrayPool bufferPool, int minSize) + public static char[] RentBuffer(IArrayPool? bufferPool, int minSize) { if (bufferPool == null) { @@ -52,12 +55,12 @@ public static char[] RentBuffer(IArrayPool bufferPool, int minSize) return buffer; } - public static void ReturnBuffer(IArrayPool bufferPool, char[] buffer) + public static void ReturnBuffer(IArrayPool? bufferPool, char[]? buffer) { bufferPool?.Return(buffer); } - public static char[] EnsureBufferSize(IArrayPool bufferPool, int size, char[] buffer) + public static char[] EnsureBufferSize(IArrayPool? bufferPool, int size, char[]? buffer) { if (bufferPool == null) { @@ -123,15 +126,16 @@ public static bool[] GetCharEscapeFlags(StringEscapeHandling stringEscapeHandlin return SingleQuoteCharEscapeFlags; } - public static bool ShouldEscapeJavaScriptString(string s, bool[] charEscapeFlags) + public static bool ShouldEscapeJavaScriptString(string? s, bool[] charEscapeFlags) { if (s == null) { return false; } - foreach (char c in s) + for (int i = 0; i < s.Length; i++) { + char c = s[i]; if (c >= charEscapeFlags.Length || charEscapeFlags[c]) { return true; @@ -141,8 +145,8 @@ public static bool ShouldEscapeJavaScriptString(string s, bool[] charEscapeFlags return false; } - public static void WriteEscapedJavaScriptString(TextWriter writer, string s, char delimiter, bool appendDelimiters, - bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, IArrayPool bufferPool, ref char[] writeBuffer) + public static void WriteEscapedJavaScriptString(TextWriter writer, string? s, char delimiter, bool appendDelimiters, + bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, IArrayPool? bufferPool, ref char[]? writeBuffer) { // leading delimiter if (appendDelimiters) @@ -150,7 +154,7 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha writer.Write(delimiter); } - if (!string.IsNullOrEmpty(s)) + if (!StringUtils.IsNullOrEmpty(s)) { int lastWritePosition = FirstCharToEscape(s, charEscapeFlags, stringEscapeHandling); if (lastWritePosition == -1) @@ -181,7 +185,7 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha continue; } - string escapedValue; + string? escapedValue; switch (c) { @@ -230,7 +234,7 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha writeBuffer = BufferUtils.EnsureBufferSize(bufferPool, UnicodeTextLength, writeBuffer); } - StringUtils.ToCharAsUnicode(c, writeBuffer); + StringUtils.ToCharAsUnicode(c, writeBuffer!); // slightly hacky but it saves multiple conditions in if test escapedValue = EscapedUnicodeText; @@ -248,7 +252,7 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha continue; } - bool isEscapedUnicodeText = string.Equals(escapedValue, EscapedUnicodeText); + bool isEscapedUnicodeText = string.Equals(escapedValue, EscapedUnicodeText, StringComparison.Ordinal); if (i > lastWritePosition) { @@ -263,7 +267,7 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha // copy it over when creating new buffer if (isEscapedUnicodeText) { - Debug.Assert(writeBuffer != null, "Write buffer should never be null because it is set when the escaped unicode text is encountered."); + MiscellaneousUtils.Assert(writeBuffer != null, "Write buffer should never be null because it is set when the escaped unicode text is encountered."); Array.Copy(writeBuffer, newBuffer, UnicodeTextLength); } @@ -286,11 +290,12 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha } else { + MiscellaneousUtils.Assert(writeBuffer != null); writer.Write(writeBuffer, 0, UnicodeTextLength); } } - Debug.Assert(lastWritePosition != 0); + MiscellaneousUtils.Assert(lastWritePosition != 0); length = s.Length - lastWritePosition; if (length > 0) { @@ -314,13 +319,13 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha } } - public static string ToEscapedJavaScriptString(string value, char delimiter, bool appendDelimiters, StringEscapeHandling stringEscapeHandling) + public static string ToEscapedJavaScriptString(string? value, char delimiter, bool appendDelimiters, StringEscapeHandling stringEscapeHandling) { bool[] charEscapeFlags = GetCharEscapeFlags(stringEscapeHandling, delimiter); using (StringWriter w = StringUtils.CreateStringWriter(value?.Length ?? 16)) { - char[] buffer = null; + char[]? buffer = null; WriteEscapedJavaScriptString(w, value, delimiter, appendDelimiters, charEscapeFlags, stringEscapeHandling, null, ref buffer); return w.ToString(); } @@ -371,7 +376,7 @@ public static Task WriteEscapedJavaScriptStringAsync(TextWriter writer, string s return WriteEscapedJavaScriptStringWithDelimitersAsync(writer, s, delimiter, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken); } - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { return cancellationToken.CancelIfRequestedAsync() ?? AsyncUtils.CompletedTask; } @@ -383,15 +388,15 @@ private static Task WriteEscapedJavaScriptStringWithDelimitersAsync(TextWriter w bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, JsonTextWriter client, char[] writeBuffer, CancellationToken cancellationToken) { Task task = writer.WriteAsync(delimiter, cancellationToken); - if (!task.IsCompletedSucessfully()) + if (!task.IsCompletedSuccessfully()) { return WriteEscapedJavaScriptStringWithDelimitersAsync(task, writer, s, delimiter, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken); } - if (!string.IsNullOrEmpty(s)) + if (!StringUtils.IsNullOrEmpty(s)) { task = WriteEscapedJavaScriptStringWithoutDelimitersAsync(writer, s, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return writer.WriteAsync(delimiter, cancellationToken); } @@ -406,7 +411,7 @@ private static async Task WriteEscapedJavaScriptStringWithDelimitersAsync(Task t { await task.ConfigureAwait(false); - if (!string.IsNullOrEmpty(s)) + if (!StringUtils.IsNullOrEmpty(s)) { await WriteEscapedJavaScriptStringWithoutDelimitersAsync(writer, s, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken).ConfigureAwait(false); } @@ -450,7 +455,7 @@ private static async Task WriteDefinitelyEscapedJavaScriptStringWithoutDelimiter int length; bool isEscapedUnicodeText = false; - string escapedValue = null; + string? escapedValue = null; for (int i = lastWritePosition; i < s.Length; i++) { @@ -539,7 +544,7 @@ private static async Task WriteDefinitelyEscapedJavaScriptStringWithoutDelimiter lastWritePosition = i + 1; if (!isEscapedUnicodeText) { - await writer.WriteAsync(escapedValue, cancellationToken).ConfigureAwait(false); + await writer.WriteAsync(escapedValue!, cancellationToken).ConfigureAwait(false); } else { @@ -565,7 +570,7 @@ private static async Task WriteDefinitelyEscapedJavaScriptStringWithoutDelimiter } #endif - public static bool TryGetDateFromConstructorJson(JsonReader reader, out DateTime dateTime, out string errorMessage) + public static bool TryGetDateFromConstructorJson(JsonReader reader, out DateTime dateTime, [NotNullWhen(false)]out string? errorMessage) { dateTime = default; errorMessage = null; @@ -626,7 +631,7 @@ public static bool TryGetDateFromConstructorJson(JsonReader reader, out DateTime return true; } - private static bool TryGetDateConstructorValue(JsonReader reader, out long? integer, out string errorMessage) + private static bool TryGetDateConstructorValue(JsonReader reader, out long? integer, [NotNullWhen(false)] out string? errorMessage) { integer = null; errorMessage = null; @@ -646,8 +651,9 @@ private static bool TryGetDateConstructorValue(JsonReader reader, out long? inte return false; } - integer = (long)reader.Value; + integer = (long)reader.Value!; return true; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/LateBoundReflectionDelegateFactory.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/LateBoundReflectionDelegateFactory.cs index c5a597385d..835914b7c8 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/LateBoundReflectionDelegateFactory.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/LateBoundReflectionDelegateFactory.cs @@ -33,6 +33,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal class LateBoundReflectionDelegateFactory : ReflectionDelegateFactory { private static readonly LateBoundReflectionDelegateFactory _instance = new LateBoundReflectionDelegateFactory(); @@ -46,18 +47,14 @@ public override ObjectConstructor CreateParameterizedConstructor(MethodB if (method is ConstructorInfo c) { // don't convert to method group to avoid medium trust issues - // https://github.com/JamesNK/Microsoft.IdentityModel.Json/issues/476 - return a => - { - object[] args = a; - return c.Invoke(args); - }; + // https://github.com/JamesNK/Newtonsoft.Json/issues/476 + return a => c.Invoke(a); } - return a => method.Invoke(null, a); + return a => method.Invoke(null, a)!; } - public override MethodCall CreateMethodCall(MethodBase method) + public override MethodCall CreateMethodCall(MethodBase method) { ValidationUtils.ArgumentNotNull(method, nameof(method)); @@ -75,40 +72,45 @@ public override Func CreateDefaultConstructor(Type type) if (type.IsValueType()) { - return () => (T)Activator.CreateInstance(type); + return () => (T)Activator.CreateInstance(type)!; } - ConstructorInfo constructorInfo = ReflectionUtils.GetDefaultConstructor(type, true); + ConstructorInfo? constructorInfo = ReflectionUtils.GetDefaultConstructor(type, true); + if (constructorInfo == null) + { + throw new InvalidOperationException("Unable to find default constructor for " + type.FullName); + } return () => (T)constructorInfo.Invoke(null); } - public override Func CreateGet(PropertyInfo propertyInfo) + public override Func CreateGet(PropertyInfo propertyInfo) { ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo)); return o => propertyInfo.GetValue(o, null); } - public override Func CreateGet(FieldInfo fieldInfo) + public override Func CreateGet(FieldInfo fieldInfo) { ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo)); return o => fieldInfo.GetValue(o); } - public override Action CreateSet(FieldInfo fieldInfo) + public override Action CreateSet(FieldInfo fieldInfo) { ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo)); return (o, v) => fieldInfo.SetValue(o, v); } - public override Action CreateSet(PropertyInfo propertyInfo) + public override Action CreateSet(PropertyInfo propertyInfo) { ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo)); return (o, v) => propertyInfo.SetValue(o, v, null); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/LinqBridge.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/LinqBridge.cs index cafdd36cbd..5df478c550 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/LinqBridge.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/LinqBridge.cs @@ -10,20 +10,20 @@ // // Atif Aziz, http://www.raboof.com // -// This library is free software; you can redistribute it and/or modify it -// under the terms of the New BSD License, a copy of which should have +// This library is free software; you can redistribute it and/or modify it +// under the terms of the New BSD License, a copy of which should have // been delivered along with this distribution. // -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // #endregion @@ -35,10 +35,12 @@ using System.Globalization; using Microsoft.IdentityModel.Json.Serialization; +#nullable disable + namespace Microsoft.IdentityModel.Json.Utilities.LinqBridge { /// - /// Provides a set of static (Shared in Visual Basic) methods for + /// Provides a set of static (Shared in Visual Basic) methods for /// querying objects that implement . /// internal static partial class Enumerable @@ -53,7 +55,7 @@ public static IEnumerable AsEnumerable(IEnumerable so } /// - /// Returns an empty that has the + /// Returns an empty that has the /// specified type argument. /// @@ -63,7 +65,7 @@ public static IEnumerable Empty() } /// - /// Converts the elements of an to the + /// Converts the elements of an to the /// specified type. /// @@ -173,7 +175,7 @@ private static IEnumerable WhereYield( yield return item; } /// - /// Filters a sequence of values based on a predicate. + /// Filters a sequence of values based on a predicate. /// Each element's index is used in the logic of the predicate function. /// @@ -220,7 +222,7 @@ private static IEnumerable SelectYield( } /// - /// Projects each element of a sequence into a new form by + /// Projects each element of a sequence into a new form by /// incorporating the element's index. /// @@ -244,7 +246,7 @@ private static IEnumerable SelectYield( } /// - /// Projects each element of a sequence to an + /// Projects each element of a sequence to an /// and flattens the resulting sequences into one sequence. /// @@ -258,9 +260,9 @@ public static IEnumerable SelectMany( } /// - /// Projects each element of a sequence to an , - /// and flattens the resulting sequences into one sequence. The - /// index of each source element is used in the projected form of + /// Projects each element of a sequence to an , + /// and flattens the resulting sequences into one sequence. The + /// index of each source element is used in the projected form of /// that element. /// @@ -274,8 +276,8 @@ public static IEnumerable SelectMany( } /// - /// Projects each element of a sequence to an , - /// flattens the resulting sequences into one sequence, and invokes + /// Projects each element of a sequence to an , + /// flattens the resulting sequences into one sequence, and invokes /// a result selector function on each element therein. /// @@ -290,10 +292,10 @@ public static IEnumerable SelectMany( } /// - /// Projects each element of a sequence to an , - /// flattens the resulting sequences into one sequence, and invokes - /// a result selector function on each element therein. The index of - /// each source element is used in the intermediate projected form + /// Projects each element of a sequence to an , + /// flattens the resulting sequences into one sequence, and invokes + /// a result selector function on each element therein. The index of + /// each source element is used in the intermediate projected form /// of that element. /// @@ -375,7 +377,7 @@ private static TSource FirstImpl( Func empty) { CheckNotNull(source, "source"); - Debug.Assert(empty != null); + MiscellaneousUtils.Assert(empty != null); var list = source as IList; // optimized case for lists if (list != null) @@ -407,7 +409,7 @@ public static TSource First( } /// - /// Returns the first element of a sequence, or a default value if + /// Returns the first element of a sequence, or a default value if /// the sequence contains no elements. /// @@ -418,7 +420,7 @@ public static TSource FirstOrDefault( } /// - /// Returns the first element of the sequence that satisfies a + /// Returns the first element of the sequence that satisfies a /// condition or a default value if no such element is found. /// @@ -466,7 +468,7 @@ public static TSource Last( } /// - /// Returns the last element of a sequence that satisfies a + /// Returns the last element of a sequence that satisfies a /// specified condition. /// @@ -478,7 +480,7 @@ public static TSource Last( } /// - /// Returns the last element of a sequence, or a default value if + /// Returns the last element of a sequence, or a default value if /// the sequence contains no elements. /// @@ -489,7 +491,7 @@ public static TSource LastOrDefault( } /// - /// Returns the last element of a sequence that satisfies a + /// Returns the last element of a sequence that satisfies a /// condition or a default value if no such element is found. /// @@ -526,7 +528,7 @@ private static TSource SingleImpl( } /// - /// Returns the only element of a sequence, and throws an exception + /// Returns the only element of a sequence, and throws an exception /// if there is not exactly one element in the sequence. /// @@ -537,8 +539,8 @@ public static TSource Single( } /// - /// Returns the only element of a sequence that satisfies a - /// specified condition, and throws an exception if more than one + /// Returns the only element of a sequence that satisfies a + /// specified condition, and throws an exception if more than one /// such element exists. /// @@ -550,8 +552,8 @@ public static TSource Single( } /// - /// Returns the only element of a sequence, or a default value if - /// the sequence is empty; this method throws an exception if there + /// Returns the only element of a sequence, or a default value if + /// the sequence is empty; this method throws an exception if there /// is more than one element in the sequence. /// @@ -562,9 +564,9 @@ public static TSource SingleOrDefault( } /// - /// Returns the only element of a sequence that satisfies a - /// specified condition or a default value if no such element - /// exists; this method throws an exception if more than one element + /// Returns the only element of a sequence that satisfies a + /// specified condition or a default value if no such element + /// exists; this method throws an exception if more than one element /// satisfies the condition. /// @@ -603,7 +605,7 @@ public static TSource ElementAt( } /// - /// Returns the element at a specified index in a sequence or a + /// Returns the element at a specified index in a sequence or a /// default value if the index is out of range. /// @@ -644,7 +646,7 @@ private static IEnumerable ReverseYield(IEnumerable s } /// - /// Returns a specified number of contiguous elements from the start + /// Returns a specified number of contiguous elements from the start /// of a sequence. /// @@ -656,7 +658,7 @@ public static IEnumerable Take( } /// - /// Bypasses a specified number of elements in a sequence and then + /// Bypasses a specified number of elements in a sequence and then /// returns the remaining elements. /// @@ -668,7 +670,7 @@ public static IEnumerable Skip( } /// - /// Bypasses elements in a sequence as long as a specified condition + /// Bypasses elements in a sequence as long as a specified condition /// is true and then returns the remaining elements. /// @@ -682,8 +684,8 @@ public static IEnumerable SkipWhile( } /// - /// Bypasses elements in a sequence as long as a specified condition - /// is true and then returns the remaining elements. The element's + /// Bypasses elements in a sequence as long as a specified condition + /// is true and then returns the remaining elements. The element's /// index is used in the logic of the predicate function. /// @@ -747,7 +749,7 @@ public static int Count( } /// - /// Returns a number that represents how many elements in the + /// Returns a number that represents how many elements in the /// specified sequence satisfy a condition. /// @@ -842,7 +844,7 @@ public static TSource[] ToArray( } /// - /// Returns distinct elements from a sequence by using the default + /// Returns distinct elements from a sequence by using the default /// equality comparer to compare values. /// @@ -853,7 +855,7 @@ public static IEnumerable Distinct( } /// - /// Returns distinct elements from a sequence by using a specified + /// Returns distinct elements from a sequence by using a specified /// to compare values. /// @@ -893,8 +895,8 @@ private static IEnumerable DistinctYield( } /// - /// Creates a from an - /// according to a specified key + /// Creates a from an + /// according to a specified key /// selector function. /// @@ -906,8 +908,8 @@ public static ILookup ToLookup( } /// - /// Creates a from an - /// according to a specified key + /// Creates a from an + /// according to a specified key /// selector function and a key comparer. /// @@ -920,8 +922,8 @@ public static ILookup ToLookup( } /// - /// Creates a from an - /// according to specified key + /// Creates a from an + /// according to specified key /// and element selector functions. /// @@ -934,8 +936,8 @@ public static ILookup ToLookup( } /// - /// Creates a from an - /// according to a specified key + /// Creates a from an + /// according to a specified key /// selector function, a comparer and an element selector function. /// @@ -969,7 +971,7 @@ public static ILookup ToLookup( } /// - /// Groups the elements of a sequence according to a specified key + /// Groups the elements of a sequence according to a specified key /// selector function. /// @@ -981,8 +983,8 @@ public static IEnumerable> GroupBy( } /// - /// Groups the elements of a sequence according to a specified key - /// selector function and compares the keys by using a specified + /// Groups the elements of a sequence according to a specified key + /// selector function and compares the keys by using a specified /// comparer. /// @@ -995,8 +997,8 @@ public static IEnumerable> GroupBy( } /// - /// Groups the elements of a sequence according to a specified key - /// selector function and projects the elements for each group by + /// Groups the elements of a sequence according to a specified key + /// selector function and projects the elements for each group by /// using a specified function. /// @@ -1009,8 +1011,8 @@ public static IEnumerable> GroupBy - /// Groups the elements of a sequence according to a specified key - /// selector function and creates a result value from each group and + /// Groups the elements of a sequence according to a specified key + /// selector function and creates a result value from each group and /// its key. /// @@ -1028,8 +1030,8 @@ public static IEnumerable> GroupBy - /// Groups the elements of a sequence according to a key selector - /// function. The keys are compared by using a comparer and each + /// Groups the elements of a sequence according to a key selector + /// function. The keys are compared by using a comparer and each /// group's elements are projected by using a specified function. /// @@ -1042,9 +1044,9 @@ public static IEnumerable GroupBy( } /// - /// Groups the elements of a sequence according to a specified key - /// selector function and creates a result value from each group and - /// its key. The elements of each group are projected by using a + /// Groups the elements of a sequence according to a specified key + /// selector function and creates a result value from each group and + /// its key. The elements of each group are projected by using a /// specified function. /// @@ -1062,8 +1064,8 @@ public static IEnumerable GroupBy( } /// - /// Groups the elements of a sequence according to a specified key - /// selector function and creates a result value from each group and + /// Groups the elements of a sequence according to a specified key + /// selector function and creates a result value from each group and /// its key. The keys are compared by using a specified comparer. /// @@ -1077,10 +1079,10 @@ public static IEnumerable GroupBy( } /// - /// Groups the elements of a sequence according to a specified key - /// selector function and creates a result value from each group and - /// its key. Key values are compared by using a specified comparer, - /// and the elements of each group are projected by using a + /// Groups the elements of a sequence according to a specified key + /// selector function and creates a result value from each group and + /// its key. Key values are compared by using a specified comparer, + /// and the elements of each group are projected by using a /// specified function. /// @@ -1121,7 +1123,7 @@ public static TSource Aggregate( } /// - /// Applies an accumulator function over a sequence. The specified + /// Applies an accumulator function over a sequence. The specified /// seed value is used as the initial accumulator value. /// @@ -1134,8 +1136,8 @@ public static TAccumulate Aggregate( } /// - /// Applies an accumulator function over a sequence. The specified - /// seed value is used as the initial accumulator value, and the + /// Applies an accumulator function over a sequence. The specified + /// seed value is used as the initial accumulator value, and the /// specified function is used to select the result value. /// @@ -1158,7 +1160,7 @@ public static TResult Aggregate( } /// - /// Produces the set union of two sequences by using the default + /// Produces the set union of two sequences by using the default /// equality comparer. /// @@ -1170,7 +1172,7 @@ public static IEnumerable Union( } /// - /// Produces the set union of two sequences by using a specified + /// Produces the set union of two sequences by using a specified /// . /// @@ -1183,8 +1185,8 @@ public static IEnumerable Union( } /// - /// Returns the elements of the specified sequence or the type - /// parameter's default value in a singleton collection if the + /// Returns the elements of the specified sequence or the type + /// parameter's default value in a singleton collection if the /// sequence is empty. /// @@ -1195,7 +1197,7 @@ public static IEnumerable DefaultIfEmpty( } /// - /// Returns the elements of the specified sequence or the specified + /// Returns the elements of the specified sequence or the specified /// value in a singleton collection if the sequence is empty. /// @@ -1256,7 +1258,7 @@ public static bool Any( } /// - /// Determines whether any element of a sequence satisfies a + /// Determines whether any element of a sequence satisfies a /// condition. /// @@ -1276,7 +1278,7 @@ public static bool Any( } /// - /// Determines whether a sequence contains a specified element by + /// Determines whether a sequence contains a specified element by /// using the default equality comparer. /// @@ -1288,7 +1290,7 @@ public static bool Contains( } /// - /// Determines whether a sequence contains a specified element by + /// Determines whether a sequence contains a specified element by /// using a specified . /// @@ -1311,7 +1313,7 @@ public static bool Contains( } /// - /// Determines whether two sequences are equal by comparing the + /// Determines whether two sequences are equal by comparing the /// elements by using the default equality comparer for their type. /// @@ -1323,7 +1325,7 @@ public static bool SequenceEqual( } /// - /// Determines whether two sequences are equal by comparing their + /// Determines whether two sequences are equal by comparing their /// elements by using a specified . /// @@ -1362,7 +1364,7 @@ private static TSource MinMaxImpl( Func lesser) { CheckNotNull(source, "source"); - Debug.Assert(lesser != null); + MiscellaneousUtils.Assert(lesser != null); return source.Aggregate((a, item) => lesser(a, item) ? a : item); } @@ -1376,7 +1378,7 @@ private static TSource MinMaxImpl( TSource? seed, Func lesser) where TSource : struct { CheckNotNull(source, "source"); - Debug.Assert(lesser != null); + MiscellaneousUtils.Assert(lesser != null); return source.Aggregate(seed, (a, item) => lesser(a, item) ? a : item); // == MinMaxImpl(Repeat(null, 1).Concat(source), lesser); @@ -1394,7 +1396,7 @@ public static TSource Min( } /// - /// Invokes a transform function on each element of a generic + /// Invokes a transform function on each element of a generic /// sequence and returns the minimum resulting value. /// @@ -1417,7 +1419,7 @@ public static TSource Max( } /// - /// Invokes a transform function on each element of a generic + /// Invokes a transform function on each element of a generic /// sequence and returns the maximum resulting value. /// @@ -1440,7 +1442,7 @@ public static TResult Max( private static IEnumerable Renumerable(this IEnumerator e) { - Debug.Assert(e != null); + MiscellaneousUtils.Assert(e != null); do { @@ -1460,7 +1462,7 @@ public static IOrderedEnumerable OrderBy( } /// - /// Sorts the elements of a sequence in ascending order by using a + /// Sorts the elements of a sequence in ascending order by using a /// specified comparer. /// @@ -1487,8 +1489,8 @@ public static IOrderedEnumerable OrderByDescending( } /// - /// Sorts the elements of a sequence in descending order by using a - /// specified comparer. + /// Sorts the elements of a sequence in descending order by using a + /// specified comparer. /// public static IOrderedEnumerable OrderByDescending( @@ -1503,7 +1505,7 @@ public static IOrderedEnumerable OrderByDescending( } /// - /// Performs a subsequent ordering of the elements in a sequence in + /// Performs a subsequent ordering of the elements in a sequence in /// ascending order according to a key. /// @@ -1515,7 +1517,7 @@ public static IOrderedEnumerable ThenBy( } /// - /// Performs a subsequent ordering of the elements in a sequence in + /// Performs a subsequent ordering of the elements in a sequence in /// ascending order by using a specified comparer. /// @@ -1530,7 +1532,7 @@ public static IOrderedEnumerable ThenBy( } /// - /// Performs a subsequent ordering of the elements in a sequence in + /// Performs a subsequent ordering of the elements in a sequence in /// descending order, according to a key. /// @@ -1542,7 +1544,7 @@ public static IOrderedEnumerable ThenByDescending( } /// - /// Performs a subsequent ordering of the elements in a sequence in + /// Performs a subsequent ordering of the elements in a sequence in /// descending order by using a specified comparer. /// @@ -1582,7 +1584,7 @@ private static IEnumerable IntersectExceptImpl( flags[item] = flag; // - // As per docs, "the marked elements are yielded in the order in + // As per docs, "the marked elements are yielded in the order in // which they were collected. // @@ -1590,7 +1592,7 @@ private static IEnumerable IntersectExceptImpl( } /// - /// Produces the set intersection of two sequences by using the + /// Produces the set intersection of two sequences by using the /// default equality comparer to compare values. /// @@ -1602,7 +1604,7 @@ public static IEnumerable Intersect( } /// - /// Produces the set intersection of two sequences by using the + /// Produces the set intersection of two sequences by using the /// specified to compare values. /// @@ -1615,7 +1617,7 @@ public static IEnumerable Intersect( } /// - /// Produces the set difference of two sequences by using the + /// Produces the set difference of two sequences by using the /// default equality comparer to compare values. /// @@ -1627,7 +1629,7 @@ public static IEnumerable Except( } /// - /// Produces the set difference of two sequences by using the + /// Produces the set difference of two sequences by using the /// specified to compare values. /// @@ -1640,8 +1642,8 @@ public static IEnumerable Except( } /// - /// Creates a from an - /// according to a specified key + /// Creates a from an + /// according to a specified key /// selector function. /// @@ -1653,8 +1655,8 @@ public static Dictionary ToDictionary( } /// - /// Creates a from an - /// according to a specified key + /// Creates a from an + /// according to a specified key /// selector function and key comparer. /// @@ -1667,8 +1669,8 @@ public static Dictionary ToDictionary( } /// - /// Creates a from an - /// according to specified key + /// Creates a from an + /// according to specified key /// selector and element selector functions. /// @@ -1681,8 +1683,8 @@ public static Dictionary ToDictionary( } /// - /// Creates a from an - /// according to a specified key + /// Creates a from an + /// according to a specified key /// selector function, a comparer, and an element selector function. /// @@ -1702,8 +1704,8 @@ public static Dictionary ToDictionary( { // // ToDictionary is meant to throw ArgumentNullException if - // keySelector produces a key that is null and - // Argument exception if keySelector produces duplicate keys + // keySelector produces a key that is null and + // Argument exception if keySelector produces duplicate keys // for two elements. Incidentally, the documentation for // IDictionary.Add says that the Add method // throws the same exceptions under the same circumstances @@ -1719,7 +1721,7 @@ public static Dictionary ToDictionary( } /// - /// Correlates the elements of two sequences based on matching keys. + /// Correlates the elements of two sequences based on matching keys. /// The default equality comparer is used to compare keys. /// @@ -1734,8 +1736,8 @@ public static IEnumerable Join( } /// - /// Correlates the elements of two sequences based on matching keys. - /// The default equality comparer is used to compare keys. A + /// Correlates the elements of two sequences based on matching keys. + /// The default equality comparer is used to compare keys. A /// specified is used to compare keys. /// @@ -1762,8 +1764,8 @@ from i in lookup[outerKeySelector(o)] } /// - /// Correlates the elements of two sequences based on equality of - /// keys and groups the results. The default equality comparer is + /// Correlates the elements of two sequences based on equality of + /// keys and groups the results. The default equality comparer is /// used to compare keys. /// @@ -1778,9 +1780,9 @@ public static IEnumerable GroupJoin( } /// - /// Correlates the elements of two sequences based on equality of - /// keys and groups the results. The default equality comparer is - /// used to compare keys. A specified + /// Correlates the elements of two sequences based on equality of + /// keys and groups the results. The default equality comparer is + /// used to compare keys. A specified /// is used to compare keys. /// @@ -1845,7 +1847,7 @@ public static int Sum( /// /// Computes the sum of a sequence of - /// values that are obtained by invoking a transform function on + /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// @@ -1883,7 +1885,7 @@ public static double Average( /// /// Computes the average of a sequence of values - /// that are obtained by invoking a transform function on each + /// that are obtained by invoking a transform function on each /// element of the input sequence. /// @@ -1913,7 +1915,7 @@ public static double Average( /// /// Computes the sum of a sequence of nullable - /// values that are obtained by invoking a transform function on + /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// @@ -1951,7 +1953,7 @@ public static double Average( /// /// Computes the average of a sequence of nullable values - /// that are obtained by invoking a transform function on each + /// that are obtained by invoking a transform function on each /// element of the input sequence. /// @@ -1963,7 +1965,7 @@ public static double Average( } /// - /// Returns the minimum value in a sequence of nullable + /// Returns the minimum value in a sequence of nullable /// values. /// @@ -1976,7 +1978,7 @@ public static double Average( } /// - /// Invokes a transform function on each element of a sequence and + /// Invokes a transform function on each element of a sequence and /// returns the minimum nullable value. /// @@ -1988,7 +1990,7 @@ public static double Average( } /// - /// Returns the maximum value in a sequence of nullable + /// Returns the maximum value in a sequence of nullable /// values. /// @@ -2002,7 +2004,7 @@ public static double Average( } /// - /// Invokes a transform function on each element of a sequence and + /// Invokes a transform function on each element of a sequence and /// returns the maximum nullable value. /// @@ -2031,7 +2033,7 @@ public static long Sum( /// /// Computes the sum of a sequence of - /// values that are obtained by invoking a transform function on + /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// @@ -2069,7 +2071,7 @@ public static double Average( /// /// Computes the average of a sequence of values - /// that are obtained by invoking a transform function on each + /// that are obtained by invoking a transform function on each /// element of the input sequence. /// @@ -2099,7 +2101,7 @@ public static double Average( /// /// Computes the sum of a sequence of nullable - /// values that are obtained by invoking a transform function on + /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// @@ -2137,7 +2139,7 @@ public static double Average( /// /// Computes the average of a sequence of nullable values - /// that are obtained by invoking a transform function on each + /// that are obtained by invoking a transform function on each /// element of the input sequence. /// @@ -2149,7 +2151,7 @@ public static double Average( } /// - /// Returns the minimum value in a sequence of nullable + /// Returns the minimum value in a sequence of nullable /// values. /// @@ -2162,7 +2164,7 @@ public static double Average( } /// - /// Invokes a transform function on each element of a sequence and + /// Invokes a transform function on each element of a sequence and /// returns the minimum nullable value. /// @@ -2174,7 +2176,7 @@ public static double Average( } /// - /// Returns the maximum value in a sequence of nullable + /// Returns the maximum value in a sequence of nullable /// values. /// @@ -2188,7 +2190,7 @@ public static double Average( } /// - /// Invokes a transform function on each element of a sequence and + /// Invokes a transform function on each element of a sequence and /// returns the maximum nullable value. /// @@ -2217,7 +2219,7 @@ public static float Sum( /// /// Computes the sum of a sequence of - /// values that are obtained by invoking a transform function on + /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// @@ -2255,7 +2257,7 @@ public static float Average( /// /// Computes the average of a sequence of values - /// that are obtained by invoking a transform function on each + /// that are obtained by invoking a transform function on each /// element of the input sequence. /// @@ -2285,7 +2287,7 @@ public static float Average( /// /// Computes the sum of a sequence of nullable - /// values that are obtained by invoking a transform function on + /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// @@ -2323,7 +2325,7 @@ public static float Average( /// /// Computes the average of a sequence of nullable values - /// that are obtained by invoking a transform function on each + /// that are obtained by invoking a transform function on each /// element of the input sequence. /// @@ -2335,7 +2337,7 @@ public static float Average( } /// - /// Returns the minimum value in a sequence of nullable + /// Returns the minimum value in a sequence of nullable /// values. /// @@ -2348,7 +2350,7 @@ public static float Average( } /// - /// Invokes a transform function on each element of a sequence and + /// Invokes a transform function on each element of a sequence and /// returns the minimum nullable value. /// @@ -2360,7 +2362,7 @@ public static float Average( } /// - /// Returns the maximum value in a sequence of nullable + /// Returns the maximum value in a sequence of nullable /// values. /// @@ -2374,7 +2376,7 @@ public static float Average( } /// - /// Invokes a transform function on each element of a sequence and + /// Invokes a transform function on each element of a sequence and /// returns the maximum nullable value. /// @@ -2403,7 +2405,7 @@ public static double Sum( /// /// Computes the sum of a sequence of - /// values that are obtained by invoking a transform function on + /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// @@ -2441,7 +2443,7 @@ public static double Average( /// /// Computes the average of a sequence of values - /// that are obtained by invoking a transform function on each + /// that are obtained by invoking a transform function on each /// element of the input sequence. /// @@ -2471,7 +2473,7 @@ public static double Average( /// /// Computes the sum of a sequence of nullable - /// values that are obtained by invoking a transform function on + /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// @@ -2509,7 +2511,7 @@ public static double Average( /// /// Computes the average of a sequence of nullable values - /// that are obtained by invoking a transform function on each + /// that are obtained by invoking a transform function on each /// element of the input sequence. /// @@ -2521,7 +2523,7 @@ public static double Average( } /// - /// Returns the minimum value in a sequence of nullable + /// Returns the minimum value in a sequence of nullable /// values. /// @@ -2534,7 +2536,7 @@ public static double Average( } /// - /// Invokes a transform function on each element of a sequence and + /// Invokes a transform function on each element of a sequence and /// returns the minimum nullable value. /// @@ -2546,7 +2548,7 @@ public static double Average( } /// - /// Returns the maximum value in a sequence of nullable + /// Returns the maximum value in a sequence of nullable /// values. /// @@ -2560,7 +2562,7 @@ public static double Average( } /// - /// Invokes a transform function on each element of a sequence and + /// Invokes a transform function on each element of a sequence and /// returns the maximum nullable value. /// @@ -2589,7 +2591,7 @@ public static decimal Sum( /// /// Computes the sum of a sequence of - /// values that are obtained by invoking a transform function on + /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// @@ -2636,7 +2638,7 @@ public static decimal Average( /// /// Computes the average of a sequence of values - /// that are obtained by invoking a transform function on each + /// that are obtained by invoking a transform function on each /// element of the input sequence. /// @@ -2666,7 +2668,7 @@ public static decimal Average( /// /// Computes the sum of a sequence of nullable - /// values that are obtained by invoking a transform function on + /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// @@ -2704,7 +2706,7 @@ public static decimal Average( /// /// Computes the average of a sequence of nullable values - /// that are obtained by invoking a transform function on each + /// that are obtained by invoking a transform function on each /// element of the input sequence. /// @@ -2716,7 +2718,7 @@ public static decimal Average( } /// - /// Returns the minimum value in a sequence of nullable + /// Returns the minimum value in a sequence of nullable /// values. /// @@ -2729,7 +2731,7 @@ public static decimal Average( } /// - /// Invokes a transform function on each element of a sequence and + /// Invokes a transform function on each element of a sequence and /// returns the minimum nullable value. /// @@ -2741,7 +2743,7 @@ public static decimal Average( } /// - /// Returns the maximum value in a sequence of nullable + /// Returns the maximum value in a sequence of nullable /// values. /// @@ -2755,7 +2757,7 @@ public static decimal Average( } /// - /// Invokes a transform function on each element of a sequence and + /// Invokes a transform function on each element of a sequence and /// returns the maximum nullable value. /// @@ -2780,8 +2782,8 @@ internal partial interface IGrouping : IEnumerable } /// - /// Defines an indexer, size property, and Boolean search method for - /// data structures that map keys to + /// Defines an indexer, size property, and Boolean search method for + /// data structures that map keys to /// sequences of values. /// internal partial interface ILookup : IEnumerable> @@ -2797,7 +2799,7 @@ internal partial interface ILookup : IEnumerable : IEnumerable { /// - /// Performs a subsequent ordering on the elements of an + /// Performs a subsequent ordering on the elements of an /// according to a key. /// @@ -2857,7 +2859,7 @@ public bool Contains(TKey key) } /// - /// Applies a transform function to each key and its associated + /// Applies a transform function to each key and its associated /// values and returns the results. /// @@ -2925,11 +2927,11 @@ public IOrderedEnumerable CreateOrderedEnumerable( public IEnumerator GetEnumerator() { // - // We sort using List.Sort, but docs say that it performs an - // unstable sort. LINQ, on the other hand, says OrderBy performs - // a stable sort. So convert the source sequence into a sequence - // of tuples where the second element tags the position of the - // element from the source sequence (First). The position is + // We sort using List.Sort, but docs say that it performs an + // unstable sort. LINQ, on the other hand, says OrderBy performs + // a stable sort. So convert the source sequence into a sequence + // of tuples where the second element tags the position of the + // element from the source sequence (First). The position is // then used as a tie breaker when all keys compare equal, // thus making the sort stable. // @@ -2964,7 +2966,7 @@ public IEnumerator GetEnumerator() /// /// See issue #11 - /// for why this method is needed and cannot be expressed as a + /// for why this method is needed and cannot be expressed as a /// lambda at the call site. /// @@ -2975,7 +2977,7 @@ private static Tuple TagPosition(T e, int i) /// /// See issue #11 - /// for why this method is needed and cannot be expressed as a + /// for why this method is needed and cannot be expressed as a /// lambda at the call site. /// @@ -3056,11 +3058,11 @@ namespace Microsoft.IdentityModel.Json.Serialization namespace System.Runtime.CompilerServices { /// - /// This attribute allows us to define extension methods without + /// This attribute allows us to define extension methods without /// requiring .NET Framework 3.5. For more information, see the section, /// Extension Methods in .NET Framework 2.0 Apps, /// of Basic Instincts: Extension Methods - /// column in MSDN Magazine, + /// column in MSDN Magazine, /// issue Nov 2007. /// @@ -3068,4 +3070,4 @@ namespace System.Runtime.CompilerServices internal sealed class ExtensionAttribute : Attribute { } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/MethodBinder.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/MethodBinder.cs index e82fb1b658..7903c6afc0 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/MethodBinder.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/MethodBinder.cs @@ -126,7 +126,7 @@ private static bool FilterParameters(ParameterInfo[] parameters, IList typ } // check if the last parameter is ParamArray - Type paramArrayType = null; + Type? paramArrayType = null; if (enableParamArray) { @@ -211,7 +211,7 @@ public int Compare(ParameterInfo[] parameters1, ParameterInfo[] parameters2) return 1; } - Type paramArrayType1 = null, paramArrayType2 = null; + Type? paramArrayType1 = null, paramArrayType2 = null; if (_enableParamArray) { diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/MethodCall.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/MethodCall.cs index 38f72a15ee..3258b35b2c 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/MethodCall.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/MethodCall.cs @@ -25,5 +25,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { - internal delegate TResult MethodCall(T target, params object[] args); -} \ No newline at end of file +#nullable enable + internal delegate TResult MethodCall(T target, params object?[] args); +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/MiscellaneousUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/MiscellaneousUtils.cs index 574944846e..ee9c458104 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/MiscellaneousUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/MiscellaneousUtils.cs @@ -31,14 +31,23 @@ using System.Text; using System.Globalization; using System.Text.RegularExpressions; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal delegate T Creator(); internal static class MiscellaneousUtils { - public static bool ValueEquals(object objA, object objB) + [Conditional("DEBUG")] + public static void Assert([DoesNotReturnIf(false)] bool condition, string? message = null) + { + Debug.Assert(condition, message); + } + + public static bool ValueEquals(object? objA, object? objB) { if (objA == objB) { @@ -77,14 +86,14 @@ public static ArgumentOutOfRangeException CreateArgumentOutOfRangeException(stri return new ArgumentOutOfRangeException(paramName, newMessage); } - public static string ToString(object value) + public static string ToString(object? value) { if (value == null) { return "{null}"; } - return (value is string s) ? @"""" + s + @"""" : value.ToString(); + return (value is string s) ? @"""" + s + @"""" : value!.ToString()!; } public static int ByteArrayCompare(byte[] a1, byte[] a2) @@ -107,9 +116,9 @@ public static int ByteArrayCompare(byte[] a1, byte[] a2) return 0; } - public static string GetPrefix(string qualifiedName) + public static string? GetPrefix(string qualifiedName) { - GetQualifiedNameParts(qualifiedName, out string prefix, out _); + GetQualifiedNameParts(qualifiedName, out string? prefix, out _); return prefix; } @@ -121,9 +130,9 @@ public static string GetLocalName(string qualifiedName) return localName; } - public static void GetQualifiedNameParts(string qualifiedName, out string prefix, out string localName) + public static void GetQualifiedNameParts(string qualifiedName, out string? prefix, out string localName) { - int colonPosition = qualifiedName.IndexOf(':'); + int colonPosition = StringUtils.IndexOf(qualifiedName, ':'); if ((colonPosition == -1 || colonPosition == 0) || (qualifiedName.Length - 1) == colonPosition) { @@ -140,9 +149,10 @@ public static void GetQualifiedNameParts(string qualifiedName, out string prefix internal static RegexOptions GetRegexOptions(string optionsText) { RegexOptions options = RegexOptions.None; - foreach (char c in optionsText) + + for (int i = 0; i < optionsText.Length; i++) { - switch (c) + switch (optionsText[i]) { case 'i': options |= RegexOptions.IgnoreCase; @@ -162,4 +172,5 @@ internal static RegexOptions GetRegexOptions(string optionsText) return options; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/NullableAttributes.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/NullableAttributes.cs new file mode 100644 index 0000000000..5733cb801a --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/NullableAttributes.cs @@ -0,0 +1,78 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if !HAVE_NULLABLE_ATTRIBUTES + +namespace System.Diagnostics.CodeAnalysis +{ + /// Specifies that an output will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true)] + internal sealed class NotNullAttribute : Attribute { } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)] + internal sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + internal sealed class MaybeNullAttribute : Attribute + { } + + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + internal sealed class AllowNullAttribute : Attribute + { } + + /// + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + /// + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal class DoesNotReturnIfAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => this.ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } +} + +#endif \ No newline at end of file diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ReflectionDelegateFactory.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ReflectionDelegateFactory.cs index deed56f7e0..c27263e766 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ReflectionDelegateFactory.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ReflectionDelegateFactory.cs @@ -34,9 +34,10 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal abstract class ReflectionDelegateFactory { - public Func CreateGet(MemberInfo memberInfo) + public Func CreateGet(MemberInfo memberInfo) { if (memberInfo is PropertyInfo propertyInfo) { @@ -54,12 +55,10 @@ public Func CreateGet(MemberInfo memberInfo) return CreateGet(fieldInfo); } -#pragma warning disable CA2201 // Do not raise reserved exception types throw new Exception("Could not create getter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo)); -#pragma warning restore CA2201 // Do not raise reserved exception types } - public Action CreateSet(MemberInfo memberInfo) + public Action CreateSet(MemberInfo memberInfo) { if (memberInfo is PropertyInfo propertyInfo) { @@ -71,17 +70,16 @@ public Action CreateSet(MemberInfo memberInfo) return CreateSet(fieldInfo); } -#pragma warning disable CA2201 // Do not raise reserved exception types throw new Exception("Could not create setter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo)); -#pragma warning restore CA2201 // Do not raise reserved exception types } - public abstract MethodCall CreateMethodCall(MethodBase method); + public abstract MethodCall CreateMethodCall(MethodBase method); public abstract ObjectConstructor CreateParameterizedConstructor(MethodBase method); public abstract Func CreateDefaultConstructor(Type type); - public abstract Func CreateGet(PropertyInfo propertyInfo); - public abstract Func CreateGet(FieldInfo fieldInfo); - public abstract Action CreateSet(FieldInfo fieldInfo); - public abstract Action CreateSet(PropertyInfo propertyInfo); + public abstract Func CreateGet(PropertyInfo propertyInfo); + public abstract Func CreateGet(FieldInfo fieldInfo); + public abstract Action CreateSet(FieldInfo fieldInfo); + public abstract Action CreateSet(PropertyInfo propertyInfo); } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ReflectionObject.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ReflectionObject.cs index f0ae29da17..b6d508d6eb 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ReflectionObject.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ReflectionObject.cs @@ -37,39 +37,40 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal class ReflectionMember { - public Type MemberType { get; set; } - public Func Getter { get; set; } - public Action Setter { get; set; } + public Type? MemberType { get; set; } + public Func? Getter { get; set; } + public Action? Setter { get; set; } } internal class ReflectionObject { - public ObjectConstructor Creator { get; } + public ObjectConstructor? Creator { get; } public IDictionary Members { get; } - private ReflectionObject(ObjectConstructor creator) + private ReflectionObject(ObjectConstructor? creator) { Members = new Dictionary(); Creator = creator; } - public object GetValue(object target, string member) + public object? GetValue(object target, string member) { - Func getter = Members[member].Getter; + Func getter = Members[member].Getter!; return getter(target); } - public void SetValue(object target, string member, object value) + public void SetValue(object target, string member, object? value) { - Action setter = Members[member].Setter; + Action setter = Members[member].Setter!; setter(target, value); } public Type GetType(string member) { - return Members[member].MemberType; + return Members[member].MemberType!; } public static ReflectionObject Create(Type t, params string[] memberNames) @@ -77,11 +78,11 @@ public static ReflectionObject Create(Type t, params string[] memberNames) return Create(t, null, memberNames); } - public static ReflectionObject Create(Type t, MethodBase creator, params string[] memberNames) + public static ReflectionObject Create(Type t, MethodBase? creator, params string[] memberNames) { ReflectionDelegateFactory delegateFactory = JsonTypeReflector.ReflectionDelegateFactory; - ObjectConstructor creatorConstructor = null; + ObjectConstructor? creatorConstructor = null; if (creator != null) { creatorConstructor = delegateFactory.CreateParameterizedConstructor(creator); @@ -131,12 +132,12 @@ public static ReflectionObject Create(Type t, MethodBase creator, params string[ ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 0 && method.ReturnType != typeof(void)) { - MethodCall call = delegateFactory.CreateMethodCall(method); + MethodCall call = delegateFactory.CreateMethodCall(method); reflectionMember.Getter = target => call(target); } else if (parameters.Length == 1 && method.ReturnType == typeof(void)) { - MethodCall call = delegateFactory.CreateMethodCall(method); + MethodCall call = delegateFactory.CreateMethodCall(method); reflectionMember.Setter = (target, arg) => call(target, arg); } } @@ -145,16 +146,6 @@ public static ReflectionObject Create(Type t, MethodBase creator, params string[ throw new ArgumentException("Unexpected member type '{0}' for member '{1}'.".FormatWith(CultureInfo.InvariantCulture, member.MemberType(), member.Name)); } - if (ReflectionUtils.CanReadMemberValue(member, false)) - { - reflectionMember.Getter = delegateFactory.CreateGet(member); - } - - if (ReflectionUtils.CanSetMemberValue(member, false, false)) - { - reflectionMember.Setter = delegateFactory.CreateSet(member); - } - reflectionMember.MemberType = ReflectionUtils.GetMemberUnderlyingType(member); d.Members[memberName] = reflectionMember; @@ -163,4 +154,5 @@ public static ReflectionObject Create(Type t, MethodBase creator, params string[ return d; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ReflectionUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ReflectionUtils.cs index 66ea8a095e..1f6293da93 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ReflectionUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ReflectionUtils.cs @@ -32,6 +32,8 @@ using System.Collections; using System.Globalization; using System.Text; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else @@ -41,6 +43,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable #if (DOTNET || PORTABLE || PORTABLE40) && !NETSTANDARD2_0 [Flags] internal enum MemberTypes @@ -96,7 +99,7 @@ public static bool IsVirtual(this PropertyInfo propertyInfo) { ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo)); - MethodInfo m = propertyInfo.GetGetMethod(true); + MethodInfo? m = propertyInfo.GetGetMethod(true); if (m != null && m.IsVirtual) { return true; @@ -111,11 +114,11 @@ public static bool IsVirtual(this PropertyInfo propertyInfo) return false; } - public static MethodInfo GetBaseDefinition(this PropertyInfo propertyInfo) + public static MethodInfo? GetBaseDefinition(this PropertyInfo propertyInfo) { ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo)); - MethodInfo m = propertyInfo.GetGetMethod(true); + MethodInfo? m = propertyInfo.GetGetMethod(true); if (m != null) { return m.GetBaseDefinition(); @@ -126,11 +129,13 @@ public static MethodInfo GetBaseDefinition(this PropertyInfo propertyInfo) public static bool IsPublic(PropertyInfo property) { - if (property.GetGetMethod() != null && property.GetGetMethod().IsPublic) + var getMethod = property.GetGetMethod(); + if (getMethod != null && getMethod.IsPublic) { return true; } - if (property.GetSetMethod() != null && property.GetSetMethod().IsPublic) + var setMethod = property.GetSetMethod(); + if (setMethod != null && setMethod.IsPublic) { return true; } @@ -138,12 +143,12 @@ public static bool IsPublic(PropertyInfo property) return false; } - public static Type GetObjectType(object v) + public static Type? GetObjectType(object? v) { return v?.GetType(); } - public static string GetTypeName(Type t, TypeNameAssemblyFormatHandling assemblyFormat, ISerializationBinder binder) + public static string GetTypeName(Type t, TypeNameAssemblyFormatHandling assemblyFormat, ISerializationBinder? binder) { string fullyQualifiedTypeName = GetFullyQualifiedTypeName(t, binder); @@ -158,11 +163,11 @@ public static string GetTypeName(Type t, TypeNameAssemblyFormatHandling assembly } } - private static string GetFullyQualifiedTypeName(Type t, ISerializationBinder binder) + private static string GetFullyQualifiedTypeName(Type t, ISerializationBinder? binder) { if (binder != null) { - binder.BindToName(t, out string assemblyName, out string typeName); + binder.BindToName(t, out string? assemblyName, out string? typeName); #if (NET20 || NET35) // for older SerializationBinder implementations that didn't have BindToName if (assemblyName == null & typeName == null) @@ -173,7 +178,7 @@ private static string GetFullyQualifiedTypeName(Type t, ISerializationBinder bin return typeName + (assemblyName == null ? "" : ", " + assemblyName); } - return t.AssemblyQualifiedName; + return t.AssemblyQualifiedName!; } private static string RemoveAssemblyDetails(string fullyQualifiedTypeName) @@ -183,6 +188,7 @@ private static string RemoveAssemblyDetails(string fullyQualifiedTypeName) // loop through the type name and filter out qualified assembly details from nested type names bool writingAssemblyName = false; bool skippingAssemblyDetails = false; + bool followBrackets = false; for (int i = 0; i < fullyQualifiedTypeName.Length; i++) { char current = fullyQualifiedTypeName[i]; @@ -191,15 +197,21 @@ private static string RemoveAssemblyDetails(string fullyQualifiedTypeName) case '[': writingAssemblyName = false; skippingAssemblyDetails = false; + followBrackets = true; builder.Append(current); break; case ']': writingAssemblyName = false; skippingAssemblyDetails = false; + followBrackets = false; builder.Append(current); break; case ',': - if (!writingAssemblyName) + if (followBrackets) + { + builder.Append(current); + } + else if (!writingAssemblyName) { writingAssemblyName = true; builder.Append(current); @@ -210,6 +222,7 @@ private static string RemoveAssemblyDetails(string fullyQualifiedTypeName) } break; default: + followBrackets = false; if (!skippingAssemblyDetails) { builder.Append(current); @@ -233,12 +246,12 @@ public static bool HasDefaultConstructor(Type t, bool nonPublic) return (GetDefaultConstructor(t, nonPublic) != null); } - public static ConstructorInfo GetDefaultConstructor(Type t) + public static ConstructorInfo? GetDefaultConstructor(Type t) { return GetDefaultConstructor(t, false); } - public static ConstructorInfo GetDefaultConstructor(Type t, bool nonPublic) + public static ConstructorInfo? GetDefaultConstructor(Type t, bool nonPublic) { BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public; if (nonPublic) @@ -271,14 +284,14 @@ public static bool IsNullableType(Type t) public static Type EnsureNotNullableType(Type t) { return (IsNullableType(t)) - ? Nullable.GetUnderlyingType(t) + ? Nullable.GetUnderlyingType(t)! : t; } public static Type EnsureNotByRefType(Type t) { return (t.IsByRef && t.HasElementType) - ? t.GetElementType() + ? t.GetElementType()! : t; } @@ -298,7 +311,7 @@ public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceD return ImplementsGenericDefinition(type, genericInterfaceDefinition, out _); } - public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceDefinition, out Type implementingType) + public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceDefinition, [NotNullWhen(true)]out Type? implementingType) { ValidationUtils.ArgumentNotNull(type, nameof(type)); ValidationUtils.ArgumentNotNull(genericInterfaceDefinition, nameof(genericInterfaceDefinition)); @@ -345,7 +358,7 @@ public static bool InheritsGenericDefinition(Type type, Type genericClassDefinit return InheritsGenericDefinition(type, genericClassDefinition, out _); } - public static bool InheritsGenericDefinition(Type type, Type genericClassDefinition, out Type implementingType) + public static bool InheritsGenericDefinition(Type type, Type genericClassDefinition, out Type? implementingType) { ValidationUtils.ArgumentNotNull(type, nameof(type)); ValidationUtils.ArgumentNotNull(genericClassDefinition, nameof(genericClassDefinition)); @@ -358,8 +371,9 @@ public static bool InheritsGenericDefinition(Type type, Type genericClassDefinit return InheritsGenericDefinitionInternal(type, genericClassDefinition, out implementingType); } - private static bool InheritsGenericDefinitionInternal(Type currentType, Type genericClassDefinition, out Type implementingType) + private static bool InheritsGenericDefinitionInternal(Type type, Type genericClassDefinition, out Type? implementingType) { + Type? currentType = type; do { if (currentType.IsGenericType() && genericClassDefinition == currentType.GetGenericTypeDefinition()) @@ -381,7 +395,7 @@ private static bool InheritsGenericDefinitionInternal(Type currentType, Type gen /// /// The type. /// The type of the typed collection's items. - public static Type GetCollectionItemType(Type type) + public static Type? GetCollectionItemType(Type type) { ValidationUtils.ArgumentNotNull(type, nameof(type)); @@ -389,41 +403,35 @@ public static Type GetCollectionItemType(Type type) { return type.GetElementType(); } - if (ImplementsGenericDefinition(type, typeof(IEnumerable<>), out Type genericListType)) + if (ImplementsGenericDefinition(type, typeof(IEnumerable<>), out Type? genericListType)) { - if (genericListType.IsGenericTypeDefinition()) + if (genericListType!.IsGenericTypeDefinition()) { -#pragma warning disable CA2201 // Do not raise reserved exception types throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type)); -#pragma warning restore CA2201 // Do not raise reserved exception types } - return genericListType.GetGenericArguments()[0]; + return genericListType!.GetGenericArguments()[0]; } if (typeof(IEnumerable).IsAssignableFrom(type)) { return null; } -#pragma warning disable CA2201 // Do not raise reserved exception types throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type)); -#pragma warning restore CA2201 // Do not raise reserved exception types } - public static void GetDictionaryKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType) + public static void GetDictionaryKeyValueTypes(Type dictionaryType, out Type? keyType, out Type? valueType) { ValidationUtils.ArgumentNotNull(dictionaryType, nameof(dictionaryType)); - if (ImplementsGenericDefinition(dictionaryType, typeof(IDictionary<,>), out Type genericDictionaryType)) + if (ImplementsGenericDefinition(dictionaryType, typeof(IDictionary<,>), out Type? genericDictionaryType)) { - if (genericDictionaryType.IsGenericTypeDefinition()) + if (genericDictionaryType!.IsGenericTypeDefinition()) { -#pragma warning disable CA2201 // Do not raise reserved exception types throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType)); -#pragma warning restore CA2201 // Do not raise reserved exception types } - Type[] dictionaryGenericArguments = genericDictionaryType.GetGenericArguments(); + Type[] dictionaryGenericArguments = genericDictionaryType!.GetGenericArguments(); keyType = dictionaryGenericArguments[0]; valueType = dictionaryGenericArguments[1]; @@ -436,9 +444,7 @@ public static void GetDictionaryKeyValueTypes(Type dictionaryType, out Type keyT return; } -#pragma warning disable CA2201 // Do not raise reserved exception types throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType)); -#pragma warning restore CA2201 // Do not raise reserved exception types } /// @@ -457,7 +463,7 @@ public static Type GetMemberUnderlyingType(MemberInfo member) case MemberTypes.Property: return ((PropertyInfo)member).PropertyType; case MemberTypes.Event: - return ((EventInfo)member).EventHandlerType; + return ((EventInfo)member).EventHandlerType!; case MemberTypes.Method: return ((MethodInfo)member).ReturnType; default: @@ -465,25 +471,24 @@ public static Type GetMemberUnderlyingType(MemberInfo member) } } - /// - /// Determines whether the member is an indexed property. - /// - /// The member. - /// - /// true if the member is an indexed property; otherwise, false. - /// - public static bool IsIndexedProperty(MemberInfo member) + public static bool IsByRefLikeType(Type type) { - ValidationUtils.ArgumentNotNull(member, nameof(member)); - - if (member is PropertyInfo propertyInfo) + if (!type.IsValueType()) { - return IsIndexedProperty(propertyInfo); + return false; } - else + + // IsByRefLike flag on type is not available in netstandard2.0 + Attribute[] attributes = GetAttributes(type, null, false); + for (int i = 0; i < attributes.Length; i++) { - return false; + if (string.Equals(attributes[i].GetType().FullName, "System.Runtime.CompilerServices.IsByRefLikeAttribute", StringComparison.Ordinal)) + { + return true; + } } + + return false; } /// @@ -506,7 +511,7 @@ public static bool IsIndexedProperty(PropertyInfo property) /// The member. /// The target object. /// The member's value on the object. - public static object GetMemberValue(MemberInfo member, object target) + public static object? GetMemberValue(MemberInfo member, object target) { ValidationUtils.ArgumentNotNull(member, nameof(member)); ValidationUtils.ArgumentNotNull(target, nameof(target)); @@ -535,7 +540,7 @@ public static object GetMemberValue(MemberInfo member, object target) /// The member. /// The target. /// The value. - public static void SetMemberValue(MemberInfo member, object target, object value) + public static void SetMemberValue(MemberInfo member, object target, object? value) { ValidationUtils.ArgumentNotNull(member, nameof(member)); ValidationUtils.ArgumentNotNull(target, nameof(target)); @@ -710,7 +715,7 @@ private static bool IsOverridenGenericMember(MemberInfo memberInfo, BindingFlags return false; } - Type declaringType = propertyInfo.DeclaringType; + Type declaringType = propertyInfo.DeclaringType!; if (!declaringType.IsGenericType()) { return false; @@ -734,12 +739,12 @@ private static bool IsOverridenGenericMember(MemberInfo memberInfo, BindingFlags return true; } - public static T GetAttribute(object attributeProvider) where T : Attribute + public static T? GetAttribute(object attributeProvider) where T : Attribute { return GetAttribute(attributeProvider, true); } - public static T GetAttribute(object attributeProvider, bool inherit) where T : Attribute + public static T? GetAttribute(object attributeProvider, bool inherit) where T : Attribute { T[] attributes = GetAttributes(attributeProvider, inherit); @@ -759,7 +764,7 @@ public static T[] GetAttributes(object attributeProvider, bool inherit) where return a.Cast().ToArray(); } - public static Attribute[] GetAttributes(object attributeProvider, Type attributeType, bool inherit) + public static Attribute[] GetAttributes(object attributeProvider, Type? attributeType, bool inherit) { ValidationUtils.ArgumentNotNull(attributeProvider, nameof(attributeProvider)); @@ -810,7 +815,7 @@ public static T[] GetAttributes(object attributeProvider, bool inherit) where return GetAttributes(attributeProvider, typeof(T), inherit).Cast().ToArray(); } - public static Attribute[] GetAttributes(object provider, Type attributeType, bool inherit) + public static Attribute[] GetAttributes(object provider, Type? attributeType, bool inherit) { switch (provider) { @@ -828,18 +833,16 @@ public static Attribute[] GetAttributes(object provider, Type attributeType, boo return (attributeType != null) ? parameterInfo.GetCustomAttributes(attributeType, inherit).ToArray() : parameterInfo.GetCustomAttributes(inherit).ToArray(); } -#pragma warning disable CA2201 // Do not raise reserved exception types throw new Exception("Cannot get attributes from '{0}'.".FormatWith(CultureInfo.InvariantCulture, provider)); -#pragma warning restore CA2201 // Do not raise reserved exception types } #endif - public static StructMultiKey SplitFullyQualifiedTypeName(string fullyQualifiedTypeName) + public static StructMultiKey SplitFullyQualifiedTypeName(string fullyQualifiedTypeName) { int? assemblyDelimiterIndex = GetAssemblyDelimiterIndex(fullyQualifiedTypeName); string typeName; - string assemblyName; + string? assemblyName; if (assemblyDelimiterIndex != null) { @@ -852,7 +855,7 @@ public static StructMultiKey SplitFullyQualifiedTypeName(string assemblyName = null; } - return new StructMultiKey(assemblyName, typeName); + return new StructMultiKey(assemblyName, typeName); } private static int? GetAssemblyDelimiterIndex(string fullyQualifiedTypeName) @@ -883,7 +886,7 @@ public static StructMultiKey SplitFullyQualifiedTypeName(string return null; } - public static MemberInfo GetMemberInfoFromType(Type targetType, MemberInfo memberInfo) + public static MemberInfo? GetMemberInfoFromType(Type targetType, MemberInfo memberInfo) { const BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; @@ -915,8 +918,10 @@ public static IEnumerable GetFields(Type targetType, BindingFlags bin } #if !PORTABLE - private static void GetChildPrivateFields(IList initialFields, Type targetType, BindingFlags bindingAttr) + private static void GetChildPrivateFields(IList initialFields, Type type, BindingFlags bindingAttr) { + Type? targetType = type; + // fix weirdness with private FieldInfos only being returned for the current Type // find base type fields and add them to result if ((bindingAttr & BindingFlags.NonPublic) != 0) @@ -959,7 +964,7 @@ public static IEnumerable GetProperties(Type targetType, BindingFl PropertyInfo member = propertyInfos[i]; if (member.DeclaringType != targetType) { - PropertyInfo declaredMember = (PropertyInfo)GetMemberInfoFromType(member.DeclaringType, member); + PropertyInfo declaredMember = (PropertyInfo)GetMemberInfoFromType(member.DeclaringType!, member)!; propertyInfos[i] = declaredMember; } } @@ -974,13 +979,14 @@ public static BindingFlags RemoveFlag(this BindingFlags bindingAttr, BindingFlag : bindingAttr; } - private static void GetChildPrivateProperties(IList initialProperties, Type targetType, BindingFlags bindingAttr) + private static void GetChildPrivateProperties(IList initialProperties, Type type, BindingFlags bindingAttr) { // fix weirdness with private PropertyInfos only being returned for the current Type // find base type properties and add them to result // also find base properties that have been hidden by subtype properties with the same name + Type? targetType = type; while ((targetType = targetType.BaseType()) != null) { foreach (PropertyInfo propertyInfo in targetType.GetProperties(bindingAttr)) @@ -1024,11 +1030,11 @@ private static void GetChildPrivateProperties(IList initialPropert } else { - Type subTypePropertyDeclaringType = subTypeProperty.GetBaseDefinition()?.DeclaringType ?? subTypeProperty.DeclaringType; + Type subTypePropertyDeclaringType = subTypeProperty.GetBaseDefinition()?.DeclaringType ?? subTypeProperty.DeclaringType!; int index = initialProperties.IndexOf(p => p.Name == subTypeProperty.Name && p.IsVirtual() - && (p.GetBaseDefinition()?.DeclaringType ?? p.DeclaringType).IsAssignableFrom(subTypePropertyDeclaringType)); + && (p.GetBaseDefinition()?.DeclaringType ?? p.DeclaringType!).IsAssignableFrom(subTypePropertyDeclaringType)); // don't add a virtual property that has an override if (index == -1) @@ -1053,7 +1059,7 @@ public static bool IsMethodOverridden(Type currentType, Type methodDeclaringType return isMethodOverriden; } - public static object GetDefaultValue(Type type) + public static object? GetDefaultValue(Type type) { if (!type.IsValueType()) { @@ -1104,4 +1110,5 @@ public static object GetDefaultValue(Type type) return Activator.CreateInstance(type); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/StringBuffer.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/StringBuffer.cs index 980f1397e1..861c45ea78 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/StringBuffer.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/StringBuffer.cs @@ -27,12 +27,13 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable /// /// Builds a string. Unlike this class lets you reuse its internal buffer. /// internal struct StringBuffer { - private char[] _buffer; + private char[]? _buffer; private int _position; public int Position @@ -43,7 +44,7 @@ public int Position public bool IsEmpty => _buffer == null; - public StringBuffer(IArrayPool bufferPool, int initalSize) : this(BufferUtils.RentBuffer(bufferPool, initalSize)) + public StringBuffer(IArrayPool? bufferPool, int initalSize) : this(BufferUtils.RentBuffer(bufferPool, initalSize)) { } @@ -53,21 +54,21 @@ private StringBuffer(char[] buffer) _position = 0; } - public void Append(IArrayPool bufferPool, char value) + public void Append(IArrayPool? bufferPool, char value) { // test if the buffer array is large enough to take the value - if (_position == _buffer.Length) + if (_position == _buffer!.Length) { EnsureSize(bufferPool, 1); } // set value and increment poisition - _buffer[_position++] = value; + _buffer![_position++] = value; } - public void Append(IArrayPool bufferPool, char[] buffer, int startIndex, int count) + public void Append(IArrayPool? bufferPool, char[] buffer, int startIndex, int count) { - if (_position + count >= _buffer.Length) + if (_position + count >= _buffer!.Length) { EnsureSize(bufferPool, count); } @@ -77,7 +78,7 @@ public void Append(IArrayPool bufferPool, char[] buffer, int startIndex, i _position += count; } - public void Clear(IArrayPool bufferPool) + public void Clear(IArrayPool? bufferPool) { if (_buffer != null) { @@ -87,7 +88,7 @@ public void Clear(IArrayPool bufferPool) _position = 0; } - private void EnsureSize(IArrayPool bufferPool, int appendLength) + private void EnsureSize(IArrayPool? bufferPool, int appendLength) { char[] newBuffer = BufferUtils.RentBuffer(bufferPool, (_position + appendLength) * 2); @@ -107,10 +108,11 @@ public override string ToString() public string ToString(int start, int length) { - // TODO: validation + MiscellaneousUtils.Assert(_buffer != null); return new string(_buffer, start, length); } - public char[] InternalBuffer => _buffer; + public char[]? InternalBuffer => _buffer; } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/StringUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/StringUtils.cs index 26e644f150..5f59d29767 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/StringUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/StringUtils.cs @@ -28,6 +28,7 @@ using System.IO; using System.Text; using System.Globalization; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else @@ -37,6 +38,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal static class StringUtils { public const string CarriageReturnLineFeed = "\r\n"; @@ -45,27 +47,32 @@ internal static class StringUtils public const char LineFeed = '\n'; public const char Tab = '\t'; - public static string FormatWith(this string format, IFormatProvider provider, object arg0) + public static bool IsNullOrEmpty([NotNullWhen(false)] string? value) { - return format.FormatWith(provider, new[] { arg0 }); + return string.IsNullOrEmpty(value); } - public static string FormatWith(this string format, IFormatProvider provider, object arg0, object arg1) + public static string FormatWith(this string format, IFormatProvider provider, object? arg0) { - return format.FormatWith(provider, new[] { arg0, arg1 }); + return format.FormatWith(provider, new object?[] { arg0 }); } - public static string FormatWith(this string format, IFormatProvider provider, object arg0, object arg1, object arg2) + public static string FormatWith(this string format, IFormatProvider provider, object? arg0, object? arg1) { - return format.FormatWith(provider, new[] { arg0, arg1, arg2 }); + return format.FormatWith(provider, new object?[] { arg0, arg1 }); } - public static string FormatWith(this string format, IFormatProvider provider, object arg0, object arg1, object arg2, object arg3) + public static string FormatWith(this string format, IFormatProvider provider, object? arg0, object? arg1, object? arg2) { - return format.FormatWith(provider, new[] { arg0, arg1, arg2, arg3 }); + return format.FormatWith(provider, new object?[] { arg0, arg1, arg2 }); } - private static string FormatWith(this string format, IFormatProvider provider, params object[] args) + public static string FormatWith(this string format, IFormatProvider provider, object? arg0, object? arg1, object? arg2, object? arg3) + { + return format.FormatWith(provider, new object?[] { arg0, arg1, arg2, arg3 }); + } + + private static string FormatWith(this string format, IFormatProvider provider, params object?[] args) { // leave this a private to force code to use an explicit overload // avoids stack memory being reserved for the object array @@ -122,7 +129,7 @@ public static void ToCharAsUnicode(char c, char[] buffer) buffer[5] = MathUtils.IntToHex(c & '\x000f'); } - public static TSource ForgivingCaseSensitiveFind(this IEnumerable source, Func valueSelector, string testValue) + public static TSource? ForgivingCaseSensitiveFind(this IEnumerable source, Func valueSelector, string testValue) { if (source == null) { @@ -148,7 +155,7 @@ public static TSource ForgivingCaseSensitiveFind(this IEnumerable ToSeparatedCase(s, '_'); + + public static string ToKebabCase(string s) => ToSeparatedCase(s, '-'); + + private enum SeparatedCaseState { Start, Lower, @@ -205,43 +216,43 @@ internal enum SnakeCaseState NewWord } - public static string ToSnakeCase(string s) + private static string ToSeparatedCase(string s, char separator) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { return s; } StringBuilder sb = new StringBuilder(); - SnakeCaseState state = SnakeCaseState.Start; + SeparatedCaseState state = SeparatedCaseState.Start; for (int i = 0; i < s.Length; i++) { if (s[i] == ' ') { - if (state != SnakeCaseState.Start) + if (state != SeparatedCaseState.Start) { - state = SnakeCaseState.NewWord; + state = SeparatedCaseState.NewWord; } } else if (char.IsUpper(s[i])) { switch (state) { - case SnakeCaseState.Upper: + case SeparatedCaseState.Upper: bool hasNext = (i + 1 < s.Length); if (i > 0 && hasNext) { char nextChar = s[i + 1]; - if (!char.IsUpper(nextChar) && nextChar != '_') + if (!char.IsUpper(nextChar) && nextChar != separator) { - sb.Append('_'); + sb.Append(separator); } } break; - case SnakeCaseState.Lower: - case SnakeCaseState.NewWord: - sb.Append('_'); + case SeparatedCaseState.Lower: + case SeparatedCaseState.NewWord: + sb.Append(separator); break; } @@ -253,22 +264,22 @@ public static string ToSnakeCase(string s) #endif sb.Append(c); - state = SnakeCaseState.Upper; + state = SeparatedCaseState.Upper; } - else if (s[i] == '_') + else if (s[i] == separator) { - sb.Append('_'); - state = SnakeCaseState.Start; + sb.Append(separator); + state = SeparatedCaseState.Start; } else { - if (state == SnakeCaseState.NewWord) + if (state == SeparatedCaseState.NewWord) { - sb.Append('_'); + sb.Append(separator); } sb.Append(s[i]); - state = SnakeCaseState.Lower; + state = SeparatedCaseState.Lower; } } @@ -293,6 +304,24 @@ public static bool IsLowSurrogate(char c) #endif } + public static int IndexOf(string s, char c) + { +#if HAVE_INDEXOF_STRING_COMPARISON + return s.IndexOf(c, StringComparison.Ordinal); +#else + return s.IndexOf(c); +#endif + } + + public static string Replace(string s, string oldValue, string newValue) + { +#if HAVE_REPLACE_STRING_COMPARISON + return s.Replace(oldValue, newValue, StringComparison.Ordinal); +#else + return s.Replace(oldValue, newValue); +#endif + } + public static bool StartsWith(this string source, char value) { return (source.Length > 0 && source[0] == value); @@ -341,4 +370,5 @@ public static string Trim(this string s, int start, int length) return s.Substring(start, end - start + 1); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/StructMultiKey.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/StructMultiKey.cs index f75c659ccc..d13da05b6e 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/StructMultiKey.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/StructMultiKey.cs @@ -27,6 +27,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal readonly struct StructMultiKey : IEquatable> { public readonly T1 Value1; @@ -43,7 +44,7 @@ public override int GetHashCode() return (Value1?.GetHashCode() ?? 0) ^ (Value2?.GetHashCode() ?? 0); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (!(obj is StructMultiKey key)) { @@ -58,4 +59,5 @@ public bool Equals(StructMultiKey other) return (Equals(Value1, other.Value1) && Equals(Value2, other.Value2)); } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ThreadSafeStore.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ThreadSafeStore.cs index f21e243384..1c1743e8d5 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ThreadSafeStore.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ThreadSafeStore.cs @@ -36,7 +36,7 @@ namespace Microsoft.IdentityModel.Json.Utilities { - internal class ThreadSafeStore + internal class ThreadSafeStore where TKey : notnull { #if HAVE_CONCURRENT_DICTIONARY private readonly ConcurrentDictionary _concurrentStore; diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/TypeExtensions.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/TypeExtensions.cs index 7fde1b4a49..e968507da3 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/TypeExtensions.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/TypeExtensions.cs @@ -26,6 +26,8 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Microsoft.IdentityModel.Json.Utilities.LinqBridge; #else @@ -34,18 +36,19 @@ namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal static class TypeExtensions { #if DOTNET || PORTABLE #if !DOTNET private static readonly BindingFlags DefaultFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; - public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo) + public static MethodInfo? GetGetMethod(this PropertyInfo propertyInfo) { return propertyInfo.GetGetMethod(false); } - public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo, bool nonPublic) + public static MethodInfo? GetGetMethod(this PropertyInfo propertyInfo, bool nonPublic) { MethodInfo getMethod = propertyInfo.GetMethod; if (getMethod != null && (getMethod.IsPublic || nonPublic)) @@ -56,12 +59,12 @@ public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo, bool nonPu return null; } - public static MethodInfo GetSetMethod(this PropertyInfo propertyInfo) + public static MethodInfo? GetSetMethod(this PropertyInfo propertyInfo) { return propertyInfo.GetSetMethod(false); } - public static MethodInfo GetSetMethod(this PropertyInfo propertyInfo, bool nonPublic) + public static MethodInfo? GetSetMethod(this PropertyInfo propertyInfo, bool nonPublic) { MethodInfo setMethod = propertyInfo.SetMethod; if (setMethod != null && (setMethod.IsPublic || nonPublic)) @@ -78,14 +81,14 @@ public static bool IsSubclassOf(this Type type, Type c) return type.GetTypeInfo().IsSubclassOf(c); } -#if !DOTNET && !NET_CORE +#if !DOTNET public static bool IsAssignableFrom(this Type type, Type c) { return type.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo()); } #endif - public static bool IsInstanceOfType(this Type type, object o) + public static bool IsInstanceOfType(this Type type, object? o) { if (o == null) { @@ -169,7 +172,7 @@ public static bool IsGenericTypeDefinition(this Type type) #endif } - public static Type BaseType(this Type type) + public static Type? BaseType(this Type type) { #if HAVE_FULL_REFLECTION return type.BaseType; @@ -215,7 +218,7 @@ public static bool IsSealed(this Type type) } #if (PORTABLE40 || DOTNET || PORTABLE) - public static PropertyInfo GetProperty(this Type type, string name, BindingFlags bindingFlags, object placeholder1, Type propertyType, IList indexParameters, object placeholder2) + public static PropertyInfo GetProperty(this Type type, string name, BindingFlags bindingFlags, object? placeholder1, Type propertyType, IList indexParameters, object? placeholder2) { IEnumerable propertyInfos = type.GetProperties(bindingFlags); @@ -243,7 +246,7 @@ public static PropertyInfo GetProperty(this Type type, string name, BindingFlags public static IEnumerable GetMember(this Type type, string name, MemberTypes memberType, BindingFlags bindingFlags) { -#if PORTABLE && !NET_CORE && !WINDOWS_APP +#if PORTABLE return type.GetMemberInternal(name, memberType, bindingFlags); #else return type.GetMember(name, bindingFlags).Where(m => @@ -273,7 +276,7 @@ public static bool IsDefined(this Type type, Type attributeType, bool inherit) } #if !DOTNET - + public static MethodInfo GetMethod(this Type type, string name) { return type.GetMethod(name, DefaultFlags); @@ -289,12 +292,12 @@ public static MethodInfo GetMethod(this Type type, IList parameterTypes) return type.GetMethod(null, parameterTypes); } - public static MethodInfo GetMethod(this Type type, string name, IList parameterTypes) + public static MethodInfo GetMethod(this Type type, string? name, IList parameterTypes) { return type.GetMethod(name, DefaultFlags, null, parameterTypes, null); } - public static MethodInfo GetMethod(this Type type, string name, BindingFlags bindingFlags, object placeHolder1, IList parameterTypes, object placeHolder2) + public static MethodInfo GetMethod(this Type type, string? name, BindingFlags bindingFlags, object? placeHolder1, IList parameterTypes, object? placeHolder2) { return MethodBinder.SelectMethod(type.GetTypeInfo().DeclaredMethods.Where(m => (name == null || m.Name == name) && TestAccessibility(m, bindingFlags)), parameterTypes); } @@ -308,17 +311,17 @@ public static IEnumerable GetConstructors(this Type type, Bindi { return type.GetTypeInfo().DeclaredConstructors.Where(c => TestAccessibility(c, bindingFlags)); } - + public static ConstructorInfo GetConstructor(this Type type, IList parameterTypes) { return type.GetConstructor(DefaultFlags, null, parameterTypes, null); } - public static ConstructorInfo GetConstructor(this Type type, BindingFlags bindingFlags, object placeholder1, IList parameterTypes, object placeholder2) + public static ConstructorInfo GetConstructor(this Type type, BindingFlags bindingFlags, object? placeholder1, IList parameterTypes, object? placeholder2) { return MethodBinder.SelectMethod(type.GetConstructors(bindingFlags), parameterTypes); } - + public static MemberInfo[] GetMember(this Type type, string member) { return type.GetMemberInternal(member, null, DefaultFlags); @@ -338,19 +341,19 @@ public static MemberInfo[] GetMemberInternal(this Type type, string member, Memb TestAccessibility(m, bindingFlags)).ToArray(); } - public static FieldInfo GetField(this Type type, string member) + public static FieldInfo? GetField(this Type type, string member) { return type.GetField(member, DefaultFlags); } - public static FieldInfo GetField(this Type type, string member, BindingFlags bindingFlags) + public static FieldInfo? GetField(this Type type, string member, BindingFlags bindingFlags) { FieldInfo field = type.GetTypeInfo().GetDeclaredField(member); if (field == null || !TestAccessibility(field, bindingFlags)) { return null; } - + return field; } @@ -378,7 +381,7 @@ private static bool ContainsMemberName(IEnumerable members, string n private static IList GetMembersRecursive(this TypeInfo type) { - TypeInfo t = type; + TypeInfo? t = type; List members = new List(); while (t != null) { @@ -397,7 +400,7 @@ private static IList GetMembersRecursive(this TypeInfo type) private static IList GetPropertiesRecursive(this TypeInfo type) { - TypeInfo t = type; + TypeInfo? t = type; List properties = new List(); while (t != null) { @@ -416,7 +419,7 @@ private static IList GetPropertiesRecursive(this TypeInfo type) private static IList GetFieldsRecursive(this TypeInfo type) { - TypeInfo t = type; + TypeInfo? t = type; List fields = new List(); while (t != null) { @@ -438,19 +441,19 @@ public static IEnumerable GetMethods(this Type type, BindingFlags bi return type.GetTypeInfo().DeclaredMethods; } - public static PropertyInfo GetProperty(this Type type, string name) + public static PropertyInfo? GetProperty(this Type type, string name) { return type.GetProperty(name, DefaultFlags); } - public static PropertyInfo GetProperty(this Type type, string name, BindingFlags bindingFlags) + public static PropertyInfo? GetProperty(this Type type, string name, BindingFlags bindingFlags) { PropertyInfo property = type.GetTypeInfo().GetDeclaredProperty(name); if (property == null || !TestAccessibility(property, bindingFlags)) { return null; } - + return property; } @@ -566,7 +569,7 @@ public static bool IsValueType(this Type type) return type.GetTypeInfo().IsValueType; #endif } - + public static bool IsPrimitive(this Type type) { #if HAVE_FULL_REFLECTION @@ -576,9 +579,9 @@ public static bool IsPrimitive(this Type type) #endif } - public static bool AssignableToTypeName(this Type type, string fullTypeName, bool searchInterfaces, out Type match) + public static bool AssignableToTypeName(this Type type, string fullTypeName, bool searchInterfaces, [NotNullWhen(true)]out Type? match) { - Type current = type; + Type? current = type; while (current != null) { @@ -614,7 +617,7 @@ public static bool AssignableToTypeName(this Type type, string fullTypeName, boo public static bool ImplementInterface(this Type type, Type interfaceType) { - for (Type currentType = type; currentType != null; currentType = currentType.BaseType()) + for (Type? currentType = type; currentType != null; currentType = currentType.BaseType()) { IEnumerable interfaces = currentType.GetInterfaces(); foreach (Type i in interfaces) @@ -629,4 +632,5 @@ public static bool ImplementInterface(this Type type, Type interfaceType) return false; } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ValidationUtils.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ValidationUtils.cs index a5cf4674a2..d72eae2092 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ValidationUtils.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/Utilities/ValidationUtils.cs @@ -24,12 +24,15 @@ #endregion using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; namespace Microsoft.IdentityModel.Json.Utilities { +#nullable enable internal static class ValidationUtils { - public static void ArgumentNotNull(object value, string parameterName) + public static void ArgumentNotNull([NotNull]object? value, string parameterName) { if (value == null) { @@ -37,4 +40,5 @@ public static void ArgumentNotNull(object value, string parameterName) } } } -} \ No newline at end of file +#nullable disable +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/WriteState.cs b/src/Microsoft.IdentityModel.Tokens/opensource/json/WriteState.cs index c043a6014a..9b22508647 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/WriteState.cs +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/WriteState.cs @@ -45,7 +45,7 @@ internal enum WriteState Closed = 1, /// - /// An object is being written. + /// An object is being written. /// Object = 2, @@ -69,4 +69,4 @@ internal enum WriteState /// Start = 6 } -} \ No newline at end of file +} diff --git a/src/Microsoft.IdentityModel.Tokens/opensource/json/opensourceinfo.txt b/src/Microsoft.IdentityModel.Tokens/opensource/json/opensourceinfo.txt index 49dde3bdc4..67d5fdf109 100644 --- a/src/Microsoft.IdentityModel.Tokens/opensource/json/opensourceinfo.txt +++ b/src/Microsoft.IdentityModel.Tokens/opensource/json/opensourceinfo.txt @@ -1,3 +1,3 @@ Name: Newtonsoft.Json -Version: 12.0.1 -Commit: 509643a8952ce731e0207710c429ad6e67dc43db \ No newline at end of file +Version: 13.0.2 +Commit: 94ff24f815a777269920f5a7b13f60db50c5eeb7 \ No newline at end of file diff --git a/src/Microsoft.IdentityModel.Validators/GlobalSuppressions.cs b/src/Microsoft.IdentityModel.Validators/GlobalSuppressions.cs index f7bdda6d6e..0ef7cebb58 100644 --- a/src/Microsoft.IdentityModel.Validators/GlobalSuppressions.cs +++ b/src/Microsoft.IdentityModel.Validators/GlobalSuppressions.cs @@ -6,3 +6,9 @@ using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Needs to be ignored", Scope = "member", Target = "~M:Microsoft.IdentityModel.Validators.AadIssuerValidator.IsValidIssuer(System.String,System.String,System.String)~System.Boolean")] +#if NET6_0 +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Adding StringComparison.Ordinal adds a performance penalty.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Validators.AadIssuerValidator.CreateV1Authority(System.String)~System.String")] +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Adding StringComparison.Ordinal adds a performance penalty.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Validators.AadIssuerValidator.IsValidIssuer(System.String,System.String,System.String)~System.Boolean")] +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Adding StringComparison.Ordinal adds a performance penalty.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Validators.AadIssuerValidator.#ctor(System.Net.Http.HttpClient,System.String)")] +#endif + diff --git a/src/Microsoft.IdentityModel.Xml/GlobalSuppressions.cs b/src/Microsoft.IdentityModel.Xml/GlobalSuppressions.cs index 6d33c364d8..8cc0bf5424 100644 --- a/src/Microsoft.IdentityModel.Xml/GlobalSuppressions.cs +++ b/src/Microsoft.IdentityModel.Xml/GlobalSuppressions.cs @@ -14,3 +14,4 @@ [assembly: SuppressMessage("Design", "CA1065:Do not raise exceptions in unexpected locations", Justification = "Current design", Scope = "member", Target = "~P:Microsoft.IdentityModel.Xml.DelegatingXmlDictionaryWriter.UseInnerWriter")] [assembly: SuppressMessage("Naming", "CA1720:Identifier contains type name", Justification = "Breaking change", Scope = "member", Target = "~F:Microsoft.IdentityModel.Xml.XmlSignatureConstants.Elements.Object")] [assembly: SuppressMessage("Naming", "CA1720:Identifier contains type name", Justification = "Breaking change", Scope = "member", Target = "~M:Microsoft.IdentityModel.Xml.XmlUtil.NormalizeEmptyString(System.String)~System.String")] +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Vendored component", Scope = "module")] diff --git a/src/Microsoft.IdentityModel.Xml/SignedInfo.cs b/src/Microsoft.IdentityModel.Xml/SignedInfo.cs index 24683dd083..19a8bbc3d5 100644 --- a/src/Microsoft.IdentityModel.Xml/SignedInfo.cs +++ b/src/Microsoft.IdentityModel.Xml/SignedInfo.cs @@ -91,7 +91,7 @@ public string CanonicalizationMethod if (string.IsNullOrEmpty(value)) throw LogArgumentNullException(nameof(value)); - if (!string.Equals(value,SecurityAlgorithms.ExclusiveC14n, StringComparison.Ordinal) && !string.Equals(value, SecurityAlgorithms.ExclusiveC14nWithComments, StringComparison.Ordinal)) + if (!string.Equals(value,SecurityAlgorithms.ExclusiveC14n) && !string.Equals(value, SecurityAlgorithms.ExclusiveC14nWithComments)) throw LogExceptionMessage(new NotSupportedException(LogHelper.FormatInvariant(LogMessages.IDX30204, LogHelper.MarkAsNonPII(CanonicalizationMethod), LogHelper.MarkAsNonPII(SecurityAlgorithms.ExclusiveC14n), LogHelper.MarkAsNonPII(SecurityAlgorithms.ExclusiveC14nWithComments)))); _canonicalizationMethod = value; @@ -155,7 +155,7 @@ public void GetCanonicalBytes(Stream stream) { using (var signedInfoWriter = XmlDictionaryWriter.CreateTextWriter(Stream.Null)) { - signedInfoWriter.StartCanonicalization(stream, _canonicalizationMethod.Equals(SecurityAlgorithms.ExclusiveC14nWithComments, StringComparison.Ordinal), null); + signedInfoWriter.StartCanonicalization(stream, _canonicalizationMethod.Equals(SecurityAlgorithms.ExclusiveC14nWithComments), null); _dsigSerializer.WriteSignedInfo(signedInfoWriter, this); signedInfoWriter.Flush(); signedInfoWriter.EndCanonicalization(); diff --git a/src/System.IdentityModel.Tokens.Jwt/GlobalSuppressions.cs b/src/System.IdentityModel.Tokens.Jwt/GlobalSuppressions.cs index 98257e08e9..e318dcee9b 100644 --- a/src/System.IdentityModel.Tokens.Jwt/GlobalSuppressions.cs +++ b/src/System.IdentityModel.Tokens.Jwt/GlobalSuppressions.cs @@ -28,3 +28,4 @@ [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exception is returned from the method.", Scope = "member", Target = "~M:System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateJWE(System.String,System.IdentityModel.Tokens.Jwt.JwtSecurityToken,Microsoft.IdentityModel.Tokens.TokenValidationParameters,Microsoft.IdentityModel.Tokens.BaseConfiguration,Microsoft.IdentityModel.Tokens.SecurityToken@,System.Runtime.ExceptionServices.ExceptionDispatchInfo@)~System.Security.Claims.ClaimsPrincipal")] [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exception is returned from the method.", Scope = "member", Target = "~M:System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateJWS(System.String,Microsoft.IdentityModel.Tokens.TokenValidationParameters,Microsoft.IdentityModel.Tokens.BaseConfiguration,Microsoft.IdentityModel.Tokens.SecurityToken@,System.Runtime.ExceptionServices.ExceptionDispatchInfo@)~System.Security.Claims.ClaimsPrincipal")] [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exception is returned from the method.", Scope = "member", Target = "~M:System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenAsync(System.String,Microsoft.IdentityModel.Tokens.TokenValidationParameters)~System.Threading.Tasks.Task{Microsoft.IdentityModel.Tokens.TokenValidationResult}")] +[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Vendored component", Scope = "module")] diff --git a/src/System.IdentityModel.Tokens.Jwt/JwtHeader.cs b/src/System.IdentityModel.Tokens.Jwt/JwtHeader.cs index d56829c6ac..f1d26c0e48 100644 --- a/src/System.IdentityModel.Tokens.Jwt/JwtHeader.cs +++ b/src/System.IdentityModel.Tokens.Jwt/JwtHeader.cs @@ -26,6 +26,7 @@ //------------------------------------------------------------------------------ using System.Collections.Generic; +using System.Linq; using Microsoft.IdentityModel.Logging; using Microsoft.IdentityModel.Tokens; @@ -91,6 +92,20 @@ public JwtHeader(SigningCredentials signingCredentials, IDictionaryprovides a mapping for the 'alg' value so that values are within the JWT namespace. /// will be added as the value for the 'typ' claim in the header. If it is null or empty will be used as token type public JwtHeader(SigningCredentials signingCredentials, IDictionary outboundAlgorithmMap, string tokenType) + : this(signingCredentials, outboundAlgorithmMap, tokenType, null) + { + } + + /// + /// Initializes a new instance of . + /// With the Header Parameters: + /// { { typ, JWT }, { alg, SigningCredentials.Algorithm } } + /// + /// used when creating a JWS Compact JSON. + /// provides a mapping for the 'alg' value so that values are within the JWT namespace. + /// will be added as the value for the 'typ' claim in the header. If it is null or empty will be used as token type + /// Defines the dictionary containing any custom header claims that need to be added to the inner JWT token header. + public JwtHeader(SigningCredentials signingCredentials, IDictionary outboundAlgorithmMap, string tokenType, IDictionary additionalInnerHeaderClaims) : base(StringComparer.Ordinal) { if (signingCredentials == null) @@ -115,13 +130,14 @@ public JwtHeader(SigningCredentials signingCredentials, IDictionary /// Initializes a new instance of . /// With the Header Parameters: - /// { { typ, JWT }, { alg, SigningCredentials.Algorithm } } + /// { { typ, JWT }, { alg, EncryptingCredentials.Algorithm } } /// /// used when creating a JWS Compact JSON. /// provides a mapping for the 'alg' value so that values are within the JWT namespace. @@ -134,13 +150,28 @@ public JwtHeader(EncryptingCredentials encryptingCredentials, IDictionary /// Initializes a new instance of . /// With the Header Parameters: - /// { { typ, JWT }, { alg, SigningCredentials.Algorithm } } + /// { { typ, JWT }, { alg, EncryptingCredentials.Algorithm } } /// /// used when creating a JWS Compact JSON. /// provides a mapping for the 'alg' value so that values are within the JWT namespace. /// provides the token type /// If 'encryptingCredentials' is null. public JwtHeader(EncryptingCredentials encryptingCredentials, IDictionary outboundAlgorithmMap, string tokenType) + : this(encryptingCredentials, outboundAlgorithmMap, tokenType, null) + { + } + + /// + /// Initializes a new instance of . + /// With the Header Parameters: + /// { { typ, JWT }, { alg, EncryptingCredentials.Algorithm } } + /// + /// used when creating a JWS Compact JSON. + /// provides a mapping for the 'alg' value so that values are within the JWT namespace. + /// provides the token type + /// Defines the dictionary containing any custom header claims that need to be added to the outer JWT token header. + /// If 'encryptingCredentials' is null. + public JwtHeader(EncryptingCredentials encryptingCredentials, IDictionary outboundAlgorithmMap, string tokenType, IDictionary additionalHeaderClaims) : base(StringComparer.Ordinal) { if (encryptingCredentials == null) @@ -165,6 +196,7 @@ public JwtHeader(EncryptingCredentials encryptingCredentials, IDictionary additionalHeaderClaims, bool setDefaultCtyClaim) + { + if (additionalHeaderClaims?.Count > 0 && additionalHeaderClaims.Keys.Intersect(DefaultHeaderParameters, StringComparer.OrdinalIgnoreCase).Any()) + throw LogHelper.LogExceptionMessage(new SecurityTokenException(LogHelper.FormatInvariant(LogMessages.IDX12742, nameof(additionalHeaderClaims), string.Join(", ", DefaultHeaderParameters)))); + + if (additionalHeaderClaims != null) + { + if (!additionalHeaderClaims.TryGetValue(JwtHeaderParameterNames.Cty, out _) && setDefaultCtyClaim) + Cty = JwtConstants.HeaderType; + + foreach (string claim in additionalHeaderClaims.Keys) + this[claim] = additionalHeaderClaims[claim]; + } + else if (setDefaultCtyClaim) + Cty = JwtConstants.HeaderType; + } + + internal static IList DefaultHeaderParameters = new List() + { + JwtHeaderParameterNames.Alg, + JwtHeaderParameterNames.Kid, + JwtHeaderParameterNames.X5t, + JwtHeaderParameterNames.Enc, + JwtHeaderParameterNames.Zip + }; + /// /// Serializes this instance to JSON. /// diff --git a/src/System.IdentityModel.Tokens.Jwt/JwtHeaderParameterNames.cs b/src/System.IdentityModel.Tokens.Jwt/JwtHeaderParameterNames.cs index 34a17417c4..e99eba09cf 100644 --- a/src/System.IdentityModel.Tokens.Jwt/JwtHeaderParameterNames.cs +++ b/src/System.IdentityModel.Tokens.Jwt/JwtHeaderParameterNames.cs @@ -93,5 +93,21 @@ public struct JwtHeaderParameterNames /// See: https://datatracker.ietf.org/doc/html/rfc7516#section-4.1.3 /// public const string Zip = Microsoft.IdentityModel.JsonWebTokens.JwtHeaderParameterNames.Zip; + + /// + /// See: https://datatracker.ietf.org/doc/html/rfc7518#section-4.6.1.1 + /// + public const string Epk = Microsoft.IdentityModel.JsonWebTokens.JwtHeaderParameterNames.Epk; + + /// + /// See: https://datatracker.ietf.org/doc/html/rfc7518#section-4.6.1.2 + /// + public const string Apu = Microsoft.IdentityModel.JsonWebTokens.JwtHeaderParameterNames.Apu; + + /// + /// See: https://datatracker.ietf.org/doc/html/rfc7518#section-4.6.1.3 + /// + public const string Apv = Microsoft.IdentityModel.JsonWebTokens.JwtHeaderParameterNames.Apv; + } } diff --git a/src/System.IdentityModel.Tokens.Jwt/JwtPayload.cs b/src/System.IdentityModel.Tokens.Jwt/JwtPayload.cs index bb3c4d410b..b2d5a97076 100644 --- a/src/System.IdentityModel.Tokens.Jwt/JwtPayload.cs +++ b/src/System.IdentityModel.Tokens.Jwt/JwtPayload.cs @@ -523,7 +523,7 @@ public void AddClaims(IEnumerable claims) } string jsonClaimType = claim.Type; - object jsonClaimValue = claim.ValueType.Equals(ClaimValueTypes.String, StringComparison.Ordinal) ? claim.Value : TokenUtilities.GetClaimValueUsingValueType(claim); + object jsonClaimValue = claim.ValueType.Equals(ClaimValueTypes.String) ? claim.Value : TokenUtilities.GetClaimValueUsingValueType(claim); object existingValue; // If there is an existing value, append to it. diff --git a/src/System.IdentityModel.Tokens.Jwt/JwtSecurityToken.cs b/src/System.IdentityModel.Tokens.Jwt/JwtSecurityToken.cs index 5bfeff7be4..2ded34bed4 100644 --- a/src/System.IdentityModel.Tokens.Jwt/JwtSecurityToken.cs +++ b/src/System.IdentityModel.Tokens.Jwt/JwtSecurityToken.cs @@ -500,7 +500,6 @@ public override string ToString() /// the original token. internal void Decode(string[] tokenParts, string rawData) { - LogHelper.LogInformation(LogMessages.IDX12716, rawData); try { Header = JwtHeader.Base64UrlDeserialize(tokenParts[0]); diff --git a/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs b/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs index 30043160f3..c39bb84aed 100644 --- a/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs +++ b/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs @@ -101,7 +101,6 @@ public class JwtSecurityTokenHandler : SecurityTokenHandler /// static JwtSecurityTokenHandler() { - LogHelper.LogVerbose("Assembly version info: " + LogHelper.MarkAsNonPII(typeof(JwtSecurityTokenHandler).AssemblyQualifiedName)); } /// @@ -362,9 +361,24 @@ public virtual string CreateEncodedJwt(SecurityTokenDescriptor tokenDescriptor) /// If is provided, then a JWS will be created. /// /// A Base64UrlEncoded string in 'Compact Serialization Format'. - public virtual string CreateEncodedJwt(string issuer, string audience, ClaimsIdentity subject, DateTime? notBefore, DateTime? expires, DateTime? issuedAt, SigningCredentials signingCredentials) + public virtual string CreateEncodedJwt( + string issuer, + string audience, + ClaimsIdentity subject, + DateTime? notBefore, + DateTime? expires, + DateTime? issuedAt, + SigningCredentials signingCredentials) { - return CreateJwtSecurityTokenPrivate(issuer, audience, subject, notBefore, expires, issuedAt, signingCredentials, null, null, null).RawData; + return CreateJwtSecurityTokenPrivate( + issuer, + audience, + subject, + notBefore, + expires, + issuedAt, + signingCredentials, + null, null, null, null, null).RawData; } /// @@ -385,9 +399,25 @@ public virtual string CreateEncodedJwt(string issuer, string audience, ClaimsIde /// /// A Base64UrlEncoded string in 'Compact Serialization Format'. /// If 'expires' <= 'notBefore'. - public virtual string CreateEncodedJwt(string issuer, string audience, ClaimsIdentity subject, DateTime? notBefore, DateTime? expires, DateTime? issuedAt, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials) + public virtual string CreateEncodedJwt( + string issuer, + string audience, + ClaimsIdentity subject, + DateTime? notBefore, + DateTime? expires, + DateTime? issuedAt, + SigningCredentials signingCredentials, + EncryptingCredentials encryptingCredentials) { - return CreateJwtSecurityTokenPrivate(issuer, audience, subject, notBefore, expires, issuedAt, signingCredentials, encryptingCredentials, null, null).RawData; + return CreateJwtSecurityTokenPrivate( + issuer, + audience, + subject, + notBefore, + expires, + issuedAt, + signingCredentials, + encryptingCredentials, null, null, null, null).RawData; } /// @@ -409,9 +439,27 @@ public virtual string CreateEncodedJwt(string issuer, string audience, ClaimsIde /// /// A Base64UrlEncoded string in 'Compact Serialization Format'. /// If 'expires' <= 'notBefore'. - public virtual string CreateEncodedJwt(string issuer, string audience, ClaimsIdentity subject, DateTime? notBefore, DateTime? expires, DateTime? issuedAt, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials, IDictionary claimCollection) + public virtual string CreateEncodedJwt( + string issuer, + string audience, + ClaimsIdentity subject, + DateTime? notBefore, + DateTime? expires, + DateTime? issuedAt, + SigningCredentials signingCredentials, + EncryptingCredentials encryptingCredentials, + IDictionary claimCollection) { - return CreateJwtSecurityTokenPrivate(issuer, audience, subject, notBefore, expires, issuedAt, signingCredentials, encryptingCredentials, claimCollection, null).RawData; + return CreateJwtSecurityTokenPrivate( + issuer, + audience, + subject, + notBefore, + expires, + issuedAt, + signingCredentials, + encryptingCredentials, + claimCollection, null, null, null).RawData; } /// @@ -434,7 +482,9 @@ public virtual JwtSecurityToken CreateJwtSecurityToken(SecurityTokenDescriptor t tokenDescriptor.SigningCredentials, tokenDescriptor.EncryptingCredentials, tokenDescriptor.Claims, - tokenDescriptor.TokenType); + tokenDescriptor.TokenType, + tokenDescriptor.AdditionalHeaderClaims, + tokenDescriptor.AdditionalInnerHeaderClaims); } /// @@ -458,9 +508,25 @@ public virtual JwtSecurityToken CreateJwtSecurityToken(SecurityTokenDescriptor t /// /// A . /// If <= . - public virtual JwtSecurityToken CreateJwtSecurityToken(string issuer, string audience, ClaimsIdentity subject, DateTime? notBefore, DateTime? expires, DateTime? issuedAt, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials) + public virtual JwtSecurityToken CreateJwtSecurityToken( + string issuer, + string audience, + ClaimsIdentity subject, + DateTime? notBefore, + DateTime? expires, + DateTime? issuedAt, + SigningCredentials signingCredentials, + EncryptingCredentials encryptingCredentials) { - return CreateJwtSecurityTokenPrivate(issuer, audience, subject, notBefore, expires, issuedAt, signingCredentials, encryptingCredentials, null, null); + return CreateJwtSecurityTokenPrivate( + issuer, + audience, + subject, + notBefore, + expires, + issuedAt, + signingCredentials, + encryptingCredentials, null, null, null, null); } /// @@ -485,9 +551,27 @@ public virtual JwtSecurityToken CreateJwtSecurityToken(string issuer, string aud /// /// A . /// If <= . - public virtual JwtSecurityToken CreateJwtSecurityToken(string issuer, string audience, ClaimsIdentity subject, DateTime? notBefore, DateTime? expires, DateTime? issuedAt, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials, IDictionary claimCollection) + public virtual JwtSecurityToken CreateJwtSecurityToken( + string issuer, + string audience, + ClaimsIdentity subject, + DateTime? notBefore, + DateTime? expires, + DateTime? issuedAt, + SigningCredentials signingCredentials, + EncryptingCredentials encryptingCredentials, + IDictionary claimCollection) { - return CreateJwtSecurityTokenPrivate(issuer, audience, subject, notBefore, expires, issuedAt, signingCredentials, encryptingCredentials, claimCollection, null); + return CreateJwtSecurityTokenPrivate( + issuer, + audience, + subject, + notBefore, + expires, + issuedAt, + signingCredentials, + encryptingCredentials, + claimCollection, null, null, null); } /// @@ -509,9 +593,23 @@ public virtual JwtSecurityToken CreateJwtSecurityToken(string issuer, string aud /// /// A . /// If <= . - public virtual JwtSecurityToken CreateJwtSecurityToken(string issuer = null, string audience = null, ClaimsIdentity subject = null, DateTime? notBefore = null, DateTime? expires = null, DateTime? issuedAt = null, SigningCredentials signingCredentials = null) + public virtual JwtSecurityToken CreateJwtSecurityToken( + string issuer = null, + string audience = null, + ClaimsIdentity subject = null, + DateTime? notBefore = null, + DateTime? expires = null, + DateTime? issuedAt = null, + SigningCredentials signingCredentials = null) { - return CreateJwtSecurityTokenPrivate(issuer, audience, subject, notBefore, expires, issuedAt, signingCredentials, null, null, null); + return CreateJwtSecurityTokenPrivate( + issuer, + audience, + subject, + notBefore, + expires, + issuedAt, + signingCredentials, null, null, null, null, null); } /// @@ -534,10 +632,24 @@ public override SecurityToken CreateToken(SecurityTokenDescriptor tokenDescripto tokenDescriptor.SigningCredentials, tokenDescriptor.EncryptingCredentials, tokenDescriptor.Claims, - tokenDescriptor.TokenType); + tokenDescriptor.TokenType, + tokenDescriptor.AdditionalHeaderClaims, + tokenDescriptor.AdditionalInnerHeaderClaims); } - private JwtSecurityToken CreateJwtSecurityTokenPrivate(string issuer, string audience, ClaimsIdentity subject, DateTime? notBefore, DateTime? expires, DateTime? issuedAt, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials, IDictionary claimCollection, string tokenType) + private JwtSecurityToken CreateJwtSecurityTokenPrivate( + string issuer, + string audience, + ClaimsIdentity subject, + DateTime? notBefore, + DateTime? expires, + DateTime? issuedAt, + SigningCredentials signingCredentials, + EncryptingCredentials encryptingCredentials, + IDictionary claimCollection, + string tokenType, + IDictionary additionalHeaderClaims, + IDictionary additionalInnerHeaderClaims) { if (SetDefaultTimesOnTokenCreation && (!expires.HasValue || !issuedAt.HasValue || !notBefore.HasValue)) { @@ -554,24 +666,35 @@ private JwtSecurityToken CreateJwtSecurityTokenPrivate(string issuer, string aud LogHelper.LogVerbose(LogMessages.IDX12721, (audience ?? "null"), (issuer ?? "null")); JwtPayload payload = new JwtPayload(issuer, audience, (subject == null ? null : OutboundClaimTypeTransform(subject.Claims)), (claimCollection == null ? null : OutboundClaimTypeTransform(claimCollection)), notBefore, expires, issuedAt); - JwtHeader header = new JwtHeader(signingCredentials, OutboundAlgorithmMap, tokenType); + JwtHeader header = new JwtHeader(signingCredentials, OutboundAlgorithmMap, tokenType, additionalInnerHeaderClaims); if (subject?.Actor != null) payload.AddClaim(new Claim(JwtRegisteredClaimNames.Actort, CreateActorValue(subject.Actor))); string rawHeader = header.Base64UrlEncode(); string rawPayload = payload.Base64UrlEncode(); - string rawSignature = signingCredentials == null ? string.Empty : JwtTokenUtilities.CreateEncodedSignature(string.Concat(rawHeader, ".", rawPayload), signingCredentials); + string message = string.Concat(header.Base64UrlEncode(), ".", payload.Base64UrlEncode()); + string rawSignature = signingCredentials == null ? string.Empty : JwtTokenUtilities.CreateEncodedSignature(message, signingCredentials); LogHelper.LogInformation(LogMessages.IDX12722, rawHeader, rawPayload, rawSignature); if (encryptingCredentials != null) - return EncryptToken(new JwtSecurityToken(header, payload, rawHeader, rawPayload, rawSignature), encryptingCredentials, tokenType); + { + return EncryptToken( + new JwtSecurityToken(header, payload, rawHeader, rawPayload, rawSignature), + encryptingCredentials, + tokenType, + additionalHeaderClaims); + } return new JwtSecurityToken(header, payload, rawHeader, rawPayload, rawSignature); } - private JwtSecurityToken EncryptToken(JwtSecurityToken innerJwt, EncryptingCredentials encryptingCredentials, string tokenType) + private JwtSecurityToken EncryptToken( + JwtSecurityToken innerJwt, + EncryptingCredentials encryptingCredentials, + string tokenType, + IDictionary additionalHeaderClaims) { if (encryptingCredentials == null) throw LogHelper.LogArgumentNullException(nameof(encryptingCredentials)); @@ -581,34 +704,33 @@ private JwtSecurityToken EncryptToken(JwtSecurityToken innerJwt, EncryptingCrede if (cryptoProviderFactory == null) throw LogHelper.LogExceptionMessage(new ArgumentException(TokenLogMessages.IDX10620)); - byte[] wrappedKey = null; - SecurityKey securityKey = JwtTokenUtilities.GetSecurityKey(encryptingCredentials, cryptoProviderFactory, out wrappedKey); - - using (var encryptionProvider = cryptoProviderFactory.CreateAuthenticatedEncryptionProvider(securityKey, encryptingCredentials.Enc)) + SecurityKey securityKey = JwtTokenUtilities.GetSecurityKey(encryptingCredentials, cryptoProviderFactory, additionalHeaderClaims, out byte[] wrappedKey); + using (AuthenticatedEncryptionProvider encryptionProvider = cryptoProviderFactory.CreateAuthenticatedEncryptionProvider(securityKey, encryptingCredentials.Enc)) { if (encryptionProvider == null) throw LogHelper.LogExceptionMessage(new SecurityTokenEncryptionFailedException(LogMessages.IDX12730)); try { - var header = new JwtHeader(encryptingCredentials, OutboundAlgorithmMap, tokenType); - var encryptionResult = encryptionProvider.Encrypt(Encoding.UTF8.GetBytes(innerJwt.RawData), Encoding.ASCII.GetBytes(header.Base64UrlEncode())); - return JwtConstants.DirectKeyUseAlg.Equals(encryptingCredentials.Alg, StringComparison.Ordinal) ? new JwtSecurityToken( - header, - innerJwt, - header.Base64UrlEncode(), - string.Empty, - Base64UrlEncoder.Encode(encryptionResult.IV), - Base64UrlEncoder.Encode(encryptionResult.Ciphertext), - Base64UrlEncoder.Encode(encryptionResult.AuthenticationTag)) : - new JwtSecurityToken( - header, - innerJwt, - header.Base64UrlEncode(), - Base64UrlEncoder.Encode(wrappedKey), - Base64UrlEncoder.Encode(encryptionResult.IV), - Base64UrlEncoder.Encode(encryptionResult.Ciphertext), - Base64UrlEncoder.Encode(encryptionResult.AuthenticationTag)); + var header = new JwtHeader(encryptingCredentials, OutboundAlgorithmMap, tokenType, additionalHeaderClaims); + AuthenticatedEncryptionResult encryptionResult = encryptionProvider.Encrypt(Encoding.UTF8.GetBytes(innerJwt.RawData), Encoding.ASCII.GetBytes(header.Base64UrlEncode())); + return JwtConstants.DirectKeyUseAlg.Equals(encryptingCredentials.Alg) ? + new JwtSecurityToken( + header, + innerJwt, + header.Base64UrlEncode(), + string.Empty, + Base64UrlEncoder.Encode(encryptionResult.IV), + Base64UrlEncoder.Encode(encryptionResult.Ciphertext), + Base64UrlEncoder.Encode(encryptionResult.AuthenticationTag)) : + new JwtSecurityToken( + header, + innerJwt, + header.Base64UrlEncode(), + Base64UrlEncoder.Encode(wrappedKey), + Base64UrlEncoder.Encode(encryptionResult.IV), + Base64UrlEncoder.Encode(encryptionResult.Ciphertext), + Base64UrlEncoder.Encode(encryptionResult.AuthenticationTag)); } catch (Exception ex) { @@ -976,7 +1098,15 @@ public override string WriteToken(SecurityToken token) if (jwtToken.InnerToken.SigningCredentials != null) encodedSignature = JwtTokenUtilities.CreateEncodedSignature(string.Concat(jwtToken.InnerToken.EncodedHeader, ".", jwtToken.EncodedPayload), jwtToken.InnerToken.SigningCredentials); - return EncryptToken(new JwtSecurityToken(jwtToken.InnerToken.Header, jwtToken.InnerToken.Payload, jwtToken.InnerToken.EncodedHeader, encodedPayload, encodedSignature), jwtToken.EncryptingCredentials, jwtToken.InnerToken.Header.Typ).RawData; + return EncryptToken( + new JwtSecurityToken( + jwtToken.InnerToken.Header, + jwtToken.InnerToken.Payload, + jwtToken.InnerToken.EncodedHeader, + encodedPayload, encodedSignature), + jwtToken.EncryptingCredentials, + jwtToken.InnerToken.Header.Typ, + null).RawData; } // if EncryptingCredentials isn't set, then we need to create JWE @@ -987,7 +1117,16 @@ public override string WriteToken(SecurityToken token) encodedSignature = JwtTokenUtilities.CreateEncodedSignature(string.Concat(encodedHeader, ".", encodedPayload), jwtToken.SigningCredentials); if (jwtToken.EncryptingCredentials != null) - return EncryptToken(new JwtSecurityToken(header, jwtToken.Payload, encodedHeader, encodedPayload, encodedSignature), jwtToken.EncryptingCredentials, jwtToken.Header.Typ).RawData; + return EncryptToken( + new JwtSecurityToken( + header, + jwtToken.Payload, + encodedHeader, + encodedPayload, + encodedSignature), + jwtToken.EncryptingCredentials, + jwtToken.Header.Typ, + null).RawData; else return string.Concat(encodedHeader, ".", encodedPayload, ".", encodedSignature); } @@ -1189,7 +1328,7 @@ private JwtSecurityToken ValidateSignature(string token, TokenValidationParamete { if (kidMatched) { - var isKidInTVP = keysInTokenValidationParameters.Any(x => x.KeyId.Equals(jwtToken.Header.Kid, StringComparison.Ordinal)); + var isKidInTVP = keysInTokenValidationParameters.Any(x => x.KeyId.Equals(jwtToken.Header.Kid)); var keyLocation = isKidInTVP ? "TokenValidationParameters" : "Configuration"; throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSignatureException( LogHelper.FormatInvariant(TokenLogMessages.IDX10511, @@ -1578,7 +1717,7 @@ internal IEnumerable GetContentEncryptionKeys(JwtSecurityToken jwtT if (keys == null) keys = GetAllDecryptionKeys(validationParameters); - if (jwtToken.Header.Alg.Equals(JwtConstants.DirectKeyUseAlg, StringComparison.Ordinal)) + if (jwtToken.Header.Alg.Equals(JwtConstants.DirectKeyUseAlg)) return keys; var unwrappedKeys = new List(); @@ -1589,6 +1728,24 @@ internal IEnumerable GetContentEncryptionKeys(JwtSecurityToken jwtT { try { +#if NET472 || NET6_0 + if (SupportedAlgorithms.EcdsaWrapAlgorithms.Contains(jwtToken.Header.Alg)) + { + //// on decryption we get the public key from the EPK value see: https://datatracker.ietf.org/doc/html/rfc7518#appendix-C + var ecdhKeyExchangeProvider = new EcdhKeyExchangeProvider( + key as ECDsaSecurityKey, + validationParameters.TokenDecryptionKey as ECDsaSecurityKey, + jwtToken.Header.Alg, + jwtToken.Header.Enc); + string apu = jwtToken.Header.GetStandardClaim(JwtHeaderParameterNames.Apu); + string apv = jwtToken.Header.GetStandardClaim(JwtHeaderParameterNames.Apv); + SecurityKey kdf = ecdhKeyExchangeProvider.GenerateKdf(apu, apv); + var kwp = key.CryptoProviderFactory.CreateKeyWrapProviderForUnwrap(kdf, ecdhKeyExchangeProvider.GetEncryptionAlgorithm()); + var unwrappedKey = kwp.UnwrapKey(Base64UrlEncoder.DecodeBytes(jwtToken.RawEncryptedKey)); + unwrappedKeys.Add(new SymmetricSecurityKey(unwrappedKey)); + } + else +#endif if (key.CryptoProviderFactory.IsSupportedAlgorithm(jwtToken.Header.Alg, key)) { var kwp = key.CryptoProviderFactory.CreateKeyWrapProviderForUnwrap(key, jwtToken.Header.Alg); diff --git a/src/System.IdentityModel.Tokens.Jwt/LogMessages.cs b/src/System.IdentityModel.Tokens.Jwt/LogMessages.cs index a43e56d714..05267fd9c9 100644 --- a/src/System.IdentityModel.Tokens.Jwt/LogMessages.cs +++ b/src/System.IdentityModel.Tokens.Jwt/LogMessages.cs @@ -50,7 +50,7 @@ internal static class LogMessages internal const string IDX12713 = "IDX12713: Creating actor value using actor.BootstrapContext(as string)"; internal const string IDX12714 = "IDX12714: Creating actor value using actor.BootstrapContext.rawData"; internal const string IDX12715 = "IDX12715: Creating actor value by writing the JwtSecurityToken created from actor.BootstrapContext"; - internal const string IDX12716 = "IDX12716: Decoding token: '{0}' into header, payload and signature."; + // internal const string IDX12716 = "IDX12716:"; internal const string IDX12720 = "IDX12720: Token string does not match the token formats: JWE (header.encryptedKey.iv.ciphertext.tag) or JWS (header.payload.signature)"; internal const string IDX12721 = "IDX12721: Creating JwtSecurityToken: Issuer: '{0}', Audience: '{1}'"; internal const string IDX12722 = "IDX12722: Creating security token from the header: '{0}', payload: '{1}' and raw signature: '{2}'."; @@ -64,6 +64,7 @@ internal static class LogMessages internal const string IDX12739 = "IDX12739: JWT: '{0}' has three segments but is not in proper JWS format."; internal const string IDX12740 = "IDX12740: JWT: '{0}' has five segments but is not in proper JWE format."; internal const string IDX12741 = "IDX12741: JWT: '{0}' must have three segments (JWS) or five segments (JWE)."; + internal const string IDX12742 = "IDX12742: ''{0}' cannot contain the following claims: '{1}'. These values are added by default (if necessary) during security token creation."; #pragma warning restore 1591 } } diff --git a/test/Microsoft.IdentityModel.Abstractions.Tests/ITelemetryClientTests.cs b/test/Microsoft.IdentityModel.Abstractions.Tests/ITelemetryClientTests.cs new file mode 100644 index 0000000000..ba694959ec --- /dev/null +++ b/test/Microsoft.IdentityModel.Abstractions.Tests/ITelemetryClientTests.cs @@ -0,0 +1,38 @@ +// Copyright(c) Microsoft Corporation.All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System; +using Moq; +using Xunit; + +namespace Microsoft.IdentityModel.Abstractions.Tests +{ + /// + /// This test suite is meant to act as a defense in depth to warn when someone changes the public interface which + /// will be breaking. + /// + public class ITelemetryClientTests + { + [Fact] + public void ValidatePublicContract() + { + // WARNING: Updating this code likely means you're breaking the public contract and should be avoided. + var mockObject = new Mock().Object; + mockObject.ClientId = "ClientId"; + mockObject.Initialize(); + mockObject.IsEnabled(); + mockObject.IsEnabled("fetch_metadata"); + mockObject.TrackEvent(new Mock().Object); + mockObject.TrackEvent( + "validate_token", + new Dictionary() { { "string", "value" } }, + new Dictionary() { { "long", 1L } }, + new Dictionary() { { "bool", true } }, + new Dictionary() { { "DateTime", DateTime.UtcNow } }, + new Dictionary() { { "double", 1.0d } }, + new Dictionary() { { "Guid", Guid.NewGuid() } }); + + } + } +} diff --git a/test/Microsoft.IdentityModel.Abstractions.Tests/Microsoft.IdentityModel.Abstractions.Tests.csproj b/test/Microsoft.IdentityModel.Abstractions.Tests/Microsoft.IdentityModel.Abstractions.Tests.csproj new file mode 100644 index 0000000000..6c563a876f --- /dev/null +++ b/test/Microsoft.IdentityModel.Abstractions.Tests/Microsoft.IdentityModel.Abstractions.Tests.csproj @@ -0,0 +1,27 @@ + + + + + + Microsoft.IdentityModel.Abstractions.Tests + Microsoft.IdentityModel.Abstractions.Tests + true + Microsoft.IdentityModel.Abstractions.Tests + true + true + $(MSBuildThisFileDirectory)..\..\build\35MSSharedLib1024.snk + + + + + + + + + + + + + + + diff --git a/test/Microsoft.IdentityModel.Abstractions.Tests/Properties/AssemblyInfo.cs b/test/Microsoft.IdentityModel.Abstractions.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..7db8142e7f --- /dev/null +++ b/test/Microsoft.IdentityModel.Abstractions.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// Copyright(c) Microsoft Corporation.All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Runtime.InteropServices; +using Xunit; + +[assembly: CLSCompliant(true)] +[assembly: ComVisible(false)] +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/test/Microsoft.IdentityModel.Abstractions.Tests/TelemetryEventDetailsTests.cs b/test/Microsoft.IdentityModel.Abstractions.Tests/TelemetryEventDetailsTests.cs new file mode 100644 index 0000000000..8083ae2789 --- /dev/null +++ b/test/Microsoft.IdentityModel.Abstractions.Tests/TelemetryEventDetailsTests.cs @@ -0,0 +1,162 @@ +// Copyright(c) Microsoft Corporation.All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.IdentityModel.Abstractions; +using Xunit; +using Moq; +using System.Collections.Generic; + +namespace Microsoft.IdentityModel.Logging.Tests +{ + public class TelemetryEventDetailsTests + { + [Fact] + public void TestNameSetGet() + { + var mock = new Mock(); + mock.CallBase = true; + const string eventName = "Create_Widget"; + mock.Object.Name = eventName; + Assert.Equal(eventName, mock.Object.Name); + } + + [Fact] + public void SetPropertyArgumentNullException() + { + var mock = new Mock(); + mock.CallBase = true; + Assert.Throws("key", () => mock.Object.SetProperty(null, "string")); + Assert.Throws("key", () => mock.Object.SetProperty(null, false)); + Assert.Throws("key", () => mock.Object.SetProperty(null, 1L)); + Assert.Throws("key", () => mock.Object.SetProperty(null, DateTime.UtcNow)); + Assert.Throws("key", () => mock.Object.SetProperty(null, 1.0d)); + Assert.Throws("key", () => mock.Object.SetProperty(null, Guid.NewGuid())); + } + + [Fact] + public void SetPropertyNoConflict() + { + Dictionary expected = new Dictionary() + { + { "string", "string" }, + { "bool", true }, + { "long", 1L }, + { "DateTime", DateTime.Now }, + { "double", 1.0d }, + { "Guid", Guid.NewGuid() } + }; + + var mock = new Mock(); + mock.CallBase = true; + mock.Object.SetProperty("string", (string)expected["string"]); + mock.Object.SetProperty("bool", (bool)expected["bool"]); + mock.Object.SetProperty("long", (long)expected["long"]); + mock.Object.SetProperty("DateTime", (DateTime)expected["DateTime"]); + mock.Object.SetProperty("double", (double)expected["double"]); + mock.Object.SetProperty("Guid", (Guid)expected["Guid"]); + + Assert.Equal(expected.Count, mock.Object.Properties.Count); + foreach (var item in mock.Object.Properties) + { + Assert.Equal(expected[item.Key], item.Value); + } + } + + [Fact] + public void SetPropertyWithConflict() + { + var mock = new Mock(); + mock.CallBase = true; + mock.Object.SetProperty("key1", "value"); + mock.Object.SetProperty("key1", false); + + Assert.Equal(1, mock.Object.Properties.Count); + Assert.False((bool)mock.Object.Properties["key1"]); + } + + [Fact] + public void VerifyDerivedTypesCanAddArbitraryTypes() + { + CustomTelemetryEventDetails eventDetails = new CustomTelemetryEventDetails(); + eventDetails.SetProperty("foo", new Foo() { Bar = "bar" }); + + Assert.Equal(1, eventDetails.Properties.Count); + Assert.Equal("bar", (eventDetails.Properties["foo"] as Foo)?.Bar); + } + + [Fact] + public void VerifyExtensibilityForClassification() + { + TelemetryEventDetailsWithClassification eventDetails = new TelemetryEventDetailsWithClassification(); + eventDetails.SetProperty("Protocol", "Bearer"); + eventDetails.SetProperty("TokenIdentity", "Bob Jones", true); + eventDetails.SetProperty("DataCenter", "CO1", false); + + Assert.Equal(3, eventDetails.Properties.Count); + Assert.True(eventDetails.IsPersonalData["TokenIdentity"]); + Assert.False(eventDetails.IsPersonalData["Protocol"]); + Assert.False(eventDetails.IsPersonalData["DataCenter"]); + } + + #region Dummy Implementation + internal class TelemetryEventDetailsWithClassification : TelemetryEventDetails + { + internal IDictionary PersonalDataDecoration = new Dictionary(); + + public IReadOnlyDictionary IsPersonalData + { + get + { + return (IReadOnlyDictionary)PersonalDataDecoration; + } + } + + public override void SetProperty( + string key, + string value) + { + SetPropertyCore(key, value); + } + + public void SetProperty( + string key, + string value, + bool isPersonal) + { + SetPropertyCore(key, value, isPersonal); + } + + private void SetPropertyCore( + string key, + object value, + bool isPersonal = false) + { + if (key == null) + throw new ArgumentNullException(nameof(key)); + + PropertyValues[key] = value; + PersonalDataDecoration[key] = isPersonal; + } + } + + internal class CustomTelemetryEventDetails : TelemetryEventDetails + { + internal void SetProperty( + string key, + Foo value) + { + if (key == null) + throw new ArgumentNullException(nameof(key)); + + PropertyValues[key] = value; + } + } + + internal class Foo + { + public string Bar { get; set; } + } + #endregion Dummy Implementation + } +} diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs index f929c2532d..86e0206e2b 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs @@ -69,6 +69,15 @@ public void Base64UrlEncodedUnsignedJwtHeader() TestUtilities.AssertFailIfErrors(context); } + [Fact] + public void CreateTokenThrowsNullArgumentException() + { + var handler = new JsonWebTokenHandler(); + Assert.Throws(() => handler.CreateToken(null, Default.SymmetricEncryptingCredentials, new Dictionary { {"key", "value" } })); + Assert.Throws(() => handler.CreateToken("Payload", (EncryptingCredentials) null, new Dictionary { { "key", "value" } })); + Assert.Throws(() => handler.CreateToken("Payload", Default.SymmetricEncryptingCredentials, (Dictionary) null)); + } + [Fact] public void ValidateTokenValidationResult() { @@ -527,7 +536,7 @@ public static TheoryData CreateJWETheoryData SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, EncryptingCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_Aes256_Sha512_512, Subject = new ClaimsIdentity(Default.PayloadClaims), - TokenType = "TokenType" + TokenType = "TokenType", }, JsonWebTokenHandler = new JsonWebTokenHandler(), JwtSecurityTokenHandler = tokenHandler, @@ -1215,6 +1224,188 @@ public static TheoryData CreateJWSWithAdditionalHeaderCla } } + [Theory, MemberData(nameof(CreateJWEWithPayloadStringTheoryData))] + public void CreateJWEWithPayloadString(CreateTokenTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.CreateJWEWithPayloadString", theoryData); + var handler = new JsonWebTokenHandler(); + string jwtTokenWithSigning = null; + JsonWebToken jsonTokenWithSigning = null; + CompressionProviderFactory.Default = new CompressionProviderFactory(); + try + { + var jwtToken = handler.CreateToken(theoryData.Payload, theoryData.TokenDescriptor.EncryptingCredentials, theoryData.TokenDescriptor.AdditionalHeaderClaims); + var jsonToken = new JsonWebToken(jwtToken); + + if (theoryData.TokenDescriptor.SigningCredentials != null) + { + jwtTokenWithSigning = handler.CreateToken(theoryData.Payload, theoryData.TokenDescriptor.SigningCredentials, theoryData.TokenDescriptor.EncryptingCredentials, CompressionAlgorithms.Deflate, theoryData.TokenDescriptor.AdditionalHeaderClaims, theoryData.TokenDescriptor.AdditionalInnerHeaderClaims); + jsonTokenWithSigning = new JsonWebToken(jwtTokenWithSigning); + } + + if (theoryData.TokenDescriptor.AdditionalHeaderClaims.TryGetValue(JwtHeaderParameterNames.Cty, out object ctyValue)) + { + if (!jsonToken.TryGetHeaderValue(JwtHeaderParameterNames.Cty, out object headerCtyValue) || (jsonTokenWithSigning != null && !jsonTokenWithSigning.TryGetHeaderValue(JwtHeaderParameterNames.Cty, out object _))) + { + context.AddDiff($"'Cty' claim does not exist in the outer header but present in theoryData.AdditionalHeaderClaims."); + } + else + IdentityComparer.AreEqual(ctyValue.ToString(), headerCtyValue.ToString(), context); + } + else if (theoryData.TokenDescriptor.EncryptingCredentials.SetDefaultCtyClaim) + { + if (!jsonToken.TryGetHeaderValue(JwtHeaderParameterNames.Cty, out object headerCtyValue) || (jsonTokenWithSigning != null && !jsonTokenWithSigning.TryGetHeaderValue(JwtHeaderParameterNames.Cty, out object _))) + { + context.AddDiff($"'Cty' claim does not exist in the outer header. It is expected to have the default value '{JwtConstants.HeaderType}'."); + } + else + IdentityComparer.AreEqual(JwtConstants.HeaderType, headerCtyValue.ToString(), context); + } + else + { + if (jsonToken.TryGetHeaderValue(JwtHeaderParameterNames.Cty, out object headerCtyValue) || (jsonTokenWithSigning != null && jsonTokenWithSigning.TryGetHeaderValue(JwtHeaderParameterNames.Cty, out object _))) + { + context.AddDiff($"'Cty' claim does exist in the outer header. It is not expected to exist since SetDefaultCtyClaim is '{theoryData.EncryptingCredentials.SetDefaultCtyClaim}'."); + } + } + + if (theoryData.TokenDescriptor.AdditionalInnerHeaderClaims != null) + { + theoryData.ValidationParameters.ValidateLifetime = false; + var result = handler.ValidateToken(jwtTokenWithSigning, theoryData.ValidationParameters); + var token = result.SecurityToken as JsonWebToken; + if (theoryData.TokenDescriptor.AdditionalInnerHeaderClaims.TryGetValue(JwtHeaderParameterNames.Cty, out object innerCtyValue)) + { + if (!token.InnerToken.TryGetHeaderValue(JwtHeaderParameterNames.Cty, out object headerCtyValue)) + { + context.AddDiff($"'Cty' claim does not exist in the inner header but present in theoryData.AdditionalHeaderClaims."); + } + else + IdentityComparer.AreEqual(innerCtyValue.ToString(), headerCtyValue.ToString(), context); + } + else + { + if (token.InnerToken.TryGetHeaderValue(JwtHeaderParameterNames.Cty, out object headerCtyValue)) + { + context.AddDiff($"It is not expected to have 'Cty' claim in the inner header."); + } + } + + } + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData CreateJWEWithPayloadStringTheoryData + { + get + { + var NoCtyEncryptionCreds = Default.SymmetricEncryptingCredentials; + NoCtyEncryptionCreds.SetDefaultCtyClaim = false; + return new TheoryData + { + new CreateTokenTheoryData + { + First = true, + TestId = "JsonPayload", + Payload = Default.PayloadString, + TokenDescriptor = new SecurityTokenDescriptor + { + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{ {"int", "123" } }, + }, + }, + new CreateTokenTheoryData + { + First = true, + TestId = "JsonPayload", + Payload = Default.PayloadString, + TokenDescriptor = new SecurityTokenDescriptor + { + EncryptingCredentials = NoCtyEncryptionCreds, + AdditionalHeaderClaims = new Dictionary{ {"int", "123" } }, + }, + }, + new CreateTokenTheoryData + { + TestId = "JsonPayload_CtyInAdditionalClaims", + Payload = Default.PayloadString, + TokenDescriptor = new SecurityTokenDescriptor + { + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{{JwtHeaderParameterNames.Cty, "str"}} + }, + }, + new CreateTokenTheoryData + { + TestId = "NonJsonPayload", + Payload = Guid.NewGuid().ToString(), + TokenDescriptor = new SecurityTokenDescriptor + { + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{{JwtHeaderParameterNames.Cty, "NonJWT"}} + }, + }, + new CreateTokenTheoryData + { + TestId = "CtyInBothAdditionalClaims", + Payload = Default.PayloadString, + TokenDescriptor = new SecurityTokenDescriptor + { + SigningCredentials = Default.SymmetricSigningCredentials, + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{{JwtHeaderParameterNames.Cty, "str_outer"}}, + AdditionalInnerHeaderClaims = new Dictionary{{JwtHeaderParameterNames.Cty, "str_inner"}} + }, + ValidationParameters = new TokenValidationParameters + { + IssuerSigningKey = Default.SymmetricSigningCredentials.Key, + TokenDecryptionKey = Default.SymmetricEncryptingCredentials.Key, + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer + } + }, + new CreateTokenTheoryData + { + TestId = "CtyInOuterAdditionalClaims", + Payload = Default.PayloadString, + TokenDescriptor = new SecurityTokenDescriptor + { + SigningCredentials = Default.SymmetricSigningCredentials, + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{{JwtHeaderParameterNames.Cty, "str"}}, + AdditionalInnerHeaderClaims = new Dictionary{ {"int", "123" } }, + }, + ValidationParameters = new TokenValidationParameters + { + IssuerSigningKey = Default.SymmetricSigningCredentials.Key, + TokenDecryptionKey = Default.SymmetricEncryptingCredentials.Key, + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer + } + }, + new CreateTokenTheoryData + { + TestId = "DefaultParameterinAdditionalInnerHeaderClaims", + Payload = Default.PayloadString, + TokenDescriptor = new SecurityTokenDescriptor + { + SigningCredentials = Default.SymmetricSigningCredentials, + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{ { JwtHeaderParameterNames.Cty, "str" } }, + AdditionalInnerHeaderClaims = new Dictionary{ { JwtHeaderParameterNames.Enc, "str" } }, + }, + ExpectedException = ExpectedException.SecurityTokenException("IDX14116:") + }, + }; + } + } + // This test checks to make sure that additional header claims are added as expected to the outer token header. [Theory, MemberData(nameof(CreateJWEWithAdditionalHeaderClaimsTheoryData))] public void CreateJWEWithAdditionalHeaderClaims(CreateTokenTheoryData theoryData) @@ -1223,22 +1414,19 @@ public void CreateJWEWithAdditionalHeaderClaims(CreateTokenTheoryData theoryData var handler = new JsonWebTokenHandler(); theoryData.ValidationParameters.ValidateLifetime = false; - var jwtTokenString = handler.CreateToken(theoryData.TokenDescriptor); - var jwtToken = handler.ValidateToken(jwtTokenString, theoryData.ValidationParameters).SecurityToken as JsonWebToken; + var jwtTokenFromDescriptor = handler.CreateToken(theoryData.TokenDescriptor); + var validatedJwtTokenFromDescriptor = handler.ValidateToken(jwtTokenFromDescriptor, theoryData.ValidationParameters).SecurityToken as JsonWebToken; var jwtTokenToCompare = handler.ValidateToken(theoryData.JwtToken, theoryData.ValidationParameters).SecurityToken as JsonWebToken; context.PropertiesToIgnoreWhenComparing = new Dictionary> { { typeof(JsonWebToken), new List { "EncodedToken", "AuthenticationTag", "Ciphertext", "InitializationVector", "EncryptedKey" } }, }; - IdentityComparer.AreEqual(jwtToken, jwtTokenToCompare, context); + IdentityComparer.AreEqual(validatedJwtTokenFromDescriptor, jwtTokenToCompare, context); foreach (var key in theoryData.TokenDescriptor.AdditionalHeaderClaims.Keys) { - if (jwtToken.InnerToken.TryGetHeaderValue(key, out string headerValue) && !key.Equals(JwtHeaderParameterNames.Typ)) - context.AddDiff($"Inner JWT header should not contain the '{key}' claim."); - - if (!jwtToken.TryGetHeaderValue(key, out headerValue)) + if (!validatedJwtTokenFromDescriptor.TryGetHeaderValue(key, out string headerValue)) context.AddDiff($"JWE header does not contain the '{key}' claim."); var headerValueToCompare = jwtTokenToCompare.GetHeaderValue(key); @@ -1260,6 +1448,7 @@ public static TheoryData CreateJWEWithAdditionalHeaderCla { First = true, TestId = "JWEDirectEncryption", + Payload = Default.PayloadString, TokenDescriptor = new SecurityTokenDescriptor { Claims = Default.PayloadDictionary, @@ -1277,8 +1466,29 @@ public static TheoryData CreateJWEWithAdditionalHeaderCla JwtToken = ReferenceTokens.JWEDirectEcryptionWithAdditionalHeaderClaims }, new CreateTokenTheoryData + { + TestId = "JWEDirectEncryptionWithCty", + Payload = Default.PayloadString, + TokenDescriptor = new SecurityTokenDescriptor + { + Claims = Default.PayloadDictionary, + SigningCredentials = Default.SymmetricSigningCredentials, + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary() { { JwtHeaderParameterNames.Cty, JwtConstants.HeaderType} } + }, + ValidationParameters = new TokenValidationParameters + { + IssuerSigningKey = Default.SymmetricSigningCredentials.Key, + TokenDecryptionKey = Default.SymmetricEncryptingCredentials.Key, + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer + }, + JwtToken = ReferenceTokens.JWEDirectEcryptionWithCtyInAdditionalHeaderClaims + }, + new CreateTokenTheoryData { TestId = "JWEDirectEncryptionWithDifferentTyp", + Payload = Default.PayloadString, TokenDescriptor = new SecurityTokenDescriptor { Claims = Default.PayloadDictionary, @@ -1298,6 +1508,7 @@ public static TheoryData CreateJWEWithAdditionalHeaderCla new CreateTokenTheoryData { TestId = "JWEKeyWrapping", + Payload = Default.PayloadString, TokenDescriptor = new SecurityTokenDescriptor { SigningCredentials = Default.SymmetricSigningCredentials, @@ -1317,6 +1528,7 @@ public static TheoryData CreateJWEWithAdditionalHeaderCla new CreateTokenTheoryData { TestId = "JWEKeyWrappingDifferentTyp", + Payload = Default.PayloadString, TokenDescriptor = new SecurityTokenDescriptor { SigningCredentials = Default.SymmetricSigningCredentials, @@ -1336,6 +1548,7 @@ public static TheoryData CreateJWEWithAdditionalHeaderCla new CreateTokenTheoryData { TestId = "JWEKeyWrappingUnsignedInnerJwt", + Payload = Default.PayloadString, TokenDescriptor = new SecurityTokenDescriptor { EncryptingCredentials = new EncryptingCredentials(KeyingMaterial.RsaSecurityKey_2048, SecurityAlgorithms.RsaPKCS1, SecurityAlgorithms.Aes128CbcHmacSha256), @@ -1354,6 +1567,7 @@ public static TheoryData CreateJWEWithAdditionalHeaderCla new CreateTokenTheoryData { TestId = "JWEDirectEncryptionUnsignedInnerJWT", + Payload = Default.PayloadString, TokenDescriptor = new SecurityTokenDescriptor { Claims = Default.PayloadDictionary, @@ -3194,7 +3408,7 @@ public AuthenticatedEncryptionProviderMock(SecurityKey key, string algorithm): b public override AuthenticatedEncryptionResult Encrypt(byte[] plaintext, byte[] authenticatedData) { - byte[] nonce = new byte[AesGcm.NonceSize]; + byte[] nonce = new byte[Tokens.AesGcm.NonceSize]; // Generate random nonce var random = RandomNumberGenerator.Create(); @@ -3205,10 +3419,10 @@ public override AuthenticatedEncryptionResult Encrypt(byte[] plaintext, byte[] a public override AuthenticatedEncryptionResult Encrypt(byte[] plaintext, byte[] authenticatedData, byte[] iv) { - byte[] authenticationTag = new byte[AesGcm.TagSize]; + byte[] authenticationTag = new byte[Tokens.AesGcm.TagSize]; byte[] ciphertext = new byte[plaintext.Length]; - using (var aes = new AesGcm(GetKeyBytes(Key))) + using (var aes = new Tokens.AesGcm(GetKeyBytes(Key))) { aes.Encrypt(iv, plaintext, ciphertext, authenticationTag, authenticatedData); } diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenTests.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenTests.cs index e7a53a2683..401f0dce5a 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenTests.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenTests.cs @@ -624,7 +624,7 @@ public void DateTimeISO8061Claim() TestUtilities.AssertFailIfErrors(context); // both claim value types should be DateTime - Assert.True(string.Equals(claimA.ValueType, ClaimValueTypes.DateTime, StringComparison.Ordinal), "ClaimValueType is not DateTime."); + Assert.True(string.Equals(claimA.ValueType, ClaimValueTypes.DateTime), "ClaimValueType is not DateTime."); // claim value shouldn't contain any quotes Assert.DoesNotContain("\"", claimA.Value); } diff --git a/test/Microsoft.IdentityModel.Logging.Tests/LoggerTests.cs b/test/Microsoft.IdentityModel.Logging.Tests/LoggerTests.cs index 04f5174c29..0f84d01670 100644 --- a/test/Microsoft.IdentityModel.Logging.Tests/LoggerTests.cs +++ b/test/Microsoft.IdentityModel.Logging.Tests/LoggerTests.cs @@ -29,13 +29,42 @@ using System.Diagnostics.Tracing; using System.Globalization; using System.IO; +using Microsoft.IdentityModel.Abstractions; using Microsoft.IdentityModel.TestUtils; using Xunit; +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant + namespace Microsoft.IdentityModel.Logging.Tests { public class LoggerTests { + [Fact] + public void EventLevelToEventLogLevelMapping() + { + var logger = new TestLogger(); + LogHelper.Logger = logger; + + var arg = "Test argument."; + var guid = Guid.NewGuid().ToString(); + var errorMessage = "Test exception message"; + var infoMessage = "Test information Message. {0}"; + var verboseMessage = "Test verbose Message. {0}"; + var warnMessage = "Warn Message. {0}"; + + LogHelper.LogExceptionMessage(EventLevel.Error, new ArgumentException(errorMessage)); + LogHelper.LogArgumentNullException(guid); + LogHelper.LogInformation(infoMessage, LogHelper.MarkAsNonPII(arg)); + LogHelper.LogVerbose(verboseMessage, LogHelper.MarkAsNonPII(arg)); + LogHelper.LogWarning(warnMessage, LogHelper.MarkAsNonPII(arg)); + + Assert.True(logger.ContainsLogOfSpecificLevel(errorMessage, EventLogLevel.Error)); + Assert.True(logger.ContainsLogOfSpecificLevel("IDX10000:", EventLogLevel.Error)); + Assert.True(logger.ContainsLogOfSpecificLevel(string.Format(infoMessage, arg), EventLogLevel.Informational)); + Assert.True(logger.ContainsLogOfSpecificLevel(string.Format(verboseMessage, arg), EventLogLevel.Verbose)); + Assert.True(logger.ContainsLogOfSpecificLevel(string.Format(warnMessage, arg), EventLogLevel.Warning)); + } + [Fact] public void LogMessageAndThrowException() { @@ -237,7 +266,63 @@ public void PrepareMessageWithNoArguments() var exception = LogHelper.LogExceptionMessage(new ArgumentException("This is the first parameter '{0}'. This is the second parameter '{1}'.")); } + + [Theory, MemberData(nameof(LoggerTestTheoryData))] + public void LoggerInstanceTests(LoggerTheoryData theoryData) + { + LogHelper.Logger = theoryData.Logger; + + if (theoryData.Logger != null) + { + Assert.True(theoryData.ShouldMessageBeLogged == LogHelper.Logger.IsEnabled(theoryData.EventLogLevel)); + } + } + + public static TheoryData LoggerTestTheoryData + { + get + { + var theoryData = new TheoryData(); + + theoryData.Add(new LoggerTheoryData + { + TestId = "NullLoggerInstanceNoMessage", + Logger = NullIdentityModelLogger.Instance, + ShouldMessageBeLogged = false + }); + + theoryData.Add(new LoggerTheoryData + { + TestId = "LoggerInstanceNoMessage", + Logger = new TestLogger() { IsLoggerEnabled = false }, + ShouldMessageBeLogged = false + }); + + theoryData.Add(new LoggerTheoryData + { + TestId = "LoggerInstanceWithMessage", + Logger = new TestLogger() { IsLoggerEnabled = true }, + ShouldMessageBeLogged = true + }); + + return theoryData; + } + } } + public class LoggerTheoryData : TheoryDataBase + { + public LoggerTheoryData() : base(false) + { } + + public IIdentityLogger Logger { get; set; } = null; + + public bool ShouldMessageBeLogged { get; set; } + public string Message { get; set; } = "Test Message"; + + public EventLogLevel EventLogLevel { get; set; } = EventLogLevel.Informational; + } } + +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant diff --git a/test/Microsoft.IdentityModel.Logging.Tests/TestLogger.cs b/test/Microsoft.IdentityModel.Logging.Tests/TestLogger.cs new file mode 100644 index 0000000000..015296aa52 --- /dev/null +++ b/test/Microsoft.IdentityModel.Logging.Tests/TestLogger.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.IdentityModel.Abstractions; + +namespace Microsoft.IdentityModel.Logging.Tests +{ + public class TestLogger : IIdentityLogger + { + readonly List> _logs = new List>(); + + public bool IsLoggerEnabled { get; set; } = true; + + public bool IsEnabled(EventLogLevel logLevel) + { + return IsLoggerEnabled; + } + + public void Log(LogEntry entry) + { + _logs.Add(new Tuple(entry.Message, entry.EventLogLevel)); + } + + public bool ContainsLog(string substring) + { + if (string.IsNullOrEmpty(substring)) + return true; + + return _logs.Any(x => x.Item1.Contains(substring)); + } + + public bool ContainsLogOfSpecificLevel(string substring, EventLogLevel logLevel) + { + if (string.IsNullOrEmpty(substring)) + throw new ArgumentException("Provided value is null or empty.", nameof(substring)); + + return _logs.Any(x => x.Item1.Contains(substring) && x.Item2 == logLevel); + } + } +} diff --git a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/JsonWebKeySetBadRsaDataMissingComponent.json b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/JsonWebKeySetBadRsaDataMissingComponent.json index de6d199291..7c95e7fd0e 100644 --- a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/JsonWebKeySetBadRsaDataMissingComponent.json +++ b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/JsonWebKeySetBadRsaDataMissingComponent.json @@ -1,4 +1,4 @@ -{ +{ "keys": [ { "Kid": "pqoeamb2e5YVzR6_rqFpiCrFZgw", diff --git a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/JsonWebKeySetUnrecognizedKty.json b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/JsonWebKeySetUnrecognizedKty.json index b303605166..cb22a5e7ed 100644 --- a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/JsonWebKeySetUnrecognizedKty.json +++ b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/JsonWebKeySetUnrecognizedKty.json @@ -1,4 +1,4 @@ -{ +{ "keys": [ { "alg": "SHA256", diff --git a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectConfigurationTests.cs b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectConfigurationTests.cs index 35ca5f0680..850db536ef 100644 --- a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectConfigurationTests.cs +++ b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectConfigurationTests.cs @@ -38,7 +38,6 @@ namespace Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests { /// - /// /// public class OpenIdConnectConfigurationTests { diff --git a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMessageTests.cs b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMessageTests.cs index e740923cc0..be97dffc9d 100644 --- a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMessageTests.cs +++ b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMessageTests.cs @@ -34,6 +34,7 @@ using Xunit; #pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +#pragma warning disable SYSLIB0013 // Type or member is obsolete namespace Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests { @@ -250,6 +251,9 @@ public void OidcCreateAuthenticationRequestUrl(string testId, OpenIdConnectMessa #elif NET472 if (!message.SkuTelemetryValue.Equals("ID_NET472")) context.Diffs.Add($"{message.SkuTelemetryValue} != ID_NET472"); +#elif NET6_0 + if (!message.SkuTelemetryValue.Equals("ID_NET6_0")) + context.Diffs.Add($"{message.SkuTelemetryValue} != ID_NET6_0"); #elif NET_CORE if (!message.SkuTelemetryValue.Equals("ID_NETSTANDARD2_0")) context.Diffs.Add($"{message.SkuTelemetryValue} != ID_NETSTANDARD2_0"); @@ -520,6 +524,9 @@ public void OidcCreateLogoutRequestUrl(string testId, OpenIdConnectMessage messa #elif NET472 if (!message.SkuTelemetryValue.Equals("ID_NET472")) context.Diffs.Add($"{message.SkuTelemetryValue} != ID_NET472"); +#elif NET6_0 + if (!message.SkuTelemetryValue.Equals("ID_NET6_0")) + context.Diffs.Add($"{message.SkuTelemetryValue} != ID_NETCOREAPP3_1"); #elif NET_CORE if (!message.SkuTelemetryValue.Equals("ID_NETSTANDARD2_0")) context.Diffs.Add($"{message.SkuTelemetryValue} != ID_NETSTANDARD2_0"); @@ -647,5 +654,5 @@ public class OpenIdConnectMessageTheoryData : TheoryDataBase } } +#pragma warning restore SYSLIB0013 // Type or member is obsolete #pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant - diff --git a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMetadataBadRsaDataMissingComponent.json b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMetadataBadRsaDataMissingComponent.json index fdcac50e84..282c92eb20 100644 --- a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMetadataBadRsaDataMissingComponent.json +++ b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMetadataBadRsaDataMissingComponent.json @@ -1,4 +1,4 @@ -{ +{ "issuer": "https://sts.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/", "authorization_endpoint": "https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/authorize", "token_endpoint": "https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/token", diff --git a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMetadataUnrecognizedKty.json b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMetadataUnrecognizedKty.json index 4388d9b6f0..e2f2b0738a 100644 --- a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMetadataUnrecognizedKty.json +++ b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMetadataUnrecognizedKty.json @@ -1,4 +1,4 @@ -{ +{ "issuer": "https://sts.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/", "authorization_endpoint": "https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/authorize", "token_endpoint": "https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/token", diff --git a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectProtocolValidatorTests.cs b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectProtocolValidatorTests.cs index 5755ca3b9b..83f4d057b4 100644 --- a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectProtocolValidatorTests.cs +++ b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectProtocolValidatorTests.cs @@ -80,6 +80,22 @@ private static JwtSecurityToken CreateValidatedIdToken(string claimType, object return new JwtSecurityToken(header, payload); } + private static JwtSecurityToken CreateJWEValidatedIdToken(string claimType, object claimValue, string alg) + { + var innerToken = CreateValidatedIdToken(claimType, claimValue, alg); + + var header = new JwtHeader(Default.SymmetricEncryptingCredentials); + var token = new JwtSecurityToken( + header, + innerToken, + "ey", + "ey", + "ey", + "ey", + "ey"); + return token; + } + [Fact] public void GenerateNonce() { @@ -173,112 +189,113 @@ public static TheoryData ValidateAuthentication { get { - var theoryData = new TheoryData(); - - theoryData.Add(new OidcProtocolValidatorTheoryData + var theoryData = new TheoryData { - ExpectedException = ExpectedException.ArgumentNullException(), - First = true, - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext == null" - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = ExpectedException.ArgumentNullException(), + First = true, + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext == null" + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21333:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext.ProtocolMessage == null", - ValidationContext = new OpenIdConnectProtocolValidationContext() - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21333:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext.ProtocolMessage == null", + ValidationContext = new OpenIdConnectProtocolValidationContext() + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21334:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "'id_token' == null, 'code' == null", - ValidationContext = new OpenIdConnectProtocolValidationContext { ProtocolMessage = new OpenIdConnectMessage() } - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21334:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "'id_token' == null, 'code' == null", + ValidationContext = new OpenIdConnectProtocolValidationContext { ProtocolMessage = new OpenIdConnectMessage() } + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21334:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "'id_token' == string.Empty, 'code' == string.Empty", - ValidationContext = new OpenIdConnectProtocolValidationContext + new OidcProtocolValidatorTheoryData { - ProtocolMessage = new OpenIdConnectMessage + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21334:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "'id_token' == string.Empty, 'code' == string.Empty", + ValidationContext = new OpenIdConnectProtocolValidationContext { - Code = string.Empty, - IdToken = string.Empty, + ProtocolMessage = new OpenIdConnectMessage + { + Code = string.Empty, + IdToken = string.Empty, + } } - } - }); + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21332:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "'id_token' != null, validationContext.validatedIdToken == null", - ValidationContext = new OpenIdConnectProtocolValidationContext + new OidcProtocolValidatorTheoryData { - ProtocolMessage = new OpenIdConnectMessage + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21332:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "'id_token' != null, validationContext.validatedIdToken == null", + ValidationContext = new OpenIdConnectProtocolValidationContext { - IdToken = Guid.NewGuid().ToString() + ProtocolMessage = new OpenIdConnectMessage + { + IdToken = Guid.NewGuid().ToString() + } } - } - }); + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21335:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "'refresh_token' should not be returned from AuthorizationEndpoint", - ValidationContext = new OpenIdConnectProtocolValidationContext + new OidcProtocolValidatorTheoryData { - ProtocolMessage = new OpenIdConnectMessage + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21335:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "'refresh_token' should not be returned from AuthorizationEndpoint", + ValidationContext = new OpenIdConnectProtocolValidationContext { - IdToken = Guid.NewGuid().ToString(), - RefreshToken = Guid.NewGuid().ToString() - }, - ValidatedIdToken = new JwtSecurityToken() - } - }); - - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ProtocolValidator = new PublicOpenIdConnectProtocolValidator - { - RequireState = false + ProtocolMessage = new OpenIdConnectMessage + { + IdToken = Guid.NewGuid().ToString(), + RefreshToken = Guid.NewGuid().ToString() + }, + ValidatedIdToken = new JwtSecurityToken() + } }, - TestId = "'id_token' == string.Empty, 'code' != null, RequireState == false", - ValidationContext = new OpenIdConnectProtocolValidationContext + + new OidcProtocolValidatorTheoryData { - ProtocolMessage = new OpenIdConnectMessage + ProtocolValidator = new PublicOpenIdConnectProtocolValidator + { + RequireState = false + }, + TestId = "'id_token' == string.Empty, 'code' != null, RequireState == false", + ValidationContext = new OpenIdConnectProtocolValidationContext { - Code = Guid.NewGuid().ToString(), - IdToken = string.Empty, + ProtocolMessage = new OpenIdConnectMessage + { + Code = Guid.NewGuid().ToString(), + IdToken = string.Empty, + } } - } - }); - - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21334:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator - { - RequireState = false }, - TestId = "'id_token' == null, 'code' == null, 'access_token' != null, RequireState == false", - ValidationContext = new OpenIdConnectProtocolValidationContext + + new OidcProtocolValidatorTheoryData { - ProtocolMessage = new OpenIdConnectMessage + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21334:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator + { + RequireState = false + }, + TestId = "'id_token' == null, 'code' == null, 'access_token' != null, RequireState == false", + ValidationContext = new OpenIdConnectProtocolValidationContext { - AccessToken = Guid.NewGuid().ToString(), - Code = string.Empty, - IdToken = string.Empty, + ProtocolMessage = new OpenIdConnectMessage + { + AccessToken = Guid.NewGuid().ToString(), + Code = string.Empty, + IdToken = string.Empty, + } } } - }); + }; return theoryData; } @@ -303,80 +320,81 @@ public static TheoryData ValidateTokenResponseT { get { - var theoryData = new TheoryData(); - - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = ExpectedException.ArgumentNullException(), - First = true, - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext == null" - }); - - theoryData.Add(new OidcProtocolValidatorTheoryData + var theoryData = new TheoryData { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21333:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext.ProtocolMessage == null", - ValidationContext = new OpenIdConnectProtocolValidationContext() - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = ExpectedException.ArgumentNullException(), + First = true, + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext == null" + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21336:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext.ProtocolMessage.IdToken == null", - ValidationContext = new OpenIdConnectProtocolValidationContext() + new OidcProtocolValidatorTheoryData { - ProtocolMessage = new OpenIdConnectMessage { AccessToken = Guid.NewGuid().ToString() } - } - }); + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21333:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext.ProtocolMessage == null", + ValidationContext = new OpenIdConnectProtocolValidationContext() + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21336:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext.ProtocolMessage.AccessToken == null", - ValidationContext = new OpenIdConnectProtocolValidationContext() + new OidcProtocolValidatorTheoryData { - ProtocolMessage = new OpenIdConnectMessage { IdToken = Guid.NewGuid().ToString() } - } - }); + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21336:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext.ProtocolMessage.IdToken == null", + ValidationContext = new OpenIdConnectProtocolValidationContext() + { + ProtocolMessage = new OpenIdConnectMessage { AccessToken = Guid.NewGuid().ToString() } + } + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21332:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext.ValidatedIdToken == null", - ValidationContext = new OpenIdConnectProtocolValidationContext() + new OidcProtocolValidatorTheoryData { - ProtocolMessage = new OpenIdConnectMessage + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21336:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext.ProtocolMessage.AccessToken == null", + ValidationContext = new OpenIdConnectProtocolValidationContext() { - AccessToken = Guid.NewGuid().ToString(), - IdToken = Guid.NewGuid().ToString() + ProtocolMessage = new OpenIdConnectMessage { IdToken = Guid.NewGuid().ToString() } } - } - }); + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ProtocolValidator = new PublicOpenIdConnectProtocolValidator + new OidcProtocolValidatorTheoryData { - RequireNonce = false, - RequireTimeStampInNonce = false + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21332:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext.ValidatedIdToken == null", + ValidationContext = new OpenIdConnectProtocolValidationContext() + { + ProtocolMessage = new OpenIdConnectMessage + { + AccessToken = Guid.NewGuid().ToString(), + IdToken = Guid.NewGuid().ToString() + } + } }, - TestId = "validationContext.ValidatedIdToken.AtHash == null (Optional)", - ValidationContext = new OpenIdConnectProtocolValidationContext() + + new OidcProtocolValidatorTheoryData { - Nonce = Default.Nonce, - ProtocolMessage = new OpenIdConnectMessage + ProtocolValidator = new PublicOpenIdConnectProtocolValidator { - AccessToken = Guid.NewGuid().ToString(), - IdToken = Guid.NewGuid().ToString() + RequireNonce = false, + RequireTimeStampInNonce = false }, - ValidatedIdToken = CreateValidatedIdToken() + TestId = "validationContext.ValidatedIdToken.AtHash == null (Optional)", + ValidationContext = new OpenIdConnectProtocolValidationContext() + { + Nonce = Default.Nonce, + ProtocolMessage = new OpenIdConnectMessage + { + AccessToken = Guid.NewGuid().ToString(), + IdToken = Guid.NewGuid().ToString() + }, + ValidatedIdToken = CreateValidatedIdToken() + } } - }); + }; return theoryData; } @@ -401,55 +419,56 @@ public static TheoryData ValidateUserInfoRespon { get { - var theoryData = new TheoryData(); - - theoryData.Add(new OidcProtocolValidatorTheoryData + var theoryData = new TheoryData { - ExpectedException = ExpectedException.ArgumentNullException(), - First = true, - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext == null" - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = ExpectedException.ArgumentNullException(), + First = true, + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext == null" + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21337:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext.UserInfoEndpointResponse == null", - ValidationContext = new OpenIdConnectProtocolValidationContext() - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21337:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext.UserInfoEndpointResponse == null", + ValidationContext = new OpenIdConnectProtocolValidationContext() + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21332:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext.validatedIdToken == null", - ValidationContext = new OpenIdConnectProtocolValidationContext { UserInfoEndpointResponse = "response" } - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21332:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext.validatedIdToken == null", + ValidationContext = new OpenIdConnectProtocolValidationContext { UserInfoEndpointResponse = "response" } + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21343:", typeof(JsonReaderException)), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "UserInfoEndpointResponse is not valid JSON", - ValidationContext = new OpenIdConnectProtocolValidationContext + new OidcProtocolValidatorTheoryData { - UserInfoEndpointResponse = "response", - ValidatedIdToken = CreateValidatedIdToken(), - } - }); + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21343:", typeof(JsonReaderException)), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "UserInfoEndpointResponse is not valid JSON", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + UserInfoEndpointResponse = "response", + ValidatedIdToken = CreateValidatedIdToken(), + } + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21345:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "UserInfoEndpointResponse.sub == null", - ValidationContext = new OpenIdConnectProtocolValidationContext + new OidcProtocolValidatorTheoryData { - UserInfoEndpointResponse = @"{ ""tid"":""42"",""name"":""bob""}", - ValidatedIdToken = CreateValidatedIdToken(), + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21345:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "UserInfoEndpointResponse.sub == null", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + UserInfoEndpointResponse = @"{ ""tid"":""42"",""name"":""bob""}", + ValidatedIdToken = CreateValidatedIdToken(), + } } - }); + }; var jwtWithoutSub = CreateValidatedIdToken(); jwtWithoutSub.Payload.Remove(JwtRegisteredClaimNames.Sub); @@ -460,7 +479,7 @@ public static TheoryData ValidateUserInfoRespon TestId = "ValidatedIdToken.sub == null", ValidationContext = new OpenIdConnectProtocolValidationContext { - UserInfoEndpointResponse = @"{ ""sub"": ""sub1""}", + UserInfoEndpointResponse = @"{ ""sub"": ""sub1""}", ValidatedIdToken = jwtWithoutSub } }); @@ -472,7 +491,7 @@ public static TheoryData ValidateUserInfoRespon TestId = "UserInfoEndpointResponse.sub != ValidatedIdToken.sub", ValidationContext = new OpenIdConnectProtocolValidationContext { - UserInfoEndpointResponse = @"{ ""sub"": ""sub1""}", + UserInfoEndpointResponse = @"{ ""sub"": ""sub1""}", ValidatedIdToken = CreateValidatedIdToken() } }); @@ -483,7 +502,7 @@ public static TheoryData ValidateUserInfoRespon TestId = "(JSON) UserInfoResponse.sub == ValidatedIdToken.sub", ValidationContext = new OpenIdConnectProtocolValidationContext { - UserInfoEndpointResponse = @"{ ""sub"": ""sub""}", + UserInfoEndpointResponse = @"{ ""sub"": ""sub""}", ValidatedIdToken = CreateValidatedIdToken("sub", "sub") } }); @@ -494,7 +513,7 @@ public static TheoryData ValidateUserInfoRespon TestId = "(JWT) UserInfoResponse.sub == ValidatedIdToken.sub", ValidationContext = new OpenIdConnectProtocolValidationContext { - UserInfoEndpointResponse = (new JwtSecurityTokenHandler()).WriteToken(CreateValidatedIdToken("sub", "sub")), + UserInfoEndpointResponse = (new JwtSecurityTokenHandler()).WriteToken(CreateValidatedIdToken("sub", "sub")), ValidatedIdToken = CreateValidatedIdToken("sub", "sub") } }); @@ -718,7 +737,7 @@ public static TheoryData ValidateIdTokenTheoryD { IdTokenValidator = ((jwtToken, context) => { - var jwtSecurityToken = jwtToken as JwtSecurityToken; + var jwtSecurityToken = jwtToken; if (jwtSecurityToken.Payload.Acr != "acr") throw new InvalidOperationException(); }) @@ -965,6 +984,137 @@ public static TheoryData ValidateCHashTheoryDat } } + [Theory, MemberData(nameof(ValidateJWEPayloadCHashTheoryData))] + private void ValidateJWEPayloadCHash(OidcProtocolValidatorTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.ValidateJWEPayloadCHash", theoryData); + try + { + theoryData.ProtocolValidator.PublicValidateCHash(theoryData.ValidationContext); + theoryData.ExpectedException.ProcessNoException(context); + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + + return; + } + + public static TheoryData ValidateJWEPayloadCHashTheoryData + { + get + { + string code = Guid.NewGuid().ToString(); + string chash256 = IdentityUtilities.CreateHashClaim(code, "SHA256"); + string chash384 = IdentityUtilities.CreateHashClaim(code, "SHA384"); + string chash512 = IdentityUtilities.CreateHashClaim(code, "SHA512"); + + return new TheoryData + { + new OidcProtocolValidatorTheoryData + { + TestId = "alg==256, hash(code)==256", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + ProtocolMessage = new OpenIdConnectMessage { Code = code }, + ValidatedIdToken = CreateJWEValidatedIdToken(JwtRegisteredClaimNames.CHash, chash256, SecurityAlgorithms.RsaSha256) + } + }, + new OidcProtocolValidatorTheoryData + { + TestId = "alg==384, hash(code)==384", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + ProtocolMessage = new OpenIdConnectMessage { Code = code }, + ValidatedIdToken = CreateJWEValidatedIdToken(JwtRegisteredClaimNames.CHash, chash384, SecurityAlgorithms.RsaSha384) + } + }, + new OidcProtocolValidatorTheoryData + { + TestId = "alg==512, hash(code)==512", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + ProtocolMessage = new OpenIdConnectMessage { Code = code }, + ValidatedIdToken = CreateJWEValidatedIdToken(JwtRegisteredClaimNames.CHash, chash512, SecurityAlgorithms.RsaSha512) + } + }, + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidCHashException), "IDX21347:", typeof(OpenIdConnectProtocolException)), + TestId = "ValidatedIdToken.chash != ProtocolMessage.Code", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + ProtocolMessage = new OpenIdConnectMessage { Code = Guid.NewGuid().ToString() }, + ValidatedIdToken = CreateJWEValidatedIdToken(JwtRegisteredClaimNames.CHash, chash256, SecurityAlgorithms.RsaSha256) + } + }, + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidCHashException), "IDX21347:", typeof(OpenIdConnectProtocolException)), + TestId = "alg==256, hash(code)==384", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + ProtocolMessage = new OpenIdConnectMessage { Code = code }, + ValidatedIdToken = CreateJWEValidatedIdToken(JwtRegisteredClaimNames.CHash, chash384, SecurityAlgorithms.RsaSha256) + } + }, + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidCHashException), "IDX21347:", typeof(OpenIdConnectProtocolException)), + TestId = "alg==256, hash(code)==384", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + ProtocolMessage = new OpenIdConnectMessage { Code = code }, + ValidatedIdToken = CreateJWEValidatedIdToken(JwtRegisteredClaimNames.CHash, chash384, SecurityAlgorithms.RsaSha256) + } + }, + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidCHashException), "IDX21347:", typeof(OpenIdConnectProtocolException)), + TestId = "alg==256, hash(code)==384", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + ProtocolMessage = new OpenIdConnectMessage { Code = code }, + ValidatedIdToken = CreateJWEValidatedIdToken(JwtRegisteredClaimNames.CHash, chash384, SecurityAlgorithms.RsaSha256) + } + }, + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidCHashException), "IDX21347:", typeof(OpenIdConnectProtocolException)), + TestId = "alg==256, hash(code)==512", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + ProtocolMessage = new OpenIdConnectMessage { Code = code }, + ValidatedIdToken = CreateJWEValidatedIdToken(JwtRegisteredClaimNames.CHash, chash512, SecurityAlgorithms.RsaSha256) + } + }, + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidCHashException), "IDX21347:", typeof(OpenIdConnectProtocolException)), + TestId = "alg==384, hash(code)==512", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + ProtocolMessage = new OpenIdConnectMessage { Code = code }, + ValidatedIdToken = CreateJWEValidatedIdToken(JwtRegisteredClaimNames.CHash, chash512, SecurityAlgorithms.RsaSha384) + } + }, + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidCHashException), "IDX21347:", typeof(OpenIdConnectProtocolException)), + TestId = "alg==384, hash(code)==256", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + ProtocolMessage = new OpenIdConnectMessage { Code = code }, + ValidatedIdToken = CreateJWEValidatedIdToken(JwtRegisteredClaimNames.CHash, chash256, SecurityAlgorithms.RsaSha384) + } + } + }; + } + } + [Theory, MemberData(nameof(ValidateNonceTheoryData))] private void ValidateNonce(OidcProtocolValidatorTheoryData theoryData) { @@ -984,22 +1134,23 @@ public static TheoryData ValidateNonceTheoryDat { get { - var theoryData = new TheoryData(); - - theoryData.Add(new OidcProtocolValidatorTheoryData + var theoryData = new TheoryData { - ExpectedException = ExpectedException.ArgumentNullException(), - First = true, - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext == null", - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = ExpectedException.ArgumentNullException(), + First = true, + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext == null", + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = ExpectedException.ArgumentNullException(), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext.ValidatedToken == null", - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = ExpectedException.ArgumentNullException(), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext.ValidatedToken == null", + } + }; var jwtWithoutNonce = CreateValidatedIdToken(); jwtWithoutNonce.Payload.Remove(JwtRegisteredClaimNames.Nonce); @@ -1093,7 +1244,7 @@ public static TheoryData ValidateNonceTheoryDat ValidationContext = new OpenIdConnectProtocolValidationContext { Nonce = nonceWithoutTimestamp, - ValidatedIdToken = CreateValidatedIdToken(JwtRegisteredClaimNames.Nonce, nonceWithoutTimestamp ) + ValidatedIdToken = CreateValidatedIdToken(JwtRegisteredClaimNames.Nonce, nonceWithoutTimestamp) } }); @@ -1121,7 +1272,7 @@ public static TheoryData ValidateNonceTheoryDat } }); - string nonceExpired = (DateTime.UtcNow-TimeSpan.FromDays(20)).Ticks.ToString(CultureInfo.InvariantCulture) + "." + nonceWithoutTimestamp; + string nonceExpired = (DateTime.UtcNow - TimeSpan.FromDays(20)).Ticks.ToString(CultureInfo.InvariantCulture) + "." + nonceWithoutTimestamp; theoryData.Add(new OidcProtocolValidatorTheoryData { ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidNonceException), "IDX21324:"), @@ -1209,31 +1360,32 @@ public static TheoryData ValidateAtHashTheoryDa { get { - var theoryData = new TheoryData(); - - theoryData.Add(new OidcProtocolValidatorTheoryData + var theoryData = new TheoryData { - ExpectedException = ExpectedException.ArgumentNullException(), - First = true, - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext == null" - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = ExpectedException.ArgumentNullException(), + First = true, + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext == null" + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = ExpectedException.ArgumentNullException(), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext.ValidatedIdToken == null", - ValidationContext = new OpenIdConnectProtocolValidationContext { ProtocolMessage = new OpenIdConnectMessage() } - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = ExpectedException.ArgumentNullException(), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext.ValidatedIdToken == null", + ValidationContext = new OpenIdConnectProtocolValidationContext { ProtocolMessage = new OpenIdConnectMessage() } + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21333:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext.ProtocolMessage == null", - ValidationContext = new OpenIdConnectProtocolValidationContext { ValidatedIdToken = CreateValidatedIdToken() } - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolException), "IDX21333:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext.ProtocolMessage == null", + ValidationContext = new OpenIdConnectProtocolValidationContext { ValidatedIdToken = CreateValidatedIdToken() } + } + }; var token = Guid.NewGuid().ToString(); var hashClaimValue256 = IdentityUtilities.CreateHashClaim(token, "SHA256"); @@ -1253,10 +1405,10 @@ public static TheoryData ValidateAtHashTheoryDa { ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidAtHashException), "IDX21348:", typeof(OpenIdConnectProtocolException)), ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId ="Jwt.at_hash != hash(access_token) - 256 - 512", + TestId = "Jwt.at_hash != hash(access_token) - 256 - 512", ValidationContext = new OpenIdConnectProtocolValidationContext() { - ProtocolMessage = new OpenIdConnectMessage{ AccessToken = token}, + ProtocolMessage = new OpenIdConnectMessage { AccessToken = token }, ValidatedIdToken = new JwtSecurityToken(claims: new List { new Claim("at_hash", hashClaimValue512) }, signingCredentials: Default.AsymmetricSigningCredentials) } }); @@ -1301,6 +1453,47 @@ public static TheoryData ValidateAtHashTheoryDa } } + [Theory, MemberData(nameof(ValidateJWEPayloadAtHashTheoryData))] + public void ValidateJWEPayloadAtHash(OidcProtocolValidatorTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.ValidateJWEPayloadAtHash", theoryData); + try + { + theoryData.ProtocolValidator.PublicValidateAtHash(theoryData.ValidationContext); + theoryData.ExpectedException.ProcessNoException(context); + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + } + + public static TheoryData ValidateJWEPayloadAtHashTheoryData + { + get + { + var token = Guid.NewGuid().ToString(); + var hashClaimValue256 = IdentityUtilities.CreateHashClaim(token, "SHA256"); + + var theoryData = new TheoryData + { + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidAtHashException), "IDX21312:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "Jwt.at_hash == hash(access_token)", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + ProtocolMessage = new OpenIdConnectMessage { AccessToken = token }, + ValidatedIdToken = CreateJWEValidatedIdToken("at_hash", hashClaimValue256, SecurityAlgorithms.RsaSha256) + } + } + }; + + return theoryData; + } + } + [Theory, MemberData(nameof(ValidateStateTheoryData))] public void ValidateState(OidcProtocolValidatorTheoryData theoryData) { @@ -1320,42 +1513,43 @@ public static TheoryData ValidateStateTheoryDat { get { - var theoryData = new TheoryData(); - - theoryData.Add(new OidcProtocolValidatorTheoryData + var theoryData = new TheoryData { - ExpectedException = ExpectedException.ArgumentNullException("IDX10000:"), - First = true, - ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), - TestId = "validationContext == null" - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = ExpectedException.ArgumentNullException("IDX10000:"), + First = true, + ProtocolValidator = new PublicOpenIdConnectProtocolValidator(), + TestId = "validationContext == null" + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidStateException), "IDX21329:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator { RequireState = true }, - TestId = "validationContext.State == null", - ValidationContext = new OpenIdConnectProtocolValidationContext { ProtocolMessage = new OpenIdConnectMessage() } - }); + new OidcProtocolValidatorTheoryData + { + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidStateException), "IDX21329:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator { RequireState = true }, + TestId = "validationContext.State == null", + ValidationContext = new OpenIdConnectProtocolValidationContext { ProtocolMessage = new OpenIdConnectMessage() } + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ProtocolValidator = new PublicOpenIdConnectProtocolValidator { RequireState = false }, - TestId = "validationContext.State == null, RequireState == false", - ValidationContext = new OpenIdConnectProtocolValidationContext { ProtocolMessage = new OpenIdConnectMessage() } - }); + new OidcProtocolValidatorTheoryData + { + ProtocolValidator = new PublicOpenIdConnectProtocolValidator { RequireState = false }, + TestId = "validationContext.State == null, RequireState == false", + ValidationContext = new OpenIdConnectProtocolValidationContext { ProtocolMessage = new OpenIdConnectMessage() } + }, - theoryData.Add(new OidcProtocolValidatorTheoryData - { - ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidStateException), "IDX21330:"), - ProtocolValidator = new PublicOpenIdConnectProtocolValidator { RequireState = true }, - TestId = "validationContext.state != null, protocolMessage.state == null", - ValidationContext = new OpenIdConnectProtocolValidationContext + new OidcProtocolValidatorTheoryData { - ProtocolMessage = new OpenIdConnectMessage(), - State = Guid.NewGuid().ToString() + ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidStateException), "IDX21330:"), + ProtocolValidator = new PublicOpenIdConnectProtocolValidator { RequireState = true }, + TestId = "validationContext.state != null, protocolMessage.state == null", + ValidationContext = new OpenIdConnectProtocolValidationContext + { + ProtocolMessage = new OpenIdConnectMessage(), + State = Guid.NewGuid().ToString() + } } - }); + }; var state = Guid.NewGuid().ToString(); theoryData.Add(new OidcProtocolValidatorTheoryData @@ -1385,7 +1579,7 @@ public static TheoryData ValidateStateTheoryDat { ProtocolValidator = new PublicOpenIdConnectProtocolValidator { RequireStateValidation = false }, TestId = "validationContext.state != protocolMessage.state, RequireStateValidation = false", - ValidationContext = new OpenIdConnectProtocolValidationContext() + ValidationContext = new OpenIdConnectProtocolValidationContext() { State = Guid.NewGuid().ToString(), ProtocolMessage = new OpenIdConnectMessage { State = Guid.NewGuid().ToString() }, @@ -1396,7 +1590,7 @@ public static TheoryData ValidateStateTheoryDat { ProtocolValidator = new PublicOpenIdConnectProtocolValidator { RequireState = false }, TestId = "validationContext.state == null, protocolMessage.state == null, RequireState = false", - ValidationContext = new OpenIdConnectProtocolValidationContext() + ValidationContext = new OpenIdConnectProtocolValidationContext() { ProtocolMessage = new OpenIdConnectMessage(), }, @@ -1407,7 +1601,7 @@ public static TheoryData ValidateStateTheoryDat ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidStateException), "IDX21330:"), ProtocolValidator = new PublicOpenIdConnectProtocolValidator { RequireState = false }, TestId = "validationContext.state != null, protocolMessage.state == null, RequireState = false", - ValidationContext = new OpenIdConnectProtocolValidationContext() + ValidationContext = new OpenIdConnectProtocolValidationContext() { ProtocolMessage = new OpenIdConnectMessage(), State = Guid.NewGuid().ToString() @@ -1419,7 +1613,7 @@ public static TheoryData ValidateStateTheoryDat ExpectedException = new ExpectedException(typeof(OpenIdConnectProtocolInvalidStateException), "IDX21329:"), ProtocolValidator = new PublicOpenIdConnectProtocolValidator { RequireState = false }, TestId = "validationContext.state == null, protocolMessage.state != null, RequireState = false", - ValidationContext = new OpenIdConnectProtocolValidationContext() + ValidationContext = new OpenIdConnectProtocolValidationContext() { ProtocolMessage = new OpenIdConnectMessage { State = Guid.NewGuid().ToString() } }, @@ -1542,7 +1736,7 @@ public void GetHashAlgorithm(OpenIdConnectProtocolValidator protocolValidator, s ee.ProcessNoException(); Assert.True(hash.GetType() == algorithmType); } - catch(Exception ex) + catch (Exception ex) { ee.ProcessException(ex); } @@ -1630,7 +1824,7 @@ public void SetHashAlgorithmMap(Dictionary hashAlgorithmMap) } } - class SampleListener : EventListener + internal class SampleListener : EventListener { public string TraceBuffer { get; set; } diff --git a/test/Microsoft.IdentityModel.TestUtils/CompareContext.cs b/test/Microsoft.IdentityModel.TestUtils/CompareContext.cs index 9eb02bdd6c..a7b6b2979e 100644 --- a/test/Microsoft.IdentityModel.TestUtils/CompareContext.cs +++ b/test/Microsoft.IdentityModel.TestUtils/CompareContext.cs @@ -54,6 +54,7 @@ public CompareContext(CompareContext other) if (other == null) return; + ClaimTypesToIgnoreWhenComparing = other.ClaimTypesToIgnoreWhenComparing; ExpectRawData = other.ExpectRawData; IgnoreClaimsIdentityType = other.IgnoreClaimsIdentityType; IgnoreClaimsPrincipalType = other.IgnoreClaimsPrincipalType; @@ -71,6 +72,13 @@ public void AddDiff(string diff) Diffs.Add(diff); } + public void AddClaimTypeToIgnoreWhenComparing(string claimType) + { + ClaimTypesToIgnoreWhenComparing.Add(claimType); + } + + public ISet ClaimTypesToIgnoreWhenComparing { get; set; } = new HashSet(); + public List Diffs { get; set; } = new List(); public bool ExpectRawData { get; set; } diff --git a/test/Microsoft.IdentityModel.TestUtils/Default.cs b/test/Microsoft.IdentityModel.TestUtils/Default.cs index 29a500ae03..cc6220a9e7 100644 --- a/test/Microsoft.IdentityModel.TestUtils/Default.cs +++ b/test/Microsoft.IdentityModel.TestUtils/Default.cs @@ -689,7 +689,7 @@ public static List SamlClaims new Claim(ClaimTypes.Role, "Developer", ClaimValueTypes.String, Issuer, OriginalIssuer), new Claim(ClaimTypes.Role, "Sales", ClaimValueTypes.String, Issuer, OriginalIssuer), new Claim(ClaimTypes.StreetAddress, "123AnyWhereStreet\r\nSomeTown/r/nUSA", ClaimValueTypes.String, Issuer, OriginalIssuer), - new Claim(ClaimsIdentity.DefaultNameClaimType, "Jean-Sébastien", ClaimValueTypes.String, Issuer, OriginalIssuer), + new Claim(ClaimsIdentity.DefaultNameClaimType, "Jean-S�bastien", ClaimValueTypes.String, Issuer, OriginalIssuer), }; } @@ -707,7 +707,7 @@ public static Dictionary SamlClaimsDictionary { ClaimTypes.HomePhone, "555.1212" }, { ClaimTypes.Role, new List{"Developer", "Sales" } }, { ClaimTypes.StreetAddress, "123AnyWhereStreet\r\nSomeTown/r/nUSA" }, - { ClaimsIdentity.DefaultNameClaimType, "Jean-Sébastien" } + { ClaimsIdentity.DefaultNameClaimType, "Jean-S�bastien" } }; } @@ -726,7 +726,7 @@ public static List SamlClaimsWithoutCRLF new Claim(ClaimTypes.Role, "Developer", ClaimValueTypes.String, Issuer, OriginalIssuer), new Claim(ClaimTypes.Role, "Sales", ClaimValueTypes.String, Issuer, OriginalIssuer), new Claim(ClaimTypes.StreetAddress, "123AnyWhereStreet/r/nSomeTown/r/nUSA", ClaimValueTypes.String, Issuer, OriginalIssuer), - new Claim(ClaimsIdentity.DefaultNameClaimType, "Jean-Sébastien", ClaimValueTypes.String, Issuer, OriginalIssuer), + new Claim(ClaimsIdentity.DefaultNameClaimType, "Jean-S�bastien", ClaimValueTypes.String, Issuer, OriginalIssuer), }; } @@ -745,7 +745,7 @@ public static List SamlClaimsIssuerEqOriginalIssuer new Claim(ClaimTypes.Role, "Developer", ClaimValueTypes.String, Issuer), new Claim(ClaimTypes.Role, "Sales", ClaimValueTypes.String, Issuer), new Claim(ClaimTypes.StreetAddress, "123AnyWhereStreet/r/nSomeTown/r/nUSA", ClaimValueTypes.String, Issuer), - new Claim(ClaimsIdentity.DefaultNameClaimType, "Jean-Sébastien", ClaimValueTypes.String, Issuer), + new Claim(ClaimsIdentity.DefaultNameClaimType, "Jean-S�bastien", ClaimValueTypes.String, Issuer), }; } diff --git a/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs b/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs index e3cf23d3bf..e8763e37b9 100644 --- a/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs +++ b/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs @@ -348,12 +348,19 @@ public static bool AreEnumsEqual(IEnumerable t1, IEnumerable t2, Compar public static bool AreClaimsEnumsEqual(object object1, object object2, CompareContext context) { - IEnumerable t1 = (IEnumerable)object1; IEnumerable t2 = (IEnumerable)object2; - var claims1 = new List(t1); - var claims2 = new List(t2); + var claims1 = new List(); + foreach (Claim c1 in t1) + if (!context.ClaimTypesToIgnoreWhenComparing.Contains(c1.Type)) + claims1.Add(c1); + + var claims2 = new List(); + foreach (Claim c2 in t2) + if (!context.ClaimTypesToIgnoreWhenComparing.Contains(c2.Type)) + claims2.Add(c2); + if (claims1.Count != claims2.Count) { context.Diffs.Add($"claims1.Count != claims2.Count: {claims1.Count}, {claims2.Count}"); @@ -1023,13 +1030,13 @@ public static bool CompareAllPublicProperties(object obj1, object obj2, CompareC localContext.Diffs.Add(BuildStringDiff(propertyInfo.Name, val1, val2)); } #if CrossVersionTokenValidation - else if (type == typeof(ClaimsIdentity) && String.Equals(propertyInfo.Name, "AuthenticationType", StringComparison.Ordinal) && String.Equals(Convert.ToString(val1), AuthenticationTypes.Federation, StringComparison.Ordinal) && String.Equals(Convert.ToString(val2), "AuthenticationTypes.Federation", StringComparison.Ordinal)) + else if (type == typeof(ClaimsIdentity) && String.Equals(propertyInfo.Name, "AuthenticationType") && String.Equals(Convert.ToString(val1), AuthenticationTypes.Federation) && String.Equals(Convert.ToString(val2), "AuthenticationTypes.Federation")) continue; - else if (type == typeof(Claim) && String.Equals(propertyInfo.Name, "Value", StringComparison.Ordinal) && (String.Equals((val1 as string), "urn:oasis:names:tc:SAML:1.0:am:password", StringComparison.Ordinal) || String.Equals((val2 as string), "urn:oasis:names:tc:SAML:1.0:am:password", StringComparison.Ordinal))) + else if (type == typeof(Claim) && String.Equals(propertyInfo.Name, "Value") && (String.Equals((val1 as string), "urn:oasis:names:tc:SAML:1.0:am:password") || String.Equals((val2 as string), "urn:oasis:names:tc:SAML:1.0:am:password"))) continue; - else if (type == typeof(ClaimsPrincipal) && String.Equals(propertyInfo.Name, "Claims", StringComparison.Ordinal) && (val1 as IEnumerable).Count() == 0) + else if (type == typeof(ClaimsPrincipal) && String.Equals(propertyInfo.Name, "Claims") && (val1 as IEnumerable).Count() == 0) continue; - else if (type == typeof(ClaimsIdentity) && String.Equals(propertyInfo.Name, "Claims", StringComparison.Ordinal) && (val1 as IEnumerable).Count() == 0) + else if (type == typeof(ClaimsIdentity) && String.Equals(propertyInfo.Name, "Claims") && (val1 as IEnumerable).Count() == 0) continue; #endif else if (val1.GetType().BaseType == typeof(System.ValueType) && !_equalityDict.Keys.Contains(val1.GetType().ToString())) diff --git a/test/Microsoft.IdentityModel.TestUtils/KeyingMaterial.cs b/test/Microsoft.IdentityModel.TestUtils/KeyingMaterial.cs index 9e3b2e29ec..f65729f1e5 100644 --- a/test/Microsoft.IdentityModel.TestUtils/KeyingMaterial.cs +++ b/test/Microsoft.IdentityModel.TestUtils/KeyingMaterial.cs @@ -145,6 +145,14 @@ public static X509SecurityKey DefaultX509Key_2048_Public public static X509SecurityKey NotYetValidX509SecurityKey_Public = new X509SecurityKey(NotYetValidX509Cert_Public); public static SigningCredentials NotYetValidX509SigningCreds_Public = new SigningCredentials(NotYetValidX509SecurityKey_Public, SecurityAlgorithms.RsaSha256Signature); +#if NET472 || NET6_0 + //encoded strings for "AliceInformation", "BobInformation", "AliceNotMatchingInfo", and "BobNotMatchingInfo" + public static string ApuExample1 = "QWxpY2VJbmZvcm1hdGlvbg"; + public static string ApvExample1 = "Qm9iSW5mb3JtYXRpb24"; + public static string ApuExample2 = "QWxpY2VOb3RNYWNoaW5nSW5mbw"; + public static string ApvExample2 = "Qm9iTm90TWFjaGluZ0luZm8"; +#endif + public static SecurityKey DefaultAADSigningKey { get diff --git a/test/Microsoft.IdentityModel.TestUtils/ReferenceTokens.cs b/test/Microsoft.IdentityModel.TestUtils/ReferenceTokens.cs index 4dec516bc7..9244c6b579 100644 --- a/test/Microsoft.IdentityModel.TestUtils/ReferenceTokens.cs +++ b/test/Microsoft.IdentityModel.TestUtils/ReferenceTokens.cs @@ -29,7 +29,7 @@ namespace Microsoft.IdentityModel.TestUtils { public class ReferenceTokens { -#region Saml2 Token + #region Saml2 Token public static string AADJWKS = @"{""keys"":[{""kty"":""RSA"",""use"":""sig"",""kid"":""a3QN0BZS7s4nN-BdrjbF0Y_LdMM"",""x5t"":""a3QN0BZS7s4nN-BdrjbF0Y_LdMM"",""n"":""wESLNTU4mazfVL-vLuJq_8ggJhW1DYxE-EeFiSccia1TTeyBWTVfG5vgYPtHXmL1RYgZvNhIYppS0ZT2U_nnCt8ukONCMSBpeLh8TqZxkHBr2pzbaKzbcHpHrsoxxXLHINZ6L4g_ewqYJwxfshuyD65tlSm8obFdnbtiCoVM-oJPbOcPsrzVgp_L5JWDe5bp6lbXXjJnMKVNCVqum1i4Taa6PGNm3HtlSXBz0CFWLwJ6IvAY7XDNOal3-5y2md6vqhzffmu90mKQ2ZzVwUoIr7aKt7DVuBQke434skDTLmJVcq-iOIpnYiLtApefX1KyDUWgnfHY1YDTrBzQKeu4uw"",""e"":""AQAB"",""x5c"":[""MIIDBTCCAe2gAwIBAgIQY4RNIR0dX6dBZggnkhCRoDANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE3MDIxMzAwMDAwMFoXDTE5MDIxNDAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBEizU1OJms31S/ry7iav/IICYVtQ2MRPhHhYknHImtU03sgVk1Xxub4GD7R15i9UWIGbzYSGKaUtGU9lP55wrfLpDjQjEgaXi4fE6mcZBwa9qc22is23B6R67KMcVyxyDWei+IP3sKmCcMX7Ibsg+ubZUpvKGxXZ27YgqFTPqCT2znD7K81YKfy+SVg3uW6epW114yZzClTQlarptYuE2mujxjZtx7ZUlwc9AhVi8CeiLwGO1wzTmpd/uctpner6oc335rvdJikNmc1cFKCK+2irew1bgUJHuN+LJA0y5iVXKvojiKZ2Ii7QKXn19Ssg1FoJ3x2NWA06wc0CnruLsCAwEAAaMhMB8wHQYDVR0OBBYEFDAr/HCMaGqmcDJa5oualVdWAEBEMA0GCSqGSIb3DQEBCwUAA4IBAQAiUke5mA86R/X4visjceUlv5jVzCn/SIq6Gm9/wCqtSxYvifRXxwNpQTOyvHhrY/IJLRUp2g9/fDELYd65t9Dp+N8SznhfB6/Cl7P7FRo99rIlj/q7JXa8UB/vLJPDlr+NREvAkMwUs1sDhL3kSuNBoxrbLC5Jo4es+juQLXd9HcRraE4U3UZVhUS2xqjFOfaGsCbJEqqkjihssruofaxdKT1CPzPMANfREFJznNzkpJt4H0aMDgVzq69NxZ7t1JiIuc43xRjeiixQMRGMi1mAB75fTyfFJ/rWQ5J/9kh0HMZVtHsqICBF1tHMTMIK5rwoweY0cuCIpN7A/zMOQtoD""]},{""kty"":""RSA"",""use"":""sig"",""kid"":""2S4SCVGs8Sg9LS6AqLIq6DpW-g8"",""x5t"":""2S4SCVGs8Sg9LS6AqLIq6DpW-g8"",""n"":""oZ-QQrNuB4ei9ATYrT61ebPtvwwYWnsrTpp4ISSp6niZYb92XM0oUTNgqd_C1vGN8J-y9wCbaJWkpBf46CjdZehrqczPhzhHau8WcRXocSB1u_tuZhv1ooAZ4bAcy79UkeLiG60HkuTNJJC8CfaTp1R97szBhuk0Vz5yt4r5SpfewIlBCnZUYwkDS172H9WapQu-3P2Qjh0l-JLyCkdrhvizZUk0atq5_AIDKRU-A0pRGc-EZhUL0LqUMz6c6M2s_4GnQaScv44A5iZUDD15B6e8Apb2yARohkWmOnmRcTVfes8EkfxjzZEzm3cNkvP0ogILyISHKlkzy2OmlU6iXw"",""e"":""AQAB"",""x5c"":[""MIIDKDCCAhCgAwIBAgIQBHJvVNxP1oZO4HYKh+rypDANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDExhsb2dpbi5taWNyb3NvZnRvbmxpbmUudXMwHhcNMTYxMTE2MDgwMDAwWhcNMTgxMTE2MDgwMDAwWjAjMSEwHwYDVQQDExhsb2dpbi5taWNyb3NvZnRvbmxpbmUudXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChn5BCs24Hh6L0BNitPrV5s+2/DBhaeytOmnghJKnqeJlhv3ZczShRM2Cp38LW8Y3wn7L3AJtolaSkF/joKN1l6GupzM+HOEdq7xZxFehxIHW7+25mG/WigBnhsBzLv1SR4uIbrQeS5M0kkLwJ9pOnVH3uzMGG6TRXPnK3ivlKl97AiUEKdlRjCQNLXvYf1ZqlC77c/ZCOHSX4kvIKR2uG+LNlSTRq2rn8AgMpFT4DSlEZz4RmFQvQupQzPpzozaz/gadBpJy/jgDmJlQMPXkHp7wClvbIBGiGRaY6eZFxNV96zwSR/GPNkTObdw2S8/SiAgvIhIcqWTPLY6aVTqJfAgMBAAGjWDBWMFQGA1UdAQRNMEuAEDUj0BrjP0RTbmoRPTRMY3WhJTAjMSEwHwYDVQQDExhsb2dpbi5taWNyb3NvZnRvbmxpbmUudXOCEARyb1TcT9aGTuB2Cofq8qQwDQYJKoZIhvcNAQELBQADggEBAGnLhDHVz2gLDiu9L34V3ro/6xZDiSWhGyHcGqky7UlzQH3pT5so8iF5P0WzYqVtogPsyC2LPJYSTt2vmQugD4xlu/wbvMFLcV0hmNoTKCF1QTVtEQiAiy0Aq+eoF7Al5fV1S3Sune0uQHimuUFHCmUuF190MLcHcdWnPAmzIc8fv7quRUUsExXmxSX2ktUYQXzqFyIOSnDCuWFm6tpfK5JXS8fW5bpqTlrysXXz/OW/8NFGq/alfjrya4ojrOYLpunGriEtNPwK7hxj1AlCYEWaRHRXaUIW1ByoSff/6Y6+ZhXPUe0cDlNRt/qIz5aflwO7+W8baTS4O8m/icu7ItE=""]}]}"; public static string Saml2Token_InclusiveNamespaces_WithoutPrefix = @@ -170,9 +170,9 @@ public static string Saml2Token_Formated } } -#endregion + #endregion -#region Saml Token + #region Saml Token public static string SamlToken_MissingMajorVersion = @"spn:fe78e0b4-6fe7-47e6-812c-fb75cee266a4add29489-7269-41f4-8841-b63c95564420d1ad9ce7-b322-4221-ab74-1e1011e1bbcbUser1@Cyrano.onmicrosoft.com1UserUser1https://sts.windows.net/add29489-7269-41f4-8841-b63c95564420/Ytfkc60mLe1Zgu7TBQpMv8nJ1SVxT0ZjsFHaFqSB2VI=NRV7REVbDRflg616G6gYg0fAGTEw8BhtyPzqaU+kPQI35S1vpgt12VlQ57PkY7Rs0Jucx9npno+bQVMKN2DNhhnzs9qoNY2V3TcdJCcwaMexinHoFXHA0+J6+vR3RWTXhX+iAnfudtKThqbh/mECRLrjyTdy6L+qNkP7sALCWrSVwJVRmzkTOUF8zG4AKY9dQziec94Zv4S7G3cFgj/i7ok2DfBi7AEMCu1lh3dsQAMDeCvt7binhIH2D2ad3iCfYyifDGJ2ncn9hIyxrEiBdS8hZzWijcLs6+HQhVaz9yhZL9u/ZxSRaisXClMdqrLFjUghJ82sVfgQdp7SF165+Q==MIIDBTCCAe2gAwIBAgIQY4RNIR0dX6dBZggnkhCRoDANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE3MDIxMzAwMDAwMFoXDTE5MDIxNDAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBEizU1OJms31S/ry7iav/IICYVtQ2MRPhHhYknHImtU03sgVk1Xxub4GD7R15i9UWIGbzYSGKaUtGU9lP55wrfLpDjQjEgaXi4fE6mcZBwa9qc22is23B6R67KMcVyxyDWei+IP3sKmCcMX7Ibsg+ubZUpvKGxXZ27YgqFTPqCT2znD7K81YKfy+SVg3uW6epW114yZzClTQlarptYuE2mujxjZtx7ZUlwc9AhVi8CeiLwGO1wzTmpd/uctpner6oc335rvdJikNmc1cFKCK+2irew1bgUJHuN+LJA0y5iVXKvojiKZ2Ii7QKXn19Ssg1FoJ3x2NWA06wc0CnruLsCAwEAAaMhMB8wHQYDVR0OBBYEFDAr/HCMaGqmcDJa5oualVdWAEBEMA0GCSqGSIb3DQEBCwUAA4IBAQAiUke5mA86R/X4visjceUlv5jVzCn/SIq6Gm9/wCqtSxYvifRXxwNpQTOyvHhrY/IJLRUp2g9/fDELYd65t9Dp+N8SznhfB6/Cl7P7FRo99rIlj/q7JXa8UB/vLJPDlr+NREvAkMwUs1sDhL3kSuNBoxrbLC5Jo4es+juQLXd9HcRraE4U3UZVhUS2xqjFOfaGsCbJEqqkjihssruofaxdKT1CPzPMANfREFJznNzkpJt4H0aMDgVzq69NxZ7t1JiIuc43xRjeiixQMRGMi1mAB75fTyfFJ/rWQ5J/9kh0HMZVtHsqICBF1tHMTMIK5rwoweY0cuCIpN7A/zMOQtoD"; @@ -241,7 +241,7 @@ public static string Saml2Token_Formated public static string SamlToken_SignatureMissing = @"http://Default.Audience.comBoburn:oasis:names:tc:SAML:1.0:cm:bearerUSABob@contoso.comBob555.1212DeveloperSalesJean-Sébastien"; - + public static string SamlToken_Formated { get @@ -314,9 +314,9 @@ public static string SamlToken_Formated } } -#endregion + #endregion -#region JWE compression tokens + #region JWE compression tokens /** * All the following tokens are signed with KeyingMaterial.DefaultSymmetricSigningCreds_256_Sha2, and encrypted with * EncryptingCredentials(KeyingMaterial.DefaultX509Key_2048, SecurityAlgorithms.RsaOAEP, SecurityAlgorithms.Aes256CbcHmacSha512) @@ -334,40 +334,44 @@ public static string SamlToken_Formated public static string JWECompressionTokenWithCustomAlgorithm = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJraWQiOiJBNkFBMUU2QTY2RjY3Qjk2MTVDRDFFQkZBRUExNjk4ODJBQzU2NjBDIiwidHlwIjoiSldUIiwiemlwIjoiTXlBbGdvcml0aG0ifQ.cM5I0koddmiWcUrjwwGXNf-o-FyL6fKHtfW7YPxLgMxtMm4RXQJB_tjh3FJ5J26V5WUE0V4G1FOGYBIaJYGAFBN2MgXdbkWlCA8bGLTOHm6TZBtuEIikZb8_Uv7tfE8_5VHgeBN1hBu0OsYaEeU6ai7lVH7bE-u8xro_glChjO6DZKrCG6Yf96mhcyMF6WO_bDBlHIeFITvAhfy8d9XwCFVlsLMfQQimZ8QNMC-KBI2ueOp0xCzGOjQhwllaWXbOQb9HFO7AHO46-6E4_z9r6cJA1CAMbABG6lmanae3CE3h11YhdnAxsGl3b6jA0WGJSwQ6J9eIEb-ISuQSaFUyXg.quBNboK_nzmnnPPbPkp7Tw.yEXS_p_qHxfFzGs8a6lutTdJMZob4tA5Zb3PMMOfS9yPM0a_Zq3N-g2cNB-giieDXeOwAe5dDOIXIVxDX3B1Wb-GQoAfQ7EhQsV8FhdUTSNa9iV8rDbUGgMnvYI7aCGwP5uVRkyZlvC9YfTTkklTwyYYso6DEvoqFqoCow9wx8_t0fljGV1ZeCXpGAMpLOJgbSHlar6xxpQ9Wbf0IR4EyUaTvk6v51uRGpLwCpbPXXO--8mmWdRmztOR53zElLkQhDyq6brlrDzWJQ-IS5-JOCO--hvAVdsuY7feDKo7tYW0bErYIy5GLvNIxY0VgqJWkUPbtNXSoPhLNG-ZHuu9m0x9PHrTA-wZV8Lo1DVtxer17WHoJr15RD9o6L0zszTEXH0MEJFwiFr_mrz4lsmoW-WuLP4MydF-Fzt8x5s_ZsXXbdz9hdT0cPMIm-Ed0__aATp_FxEcp87dH_ViNVIC5NiePI_chW-2SS8VYgGOWWg262IeqnsR1G6R-7Ey3QgZnboixKYV_y0-497mJEYBA6MkXrhdsofOR-Gy0Y-WlSgvV314pbZT-cF62a5ZOT37NrsJ3_3P0oo08MBfBEvJI3iRqiZbNGlHpPW0Pg53GYtbaGWhFN6sx3Tg4EUgUWse9rzqpQYw_7Sf8wy3knUN1Q5PJdPWHIS5QJBz1ts-jPge3AqYtbltzJgDaYsiGVvVq3UM33G52jHmU83cHdcZPTdJw8jSSr2DBdbB_Eo2jfzmIxezN7EYRtMUIBSNuh2-PjHRxf_gW_z12UAeOBw09aelcHH2cUaHZvIHxoNxQHn09rPlMKgF7AxOaKiOZiIqznQTzGtgFCzbCIf7AohkMOuzjbOwvdKg0blHIIVWJbFhmEDustZKAeQ6PoruFjTmFt2AZ7X5Aqxwqed9ubjJVqLV-RMf6muA9Y_mOCBNaDc.0UOmt5CyGX9IylnQAPcc2UsbyexhYkcchrI6ubgZEbk"; -#endregion + #endregion -#region JWE tokens + #region JWE tokens /** * The following tokens were created using . **/ // This token was signed with Default.SymmetricSigningCredentials and encryted with Default.SymmetricEncryptingCredentials. // This token includes two additional header claims: // { "int", 123 } and { "string", "string" }. - public static string JWEDirectEcryptionWithAdditionalHeaderClaims = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiRGVmYXVsdFN5bW1ldHJpY1NlY3VyaXR5S2V5XzI1NiIsInR5cCI6IkpXVCIsImludCI6MTIzLCJzdHJpbmciOiJzdHJpbmcifQ..Jph7tSiacUx4bdAlUZE49g.sOsePYxZ44SXyynUeLwvlw3Q0SioyNtHFy1AdYEuk4YC6U_zhAFC5jRPQf4wymjB7WMuqHLkj0uv9f6hRtvefWJA-yF9UOUUaBln5u6wtliotiGDh0JcyLpOLjuZwqiFj0rLe-6VoowG_1hbXmYrpb8jtvu23vib_cx-hj3vjAUiIgD6Gay7xgh9yPoxzbsEa4enzOh7Cgc-Zlv1GyC4B4Pj4AZ_5daabz62YGsu2DyffRqA-BNezICoYErw_vAs4SvhvzaE_b4_N5IQ5cwlGeNAVTPGabkYCu2D6oMGF2QDaebm06Fpr79kFni35sz3CERWzHt6sGSQT3sxCm0e7ORtM11d0O34oLmkbUdrBZaB047jv4aACK2MCdOWwvwNUSc5jE3rInSGzcKGistq_mmIBTWe0pZqo6k3cNJ_NTz6WL_r48f9p9rAe5wAR9ZfY_o3AlwHhKfl-Mhio5lfANKk5PylQcsOqWxBKrdbXznzQZ9eyluDpxNxdp62JU0jYvkUW2rjfmku-yh5A5qcgnMzqyDcunS-My8tbnyJ8XcEiEbq89cMrbe-4BGy1bha.djjhS_qNCs4dICnfw7676A"; + public static string JWEDirectEcryptionWithAdditionalHeaderClaims = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiRGVmYXVsdFN5bW1ldHJpY1NlY3VyaXR5S2V5XzI1NiIsInR5cCI6IkpXVCIsImludCI6MTIzLCJzdHJpbmciOiJzdHJpbmciLCJjdHkiOiJKV1QifQ..C-8-f1uCz2JnM2V5034vVQ.oRaUEE3FPy4H72hicODQkK7m_0XjUOug502Uvds4DeMaR5EBxpyP8zz1_YXOLu736LBpSqS4Uy3MAxqBcUH3i7gMk-G53_MtM0voQxDvW9bofBlxzCsGC8cfz0wrrFskaU0rO_30N8YurOHsqCTCUguPqgrY18U1Z12VyBw-bxeKhERsT4uz-i8D0ZN0u64Ls1Z4IFTiQwpv7ruuTFVxXQOdSqW-fru6YIatqmOdXcP6ARgSB6FkDazi_LPwKQXDsp7NTKubyKfSIE2imGBisS78pgAS0edzs76Hk0r7zfkBBYF5PybSB33lSlPvOM0TViDVYPjEbrKec_UmvzzO9Ij1CcaYW5RR9F4c7n6bszdp1e0hIXvSg9YoxZA87saG2n3VBrKbXfwHhKqqPVt_Z2WSTfHkZ-XWQDd8sJEwVxGA3M7NkqLthusdy7HsbiXkQfkRZkNkhPD0Iw0tANxcJfCYgTU9RUTDAxt1RfiCJhxk_H_6xpweHhRDDACRnWd9lYn_A-NB1gIqCe0oI31WzqmHNLSRobb2FY1VSyjpHbCMn07HdhidJrDiYw08NO9Z.ZyVjUgWJd7B1fR4ftWPe0w"; // This token was signed with Default.SymmetricSigningCredentials and encryted with Default.SymmetricEncryptingCredentials. // The value for the 'typ' header claim in this token has been changed to "TEST". - public static string JWEDirectEcryptionWithDifferentTyp = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiRGVmYXVsdFN5bW1ldHJpY1NlY3VyaXR5S2V5XzI1NiIsInR5cCI6IlRFU1QifQ..xJEJ2ClTfUIvjzh5wtS-ow.N-0XvCnAcjp5C59LiB7G3EO0XL7S9ILsDMgwqRWQ0bXoBgKM9GUhCRByft24iORAD5NOKBvs7gt3kbN6Yek5q7I3fRYUZBJlcA7tLhmdl3-XU-N3H9Z0du7NwOZPlytqNJByF0sTsz5MJDUo2BvBZ7tb0g7G8240eGnPBBOTyA0q6uEYQJSoxUKL-_-rkwEudyikTgVrlFOCTtaZZDUXPrT4406enNlXwel6PpYnZq_hxoAzS1tfZZpaW0lpg-55o4d6OiXu143EUq-JXMUDieln1AoKOtsBXM25JtXzo2QphP5PzM-knebR4PusOVupm44MTGZRjz0Upmj2DKR6wblO-Hc3U3LJIRR9FFSmAHew4QFKbC7I1KKvbZ0UMuHulnZR9DiE340_N2RKn0Odo4goXyUDLGcUolF5JthXE8ljIixbmbDgfalbFTlqbsLtbvzbZRRjspYACuB7kVkh-K6fyNLuawvkC_IgTKjFxAWDnFVaPirf8kYm-ckbyZmEhDyvMtVeREjTXV6jWW_mynwCHy78-cst8PAVSnsdQkLCYntAf-ZNhxLSTC9WlE2k.prYwXw1nKcjTCUrko6HF7Q"; + public static string JWEDirectEcryptionWithDifferentTyp = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiRGVmYXVsdFN5bW1ldHJpY1NlY3VyaXR5S2V5XzI1NiIsInR5cCI6IlRFU1QiLCJjdHkiOiJKV1QifQ..vFA0IavkWL8XJVXez8dShg.dsiA6xvBzi1M4PZD8-qXHi7NKMCl-3HDyFbVTGv7JDwg7Bd7x5MUo2qL0tQgf4gLIf_a1EBpSquAM6YyKjvEbNcqoM8dopw_J0s2sPn2f5BPyZjI7IbysV7GVEYG8sESPy9xKOo4mUM2nmWrOa5Ua4Hm_VfAATnUe1ujx3XmuiZG3zFWK7s5cMOG7qVqOurLpmb4wQplaKqjSETr0qkSQ9BSGtIsziy3jphJkAaPwwXckcGskOUHFLoDeW3_M21uGHnBGqN95gBsIy6BCgv-Qs1yJTcFDUrJtFDn_TGNkyxhwjiMDjZMaLQ4ZXxEH-B32GDDNcG8VeBGJvgRSBbnXBEx4u1zyOPZAAFl5RPPrGI3GPCgcbORWf91nz6ewDqc4j8qwL6PpqTGjmqVkRzTvV6oMaJ9aOmCy__8U4wntn8A2nwWinfzCjb9QXL4ozSPCQilcebW034N_P3zyFZWq17xgG1u4eCVOjnib7Il2nCX0HMrOv49Hs8fFxdqy-xVzXqwJizGRswjYMVBpK7bHD7WFZtA10oQQ--ypoSF4uCdQOAyWq4pfH3vX6gCjpPG.WyrC70H_YtZFmyCSiU4IAQ"; // This token was signed with Default.SymmetricSigningCredentials and encryted with Default.SymmetricEncryptingCredentials. // The inner JWT is unsigned and this token includes two additional header claims: // { "int", 123 } and { "string", "string" }. - public static string JWEDirectEncryptionUnsignedInnerJWTWithAdditionalHeaderClaims = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiRGVmYXVsdFN5bW1ldHJpY1NlY3VyaXR5S2V5XzI1NiIsInR5cCI6IkpXVCIsImludCI6MTIzLCJzdHJpbmciOiJzdHJpbmcifQ..Z1hcrcpQf5jXayinT3rF-w.znWveolvSaum8K_PywIM52ByvxW0qbXd2cOMxqb-aHEiawZoCeXais4AnIAN3C4uVRdBQ38HfHq2QeMsnGSO1N1BS5baIXB_5bs3-WHo2CMCf30pjDCSNt9wDMCSUuwf4oYZ8yk55ibl0rnebWJ1K8NkpXRrIpALnkixsyG3tLAVM5tI8d3zP52IslmvSL-LpReX0MXp96odi5NmQm9G7C_iiEE7QMbmX6DcCJMPCVEhpBeC7SfrPW6r2GMjaRfp451lE0uTEY7g70nJO44uOMg79DNN6RgPcj57tF_UH-G_RudS94Mk7x-ojMlZk3KyOqTIkoF8QxmavapKNcuEBEJlLIw_B0ljTDff5fMdLys.5dLQqOaiOSkVOO2BwqLShw"; + public static string JWEDirectEncryptionUnsignedInnerJWTWithAdditionalHeaderClaims = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiRGVmYXVsdFN5bW1ldHJpY1NlY3VyaXR5S2V5XzI1NiIsInR5cCI6IkpXVCIsImludCI6MTIzLCJzdHJpbmciOiJzdHJpbmciLCJjdHkiOiJKV1QifQ..IaH2b5aXOGuDnI04NUt74Q.QwNrngDbHNY-CE_7QghcRuiAT5GwyGC5QwJdVzbW2kQ4HWwKOpqZkPmI49Cs6Ha537aVVQmanC28J3Zzldser5e1xJ6QT6IeeF0y2y9d4uM1ljT997tu9sfhAm8CmMOyw_FC5WIJrE7xUmvyBisSCP2xsFxItaoJcl9IlGdM9Av4bNp3S5ogJLps-KhWsNQ_i23yrw5HXYTWCRye4QfrkoraO3MbPU8_Oqo5CzJOej9qv7Nd7nJa_u7DDL80oiec2h3Ou0022IJ3nfPitOoUJ2r8yS1JA9w9xC7GEsPcvEQi4E978wjLHRR3KtEY5Mu8aGpUTtyMJKiRBkMQVq9C0fLQbOsIh0yDL6oIhUfOHhY.Y60oz4iBJvvZuItFrNlFcw"; // This token was signed with Default.SymmetricSigningCredentials and encrypted with EncryptingCredentials(KeyingMaterial.RsaSecurityKey_2048, SecurityAlgorithms.RsaPKCS1, SecurityAlgorithms.Aes128CbcHmacSha256). // This token includes two additional header claims: // { "int", 123 } and { "string", "string" }. - public static string JWEKeyWrappingWithAdditionalHeaderClaims = "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiUnNhU2VjdXJpdHlLZXlfMjA0OCIsInR5cCI6IkpXVCIsImludCI6MTIzLCJzdHJpbmciOiJzdHJpbmcifQ.sw1A_ikOQlAroR_AAHGoe2vUA7ps7vQo8ZcNkprBaLSf0YES6hnzml0XeJ0gYjOumNAqZNxpWE7Jre1BqiK-o1uINjRdoOlgF62S-2Y2PSPlU202jzJhBo9OQMJzgpKewMFtR0poLtXvzgWpwI-scETh0IrrQ81zhwx2ZmaFaeJVTesZTNT_cE-MFE_xTDIv_sklpbBtcqdNdOUOSgPxSrsd1p2TG55w2FP-EvqoESF-F7agyK_szFaRCICIgz82VUUkp0Z1t6QDgNUw-lGpDV25w1REmT0y_I8j2a-9WlycVUwvtNXQxTZ5LeGyug9xAG_stomneYwqOwQXIOS04w.-OEPy1izi1LaiDQ6UmWzPA.phUKIJBqBdjTplTwZk3xI8GP9qN5TqKSPz5p5ix-GnAG4RaZg_XvsLlX6yFh_PBjp15Cd9Myzo9QnGUHd1fIGUkuCqS3fV1oLFHePEMx2b4HfHeQOXGNNnBg9PM0UEjTOmxhe3fq-c4o45nvmHz9jmC3sWJHK4Ev4GXSIrmyxC0_2vs81gspfeFg72s-azBFzhKNcUwhtniTFixregY722ezhEE5XLhB861G1hWqkphiMN-MAW0jAHtyWfyy4S4PV7ysZihQqU4DyjtYiSE36i_vV9lofjeXmPQp4yl529cawEFE2i3rQc6uP5vfBRkU08TokFdNA3O01DgsUhjzJ4VmWD8Z8zAYmu7YQwcLGGNZlYvRdVXnkxQkvITo4lRi7on05wo14VT46rNhmRDQ8r56b8-qgpODC60qLK9YhhsSTKhhsRUU-W4HsrkOopUjrHdzmSevepm81ISev7ZoJp1-9wSUomsxFaz8liux7wugEBkwqKhJh_tvclyUEq8Ta9pKDwvTExhycAlRKz-L3TwbHa4MIVaAXIR0IDeRV-0Q3DDE0TEdtLMK31N1pVmU.hsQ5f1Sz8lBnQPWnjnrX4A"; + public static string JWEKeyWrappingWithAdditionalHeaderClaims = "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiUnNhU2VjdXJpdHlLZXlfMjA0OCIsInR5cCI6IkpXVCIsImludCI6MTIzLCJzdHJpbmciOiJzdHJpbmciLCJjdHkiOiJKV1QifQ.aup73T5pXH_YXAu1tI2Ahyii4GSm5810Wr39YPEH_f6O3N4LDT_bKe63A0QVrqunHy8cT-DZTEuU_DDWq434IFFNWQ-o7F-4iutFH5oMXPsA8WT8nzlfMR9HXAVpZeiOgQGwh-DtStf7ZgNSqETzBJFyf0WCYCYcXqGbpDUQeNvQ-MCm-a9I-RHJKez2H7GQMZayWOCrrp3GoO-2_U1Qmzw9WILATUQykV-l5S2xYfW61EKiZC3oxGe89zgFN9EEjqIC34Na89b1KmwHMedJtxLNI4bDNxxv9xK7DqdOtbaEkPzYb--muIMNteaYycPdXOUY2xx3UBZZ1yVUzrFJDg.Fei3ubbZ3oNtaoqFhb1lzw.fdkNYZff2p22rQaB-nh1KgIADWSw7BDkDkIMfKvGOW4MpACgE1VAtYDPJQQFGwBdC-83iRL8RQWAYoGb2baOGVPq7NiVeRgcTqe03w8Knbeh-fEPWfcjE3kaEBxssX9JpKA6YcaD_mkkpg9Qx32BpuCgo7w8hnDFv29nGw75rusHrlvOHK2gxSGCqYNAV6TF78tHzLlsVuJD4t0DCKyfw91fy6cX8lWqfqik7aZG1fAUjUJ3KUTIEviSx1iGgqaLsN1A-QdVzVWJTwmWgIoZVR5g4nbWwdqGAE2xkWrmuMOSGBuyU95OE5rjvcOjBsPss_0Om1DzlN7CjsErjpa3ExCzK9e-ifyS1fwH_LjO06x7gtqhOuUw40Px4uo_rzDCzlGGFeUe31w3icGOaSqnBka6H8dJB1If98h3Hwx3g_CcBVmEwlev5MFJKC0M5au52ulyuf2X-PvdLKp5XBUFaHEdJDkgciXDzmDIL9J_JFqfyfcuQhh90PCHFFVXOnlJELpCM8DXKV8-oEl8BcvB26lvuOHCwQbUjjGRNZIJU6P7GEV1zVJ6dnIjE5qPUzXJ.LiHXY8UmlG0vNt5t5gRZhQ"; // This token was signed with Default.SymmetricSigningCredentials and encrypted with EncryptingCredentials(KeyingMaterial.RsaSecurityKey_2048, SecurityAlgorithms.RsaPKCS1, SecurityAlgorithms.Aes128CbcHmacSha256). // The value for the 'typ' header claim in this token has been changed to "TEST". - public static string JWEKeyWrappingWithDifferentTyp = "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiUnNhU2VjdXJpdHlLZXlfMjA0OCIsInR5cCI6IlRFU1QifQ.4O-5-yN67fG2iEW3dvViUN9mj3hIHXhEXkf3_8YbvDqQz91hR6A2vrNQMAx5H8SBJvcKUj9xtMvs5yT4bSXJijN60xXJeP6SUyxxC9IlMgeNIlguJSeBGDxD_Oka1DKYdWjWO50LrvuD2FR99vpLA8merOmOXTkePrYb0Cgz4lPwHVrEuOsRa_YSg6FwHZS_nTKwHH6A5Y8Jo9m8IAIxWMxTeUksOip9kzZetURWIMrYToQIcwCESv5szAXV3uXMUa2veESDtwSTXOJc3GkzTt22vcxk5plRnX9vWT2cwKb33ZeX7SMJwd8OweEb47d93L0YJklwPIFuUrjPztyNCg.bI0Xb6prW9z6rQhhF4hDUg.n6gBVp7MVKU71lzYv0yJQsIIh05veO9Ee26C44Venp2KkqDrsHkUxAOGuwCEzrJG6e2H4trPa5mv8Nwi9voTf_YAtQyrZVojMD3N3Apqsl9vDdxV7yyOz1Y1LsUhkriWV3YgkRtlW8-oqKXDlkDlWv_o47aFOv4zqwn8xx58ohg6des0PjyKb5dORtSKmvAoIxBUlDN2vp9gEquZiRQSFjFKw9bK28rklf345wFB3MnLxPk2JVLXHk3IjggHNV8BR6fi38ViFzKD8uFO1pvNc_balCJWGIPUtOGU0D7paJWbzCHnjKK_SohG7-dBIPPoynSNRz5bubRuuIAvhUC2cjVCwp2KNV1_V3Tdaw9qo_x32TNIL-wO0-RNyKJB5SxTiEjO2xi-I5CGPNNf-yzRrwqfjvsF_3_yccdbNT_VleCwnBp403A4rnmq8Pa2nLB3hHL_Uv2qvkSa5GuJYyLtMb93mr_fyCL21KS6TlL5uD_x91oQsAeeT87bKnmP3RI3kgmR2MhXIQVabkI83rNpHqF-YyzpOIFMCtLN0ZtilbKWlc-0cxuoh2zJy-Dek20_.nk6ecxkk77wf-qSG59QwEw"; + public static string JWEKeyWrappingWithDifferentTyp = "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiUnNhU2VjdXJpdHlLZXlfMjA0OCIsInR5cCI6IlRFU1QiLCJjdHkiOiJKV1QifQ.GfOOyLBN3pEAQHVKlYB0AIaktBi33eBZdPP3_Lyv4I3KqNVyFh3jC1uj_uQ14s491ezHGaWdOwpR_j2Uxah_taDgFZ8IKp8yGNEKL-yrl1MdrY5nq2sgzlcsvW8dG73iMSn7fnzr-bpgiAIvHndse_PfEuvB-glj4qGarWE7rp-Fg1DhnhQpK1z3C075R3eAnWQkQd4euN59hmdvWcpxe-zS5eMHSNueoX9gGQ-1Ow31eqGL5A4RJXmOi0o_5mzc05gz2n2JNY4_pg-olqcHkx3Oh1dC_R-zWQKjy2DkZFa19D0lPc13ZTKc-ImQVtiQWhB-mPdUB3taJHbRhBbm7w.q1Nas2R8KWysJ9Sc6UAZuw.jOaIHr6zef7VRMVmXfEwNMZ2nuVQVp2IRG6BnZQ-FKloKIjg5eFTxHSaGMQaKMHWGqiFEz56FhsknJ2FqpcYZxZC37TehcMrSf82KEitXVFiLj7n-ojH-2QZUiUUiCs1R99AeTO3pdCdhJ2dOhexPkybcryyH-ls6BOFURFdNPVpJQHfXeQ6hUDiv3hDYmEEQFR0S-eJJgrJlvFPhWZFBfzHhGjJcmIBJDnr8aQyg1Q4kNYfxOWI2kWooxLtT31qNZKOzCmkSPQ34OG55GCZz-WQCeXiZQnFPPYfIotQd_huzEfd0RbschDxDcXsv9QR_g7QssY5hgRCy6j7_ZMMLqJyc9G0JR-TmR74o1gXstMTTXxTFVZ05MC-_cjml7ZH7O8GIbuApYNV3vUFJIN_NkTCl2NZVL4RiXF5rTG8ggKkPlUM6GtQ4BkLk4dWnf5iTlTxNwVJSzrztS7LmGSCHIwE33CkoU4beFNB6E1xjxH253QDkn2H0b2N5jDMddKYfTV2cQ-9NheKsHCu_lrZ9qdecq96loqFOLhbk50y368O5t11ggIiCT9IYoNhQoP1.SVpBa3ZbGyZBHoFZpLznqg"; // This token was signed with Default.SymmetricSigningCredentials and encrypted with EncryptingCredentials(KeyingMaterial.RsaSecurityKey_2048, SecurityAlgorithms.RsaPKCS1, SecurityAlgorithms.Aes128CbcHmacSha256). // The inner JWT is unsigned and yhis token includes two additional header claims: // { "int", 123 } and { "string", "string" }. - public static string JWEKeyWrappingUnsignedInnerJWTWithAdditionalHeaderClaims = "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiUnNhU2VjdXJpdHlLZXlfMjA0OCIsInR5cCI6IkpXVCIsImludCI6MTIzLCJzdHJpbmciOiJzdHJpbmcifQ.UuIMP7ipqfWl0fjWpgUtDQtn9YVMy2_r7oQ-3moQOjQP_sfuxTPQ8LwlgSxGqZ42ihfzyZJ2RjuyQPETi_CN5t1T7EJzdLfjmLAExanc4XjtveKxcKgUxPfq1izIRzn4ceEswfbFqFRSw-MG5MiyxwZN7EMZFtHQZPbJFLZuOdtMUcNXCIbaJTRdyWHrOqd_3PoGJG29puuhbhTdWbK3qtrpaLULf0wUcEE5GL5K8Ob8f4XqKTlaF5t_QZOD1P9rtEiFvnF0Iw74yrs-cv6mvG1AgEG5AcfPH9mIO7Xul6o5KiPqaMsJ2PZSJ2CApeajWgdtgfxeUn8HUecss20P3g.XSpcWjCuqG2VBKhloR8DHw.LbUjGDCLvWxR1nxf_YKpTr_9Bx4OtivIgileWVFA8gwYqV73OSrt1TeuGOEdNrIFwf0uZomNSL7WWOQqrwGqpXL4I43Mua8SkG5vEACoXid_aTyo0ANil4ujnBBNxwDHopF0a-sH0AZGNsiaSLPwq2DjLq34Dg7YsWK3Y4BJtpGuXeJJmSxdn17uZFuJ3ptPdh29YRlWPl6wke6fWfotS95O40ydg-eGqcrdOVpm4Ccy88QEzT7zOW0NRFTGAh3dI8SrzRlKPh-f-uCyRWYkL4gHLty07g23PnsCj6w2xccI5iqcCQelFBouJhOqDNSrga0mdwfZ6dOFle0zTBrHDsdFNgEpT2ruhZS1-BD05ds.9s3x86R6cDfY8q-IvQLIRw"; + public static string JWEKeyWrappingUnsignedInnerJWTWithAdditionalHeaderClaims = "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiUnNhU2VjdXJpdHlLZXlfMjA0OCIsInR5cCI6IkpXVCIsImludCI6MTIzLCJzdHJpbmciOiJzdHJpbmciLCJjdHkiOiJKV1QifQ.4ZV5pdLrOjukt51gFAHhSDnR6FCriOjajEsxSBslnZhwtp9p0KKpYf5XeT7LIXRoj_iSxmKagCN33FGKjgLsMSqcGy_RhF0nAZdhKvRnfw6Wixa342zw44Pq6aaHcPRAcMlebYRsFjNB0aTYhTcGZUGB50011yCeDeJZjevFA4VMh_QXqXmiigX1hOqWSDDKamAETT6q_WIF51lLqjnOvjW8vuVe5axX1yA0pEbIjCsAuAJN5bJq9sc3McFshDgd8Ysr4rrMS2HobqUAlafuIU4eZofAixOtkDJuu0-RN9OETT2_DzAhwBxMkgQ3LZh9Ss66SeHbJJeYtE1Qv_Z7Lg.w1uj-_N4Puy16Rn_qGwFNw.9kZxcc5SSJ9C-I5wzpwLdryKXi4v0AsPY2TL1hsELtHIANcW3xTuIhj0ludvEEPuErq0pYulnJW2IBLWrqOZIqHtkz9LrSotlbx9ts14XeGQW8hvfPBdNXjlejGf2QggYqLnTxauW6gBnOarYDfkv5snDCw6Niuxnpq7VsO4z7mON_9JbB8MTxmIPpO3Q0sw0Yp942dfiVe6QgDff1czv3QUITSThEPPGxas4eoEc-l3bwLy3-m568Zgk3snKLRXMjjDMzzoFxg9Blrp3RZXP9nA-r3R21-7cZKXFbb6BzLsaiyyDcnBq6VYNELm80U9T3mMGpTVN0OOmf_S0pLqNpNXLFbsLH5mD2h1MT69xBo.T520Y8V3Dvx0lGVUB8Oi-g"; + // This token was signed with Default.SymmetricSigningCredentials and encryted with Default.SymmetricEncryptingCredentials. + // This token includes one additional header claim: + // { "cty", "JWT"}. + public static string JWEDirectEcryptionWithCtyInAdditionalHeaderClaims = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiRGVmYXVsdFN5bW1ldHJpY1NlY3VyaXR5S2V5XzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9..xrukZ8CBmmDBe10fwAoOng.SlxANnyUr--zfFXJ7LqgUzHIMPzGZ0uLdxJnXSINu9j8wINKA7uqIJ4HqyuSOjGg9-3ydx74X0uugqgjMs4yJ9uT1N-TIEJgBmb8tEwkWE-_HXNDLJuD3I9b6uWk4n6MJIqXf9ukPDsy8tK_fZIYRKWtOqz1CUnvdcaXSDJwLiBPabcC64rnlVI0ME9xQbAPZk7jE0OxdKagYGk_MQ2fxlWaOsdHnHGSPXpQepF-X2qytjdCIbHzZBjQ_n_P3SX5LsuXEOSwgqLNYsvh4SGDKxVnxZw1ePozyiNFFsF_rF6HimbBFkLUcQS543edujDPSDgjDdgMCMoMVQWz0hXHfG7uVb0Mq_yAxag7JY49BORRnZzS4MhogCbXida3YqucX4_cM8mSzeLCbwEcL35kitWibNKtfiWPFDYzw2Brh7jV1l49kX31Q6nqX5jB183emKgE7d2fimfZWTJA5nM_NG7l0B_oInwIv5JvB6HFUWX3kJgds3UOH4zYOe2paVuSj0qsLmzEknYWe3P8mou8ItW8353_Ts2GtU5CiiQu0aLXuJBPhMzK5Zgk-0S_qF0W.pEQ7c9S6GW6hYe3-OQBwVQ"; #endregion #region JWS tokens diff --git a/test/Microsoft.IdentityModel.TestUtils/References.cs b/test/Microsoft.IdentityModel.TestUtils/References.cs index e30cfd4749..6eb7e53f36 100644 --- a/test/Microsoft.IdentityModel.TestUtils/References.cs +++ b/test/Microsoft.IdentityModel.TestUtils/References.cs @@ -25,6 +25,7 @@ // //------------------------------------------------------------------------------ +using System.IO.Compression; using Microsoft.IdentityModel.Tokens; namespace Microsoft.IdentityModel.TestUtils @@ -490,6 +491,132 @@ public static string EncodedEncryptedKey } } + // https://datatracker.ietf.org/doc/html/rfc7518#appendix-C + public static class ECDH_ES + { + public static byte[] AlgorithmID = new byte[] { 0, 0, 0, 7, 65, 49, 50, 56, 71, 67, 77 }; + + public static JsonWebKey AliceEphereralPrivateKey => + new JsonWebKey + { + Crv = "P-256", + D = "0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo", + Kty = "EC", + X = "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0", + Y = "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps" + }; + + public static string AliceEphereralPrivateKeyString => + @"{ + ""kty"":""EC"", + ""crv"":""P-256"", + ""x"":""gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0"", + ""y"":""SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps"", + ""d"":""0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo"" + }"; + + public static JsonWebKey AliceEphereralPublicKey => + new JsonWebKey + { + Crv = "P-256", + Kty = "EC", + X = "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0", + Y = "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps" + }; + + public static string AliceEphereralPublicKeyString => + @"{ + ""kty"":""EC"", + ""crv"":""P-256"", + ""x"":""gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0"", + ""y"":""SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps"" + }"; + + public static JsonWebKey BobEphereralPrivateKey => + new JsonWebKey + { + Crv = "P-256", + D = "VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw", + Kty = "EC", + X = "weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ", + Y = "e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck" + }; + + public static string BobEphereralPrivateKeyString => + @"{ + ""kty"":""EC"", + ""crv"":""P-256"", + ""x"":""weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ"", + ""y"":""e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck"", + ""d"":""VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw"" + }"; + + public static JsonWebKey BobEphereralPublicKey => + new JsonWebKey + { + Crv = "P-256", + Kty = "EC", + X = "weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ", + Y = "e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck" + }; + + public static string BobEphereralPublicString => + @"{ + ""kty"":""EC"", + ""crv"":""P-256"", + ""x"":""weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ"", + ""y"":""e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck"" + }"; + + public static byte[] ConcatKDF = + new byte[] { 0, 0, 0, 1, + 158, 86, 217, 29, 129, 113, 53, 211, 114, 131, 66, 131, 191, 132, 38, 156, 251, 49, 110, 163, 218, 128, 106, 72, 246, 218, 167, 121, 140, 254, 144, 196, + 0, 0, 0, 7, 65, 49, 50, 56, 71, 67, 77, + 0, 0, 0, 5, 65, 108, 105, 99, 101, + 0, 0, 0, 3, 66, 111, 98, 0, 0, 0, 128}; + + public static byte[] DerivedKeyBytes = new byte[] { 86, 170, 141, 234, 248, 35, 109, 32, 92, 34, 40, 205, 113, 167, 16, 26 }; + + public static string DerivedKeyEncoded = "VqqN6vgjbSBcIijNcacQGg"; + + public static string EPKString => + @"{ + ""alg"":""ECDH-ES"", + ""enc"":""A128GCM"", + ""apu"":""QWxpY2U"", + ""apv"":""Qm9i"", + ""epk"": + { + ""kty"":""EC"", + ""crv"":""P-256"", + ""x"":""gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0"", + ""y"":""SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps"" + } + }"; + + public static string Alg = "ECDH-ES"; + + public static string Enc = "A128GCM"; + + public static string Apu = "QWxpY2U"; + + public static string Apv = "Qm9i"; + + public static int KeyDataLen = 128; + + public static byte[] PartyUInfo = new byte[] { 0, 0, 0, 5, 65, 108, 105, 99, 101 }; + + public static byte[] PartyVInfo = new byte[] { 0, 0, 0, 3, 66, 11, 98 }; + + public static byte[] OtherInfo = new byte[] { 0, 0, 0, 7, 65, 49, 50, 56, 71, 67, 77, 0, 0, 0, 5, 65, 108, 105, 99, 101, 0, 0, 0, 3, 66, 111, 98, 0, 0, 0, 128 }; + + public static byte[] SuppPubInfo = new byte[] { 0, 0, 0, 128 }; + + public static byte[] SuppPrivInfo = new byte[] { }; + + public static byte[] Z => new byte[] { 158, 86, 217, 29, 129, 113, 53, 211, 114, 131, 66, 131, 191, 132, 38, 156, 251, 49, 110, 163, 218, 128, 106, 72, 246, 218, 167, 121, 140, 254, 144, 196 }; + } + // https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.1.3 // A.1.3 Key wrap: RSAES-OAEP + JsonWebKey public static class RSAES_OAEP_KeyWrap diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricAdapterTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricAdapterTests.cs index 09b8167d98..d94764e6e9 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricAdapterTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricAdapterTests.cs @@ -48,7 +48,7 @@ public void AsymmetricAdapterUsageTests(AsymmetricAdapterTheoryData theoryData) try { -#if NET461 || NET472 || NETCOREAPP2_1 +#if NET461 || NET472 || NETCOREAPP2_1 || NET6_0 AsymmetricAdapter asymmetricdapter = new AsymmetricAdapter(theoryData.SecurityKey, theoryData.Algorithm, hashAlgorithm, SupportedAlgorithms.GetHashAlgorithmName(theoryData.Algorithm), true); #else AsymmetricAdapter asymmetricdapter = new AsymmetricAdapter(theoryData.SecurityKey, theoryData.Algorithm, hashAlgorithm, true); @@ -69,6 +69,7 @@ public void AsymmetricAdapterUsageTests(AsymmetricAdapterTheoryData theoryData) public static TheoryData AsymmetricAdapterUsageTestCases { +#pragma warning disable SYSLIB0028 // Type or member is obsolete get => new TheoryData { // X509 @@ -82,7 +83,7 @@ public static TheoryData AsymmetricAdapterUsageTest // RSA // RSACertificateExtensions.GetRSAPrivateKey - this results in - #if NET461 || NET472 || NETCOREAPP2_1 + #if NET461 || NET472 || NETCOREAPP2_1 || NET6_0 new AsymmetricAdapterTheoryData { Algorithm = SecurityAlgorithms.RsaSha256, @@ -102,7 +103,7 @@ public static TheoryData AsymmetricAdapterUsageTest }, // RSA.Create - #if NET472 || NETCOREAPP2_1 + #if NET472 || NETCOREAPP2_1 || NET6_0 new AsymmetricAdapterTheoryData { Algorithm = SecurityAlgorithms.RsaSha256, @@ -140,7 +141,7 @@ public static TheoryData AsymmetricAdapterUsageTest TestId = "KeyingMaterial_Ecdsa256Key" }, - #if NET472 || NETCOREAPP2_1 + #if NET472 || NETCOREAPP2_1 || NET6_0 new AsymmetricAdapterTheoryData { Algorithm = SecurityAlgorithms.EcdsaSha256, @@ -151,6 +152,7 @@ public static TheoryData AsymmetricAdapterUsageTest #endif }; +#pragma warning restore SYSLIB0028 // Type or member is obsolete } public class AsymmetricAdapterTheoryData : TheoryDataBase diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricSignatureTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricSignatureTests.cs index a93b7e6b53..ce5506cb07 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricSignatureTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricSignatureTests.cs @@ -32,6 +32,8 @@ using Xunit; #pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +#pragma warning disable SYSLIB0028 // Type or member is obsolete +#pragma warning disable SYSLIB0027 // Type or member is obsolete namespace Microsoft.IdentityModel.Tokens.Tests { @@ -514,4 +516,6 @@ public class AsymmetricSignatureProviderTheoryData : TheoryDataBase } } +#pragma warning restore SYSLIB0027 // Type or member is obsolete +#pragma warning restore SYSLIB0028 // Type or member is obsolete #pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/AuthenticatedEncryptionProviderTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/AuthenticatedEncryptionProviderTests.cs index 70058c7967..f26cbc55ec 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/AuthenticatedEncryptionProviderTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/AuthenticatedEncryptionProviderTests.cs @@ -89,7 +89,6 @@ public class AuthenticatedEncryptionProviderTests { #if NET_CORE [PlatformSpecific(TestPlatforms.Linux | TestPlatforms.OSX)] - [Fact] public void AesGcmEncryptionOnLinuxAndMac() { diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/CallContextTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/CallContextTests.cs new file mode 100644 index 0000000000..e0480a2167 --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Tests/CallContextTests.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.CodeDom; +using Microsoft.IdentityModel.Logging; +using Microsoft.IdentityModel.TestUtils; +using Xunit; + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant + +namespace Microsoft.IdentityModel.Tokens.Tests +{ + public class CallContextTests + { + [Theory, MemberData(nameof(CallContextTestTheoryData))] + public void LoggerInstanceTests(CallContextTheoryData theoryData) + { + var context = new CallContext(theoryData.ActivityId) { DebugId = theoryData.TestId }; + + Assert.IsAssignableFrom(context); + Assert.Equal(theoryData.TestId, context.DebugId); + Assert.Equal(theoryData.ActivityId, context.ActivityId); + Assert.False(context.CaptureLogs); + Assert.Empty(context.Logs); + Assert.Null(context.PropertyBag); + } + + public static TheoryData CallContextTestTheoryData + { + get + { + var theoryData = new TheoryData(); + + theoryData.Add(new CallContextTheoryData + { + TestId = "abdc", + ActivityId = new Guid() + }); + + return theoryData; + } + } + } + + public class CallContextTheoryData : TheoryDataBase + { + public Guid ActivityId; + } +} + +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/CryptoProviderCacheTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/CryptoProviderCacheTests.cs index 6ce6e1c049..30342acbee 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/CryptoProviderCacheTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/CryptoProviderCacheTests.cs @@ -291,7 +291,7 @@ public static TheoryData TryAddTheoryData SignatureProvider = new SymmetricSignatureProvider(KeyingMaterial.DefaultSymmetricSecurityKey_384, ALG.HmacSha384, true), TestId = nameof(KeyingMaterial.DefaultSymmetricSecurityKey_256) }, -#if NET472 || NET_CORE +#if NET472 || NET_CORE // ecdsa signature provider should be added to the cache on NET472 and NET_CORE. new CryptoProviderCacheTheoryData { diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/CustomCryptoProviders.cs b/test/Microsoft.IdentityModel.Tokens.Tests/CustomCryptoProviders.cs index 60abf9cda8..59023a5301 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/CustomCryptoProviders.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/CustomCryptoProviders.cs @@ -95,7 +95,7 @@ public bool IsHashAlgorithm(string algorithm) foreach (var alg in AdditionalHashAlgorithms) - if (alg.Equals(algorithm, StringComparison.Ordinal)) + if (alg.Equals(algorithm)) return true; return false; diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/EcdhEsTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/EcdhEsTests.cs new file mode 100644 index 0000000000..0f6bc99c0a --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Tests/EcdhEsTests.cs @@ -0,0 +1,197 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//------------------------------------------------------------------------------ + +using System; +using Microsoft.IdentityModel.TestUtils; +using Xunit; + +using KEY = Microsoft.IdentityModel.TestUtils.KeyingMaterial; + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +#if NET472 || NET6_0 +namespace Microsoft.IdentityModel.Tokens.Tests +{ + public class EcdhEsTests + { + [Theory, MemberData(nameof(CreateEcdhEsTestCases))] + public void EcdhEsKeyExchangeProviderTests(EcdhEsTheoryData theoryData) + { + var context = new CompareContext(); + // arrange + string alg = theoryData.Algorithm; + string enc = theoryData.Encryption; + string apuProducer = theoryData.ApuProducer; + string apvProducer = theoryData.ApvProducer; + string apuConsumer = theoryData.ApuConsumer; + string apvConsumer = theoryData.ApvConsumer; + + var aliceKeyExchangeProvider = new EcdhKeyExchangeProvider(theoryData.PrivateKeySender, theoryData.PublicKeyReceiver, alg, enc); + var bobKeyExchangeProvider = new EcdhKeyExchangeProvider(theoryData.PrivateKeyReceiver, theoryData.PublicKeySender, alg, enc); + + // act + SecurityKey aliceCek = aliceKeyExchangeProvider.GenerateKdf(apuProducer, apvProducer); + SecurityKey bobCek = bobKeyExchangeProvider.GenerateKdf(apuConsumer, apvConsumer); + + // assert + // compare KDFs are the same + if (theoryData.MatchingKdfs && !Utility.AreEqual(((SymmetricSecurityKey)aliceCek).Key, ((SymmetricSecurityKey)bobCek).Key)) + context.AddDiff($"theoryData.MatchingKdfs && !Utility.AreEqual(aliceCek, bobCek)"); + if (!theoryData.MatchingKdfs && Utility.AreEqual(((SymmetricSecurityKey)aliceCek).Key, ((SymmetricSecurityKey)bobCek).Key)) + context.AddDiff($"!theoryData.MatchingKdfs && Utility.AreEqual(aliceCek, bobCek)"); + + TestUtilities.AssertFailIfErrors(context); + } + + + [Theory, MemberData(nameof(CreateEcdhEsTestCases))] + public void CreateEcdhEsTests(EcdhEsTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.CreateEcdhEsTests", theoryData); + try + { + theoryData.ExpectedException.ProcessNoException(context); + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData CreateEcdhEsTestCases + { + get + { + TheoryData theoryData = new TheoryData(); + theoryData.Add(KeyExchangeEcdhEsA256kwTestPass()); + theoryData.Add(KeyExchangeEcdhEsA256kwTestPassNullApuApv()); + theoryData.Add(KeyExchangeEcdhEsA256kwTestFailDifferentApu()); + theoryData.Add(KeyExchangeEcdhEsA256kwTestFailDifferentApv()); + theoryData.Add(KeyExchangeEcdhEsA256kwTestFailDifferentApuApv()); + return theoryData; + } + } + + private static EcdhEsTheoryData KeyExchangeEcdhEsA256kwTestPass() => new EcdhEsTheoryData("KeyExchangeEcdhEsA256kwTestPass") + { + First = true, + Algorithm = SecurityAlgorithms.EcdhEsA256kw, + Encryption = SecurityAlgorithms.Aes128CbcHmacSha256, + ApuProducer = KEY.ApuExample1, + ApvProducer = KEY.ApvExample1, + ApuConsumer = KEY.ApuExample1, + ApvConsumer = KEY.ApvExample1, + PrivateKeySender = new ECDsaSecurityKey(KEY.JsonWebKeyP256, true), + PublicKeyReceiver = KEY.JsonWebKeyP256_Public, + PublicKeySender = KEY.JsonWebKeyP256_Public, + PrivateKeyReceiver = new ECDsaSecurityKey(KEY.JsonWebKeyP256, true), + MatchingKdfs = true + }; + + private static EcdhEsTheoryData KeyExchangeEcdhEsA256kwTestPassNullApuApv() => new EcdhEsTheoryData("KeyExchangeEcdhEsA256kwTestPassNullApuApv") + { + Algorithm = SecurityAlgorithms.EcdhEsA256kw, + Encryption = SecurityAlgorithms.Aes128CbcHmacSha256, + ApuProducer = null, + ApvProducer = null, + ApuConsumer = null, + ApvConsumer = null, + PrivateKeySender = new ECDsaSecurityKey(KEY.JsonWebKeyP256, true), + PublicKeyReceiver = KEY.JsonWebKeyP256_Public, + PublicKeySender = KEY.JsonWebKeyP256_Public, + PrivateKeyReceiver = new ECDsaSecurityKey(KEY.JsonWebKeyP256, true), + MatchingKdfs = true + }; + + private static EcdhEsTheoryData KeyExchangeEcdhEsA256kwTestFailDifferentApu() => new EcdhEsTheoryData("KeyExchangeEcdhEsA256kwTestFailDifferentApu") + { + Algorithm = SecurityAlgorithms.EcdhEsA256kw, + Encryption = SecurityAlgorithms.Aes128CbcHmacSha256, + ApuProducer = KEY.ApuExample1, + ApvProducer = KEY.ApvExample1, + ApuConsumer = KEY.ApuExample2, + ApvConsumer = KEY.ApvExample1, + PrivateKeySender = new ECDsaSecurityKey(KEY.JsonWebKeyP256, true), + PublicKeyReceiver = KEY.JsonWebKeyP256_Public, + PublicKeySender = KEY.JsonWebKeyP256_Public, + PrivateKeyReceiver = new ECDsaSecurityKey(KEY.JsonWebKeyP256, true), + MatchingKdfs = false + }; + + private static EcdhEsTheoryData KeyExchangeEcdhEsA256kwTestFailDifferentApv() => new EcdhEsTheoryData("KeyExchangeEcdhEsA256kwTestFailDifferentApv") + { + Algorithm = SecurityAlgorithms.EcdhEsA256kw, + Encryption = SecurityAlgorithms.Aes128CbcHmacSha256, + ApuProducer = KEY.ApuExample1, + ApvProducer = KEY.ApvExample1, + ApuConsumer = KEY.ApuExample1, + ApvConsumer = KEY.ApvExample2, + PrivateKeySender = new ECDsaSecurityKey(KEY.JsonWebKeyP256, true), + PublicKeyReceiver = KEY.JsonWebKeyP256_Public, + PublicKeySender = KEY.JsonWebKeyP256_Public, + PrivateKeyReceiver = new ECDsaSecurityKey(KEY.JsonWebKeyP256, true), + MatchingKdfs = false + }; + + private static EcdhEsTheoryData KeyExchangeEcdhEsA256kwTestFailDifferentApuApv() => new EcdhEsTheoryData("KeyExchangeEcdhEsA256kwTestFailDifferentApuApv") + { + Algorithm = SecurityAlgorithms.EcdhEsA256kw, + Encryption = SecurityAlgorithms.Aes128CbcHmacSha256, + ApuProducer = KEY.ApuExample1, + ApvProducer = KEY.ApvExample1, + ApuConsumer = KEY.ApuExample2, + ApvConsumer = KEY.ApvExample2, + PrivateKeySender = new ECDsaSecurityKey(KEY.JsonWebKeyP256, true), + PublicKeyReceiver = KEY.JsonWebKeyP256_Public, + PublicKeySender = KEY.JsonWebKeyP256_Public, + PrivateKeyReceiver = new ECDsaSecurityKey(KEY.JsonWebKeyP256, true), + MatchingKdfs = false + }; + + public class EcdhEsTheoryData : TheoryDataBase + { + public EcdhEsTheoryData(string testId) + { + TestId = testId; + } + public ECDsaSecurityKey PrivateKeySender { get; set; } + public ECDsaSecurityKey PrivateKeyReceiver { get; set; } + public JsonWebKey PublicKeyReceiver { get; set; } + public JsonWebKey PublicKeySender { get; set; } + public string Algorithm { get; set; } + public string Encryption { get; set; } + public string ApuProducer { get; set; } + public string ApvProducer { get; set; } + public string ApuConsumer { get; set; } + public string ApvConsumer { get; set; } + public bool MatchingKdfs { get; set; } + } + } +} +#endif +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/EventBasedLRUCacheTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/EventBasedLRUCacheTests.cs index fb2e72c90f..4fd3dfdb6b 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/EventBasedLRUCacheTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/EventBasedLRUCacheTests.cs @@ -87,6 +87,40 @@ public void DoNotRemoveExpiredValues() TestUtilities.AssertFailIfErrors(context); } + /// + /// Verifies that the Compact() and CompactLRU() are called when the number of cached items exceeds the specified percentage. + /// + [Fact] + public void CompactCache() + { + int capacity = 10; + int expiredInSeconds = 1; + int waitInMiliSeconds = 2 * 1000 * expiredInSeconds; + + TestUtilities.WriteHeader($"{this}.CompactCache"); + var context = new CompareContext($"{this}.CompactCache"); + var cache = new EventBasedLRUCache(capacity, removeExpiredValues: true, maintainLRU: false); + + // add 3 times the capacity to start the compaction process + AddItemsToCache(cache, 3 * capacity, expiredInSeconds); + + // allows the compaction event to be processed + cache.WaitForProcessing(); + + // keep checking the cache size, up to 1 min, until it is reduced + for (int i = 0; i < 10; i++) + { + // wait 0.1 sec if the cache size > the capacity + if (cache.MapCount > capacity) + Thread.Sleep(100); // sleep 0.1 sec + } + + if (cache.MapCount > capacity) + context.AddDiff($"The cache size should be less than {capacity}."); + + TestUtilities.AssertFailIfErrors(context); + } + /// /// Verifies that the RemoveExpiredValues() method (non LRU) is working as expected. /// diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/JweUsingEchdTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/JweUsingEchdTests.cs new file mode 100644 index 0000000000..9386e4d6f3 --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Tests/JweUsingEchdTests.cs @@ -0,0 +1,334 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//------------------------------------------------------------------------------ + +#if NET472 || NET6_0 + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using Microsoft.IdentityModel.Json.Linq; +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.TestUtils; +using Microsoft.IdentityModel.Tokens; +using Xunit; + + +using KEY = Microsoft.IdentityModel.TestUtils.KeyingMaterial; + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant + +namespace Microsoft.IdentityModel.Tokens.Tests +{ + public class JweUsingEcdhEsTests + { + [Theory, MemberData(nameof(CreateEcdhEsTestcases))] + public void CreateJweEcdhEsTests(CreateEcdhEsTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.CreateJweEcdhEsTests", theoryData); + context.AddClaimTypeToIgnoreWhenComparing("exp"); + context.AddClaimTypeToIgnoreWhenComparing("iat"); + context.AddClaimTypeToIgnoreWhenComparing("nbf"); + + try + { + JsonWebTokenHandler jsonWebTokenHandler = new JsonWebTokenHandler(); + JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); + jwtSecurityTokenHandler.MapInboundClaims = false; + jwtSecurityTokenHandler.OutboundClaimTypeMap.Clear(); + SecurityTokenDescriptor securityTokenDescriptor = new SecurityTokenDescriptor + { + Subject = Default.ClaimsIdentity, + SigningCredentials = Default.AsymmetricSigningCredentials, + EncryptingCredentials = theoryData.EncryptingCredentials, + AdditionalHeaderClaims = theoryData.AdditionalHeaderParams, + Audience = Default.Audience, + Issuer = Default.Issuer, + }; + + string jsonJwe = jsonWebTokenHandler.CreateToken(securityTokenDescriptor); + string jwtJwe = jwtSecurityTokenHandler.CreateEncodedJwt(securityTokenDescriptor); + + TokenValidationResult tokenValidationResult1 = jsonWebTokenHandler.ValidateToken(jsonJwe, theoryData.TokenValidationParameters); + TokenValidationResult tokenValidationResult2 = jsonWebTokenHandler.ValidateToken(jwtJwe, theoryData.TokenValidationParameters); + TokenValidationResult tokenValidationResult3 = jwtSecurityTokenHandler.ValidateTokenAsync(jsonJwe, theoryData.TokenValidationParameters).GetAwaiter().GetResult(); + TokenValidationResult tokenValidationResult4 = jwtSecurityTokenHandler.ValidateTokenAsync(jwtJwe, theoryData.TokenValidationParameters).GetAwaiter().GetResult(); + + if (tokenValidationResult1.IsValid != theoryData.ExpectedIsValid) + context.AddDiff($"tokenValidationResult1.IsValid != theoryData.ExpectedIsValid"); + + if (tokenValidationResult2.IsValid != theoryData.ExpectedIsValid) + context.AddDiff($"tokenValidationResult2.IsValid != theoryData.ExpectedIsValid"); + + if (tokenValidationResult3.IsValid != theoryData.ExpectedIsValid) + context.AddDiff($"tokenValidationResult3.IsValid != theoryData.ExpectedIsValid"); + + if (tokenValidationResult4.IsValid != theoryData.ExpectedIsValid) + context.AddDiff($"tokenValidationResult4.IsValid != theoryData.ExpectedIsValid"); + + IdentityComparer.AreEqual(tokenValidationResult1.ClaimsIdentity, tokenValidationResult2.ClaimsIdentity, context); + IdentityComparer.AreEqual(tokenValidationResult1.ClaimsIdentity, tokenValidationResult3.ClaimsIdentity, context); + IdentityComparer.AreEqual(tokenValidationResult1.ClaimsIdentity, tokenValidationResult4.ClaimsIdentity, context); + IdentityComparer.AreEqual(tokenValidationResult1.Claims, tokenValidationResult2.Claims, context); + IdentityComparer.AreEqual(tokenValidationResult1.Claims, tokenValidationResult3.Claims, context); + IdentityComparer.AreEqual(tokenValidationResult1.Claims, tokenValidationResult4.Claims, context); + + theoryData.ExpectedException.ProcessNoException(context); + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData CreateEcdhEsTestcases + { + get + { + TheoryData theoryData = new TheoryData(); + + theoryData.Add(EcdhEsCurveP256AEnc256KW()); + theoryData.Add(EcdhEsCurveP256AEnc256KWNullApuApv()); + theoryData.Add(EcdhEsCurveP384EncA256KW()); + theoryData.Add(EcdhEsCurveP512EncA256KW()); + theoryData.Add(EcdhEsCurveP256EncA192KW()); + theoryData.Add(EcdhEsCurveP256EncA128KW()); + + return theoryData; + } + } + + private static CreateEcdhEsTheoryData EcdhEsCurveP256AEnc256KW() + { + CreateEcdhEsTheoryData testData = new CreateEcdhEsTheoryData("EcdhEsCurveP256AEnc256KW") + { + EncryptingCredentials = new EncryptingCredentials( + new ECDsaSecurityKey(KeyingMaterial.JsonWebKeyP256, true), + SecurityAlgorithms.EcdhEsA256kw, + SecurityAlgorithms.Aes128CbcHmacSha256) + { + KeyExchangePublicKey = KeyingMaterial.JsonWebKeyP256_Public + }, + PublicKeyReceiver = KeyingMaterial.JsonWebKeyP256_Public, + PublicKeySender = KeyingMaterial.JsonWebKeyP256_Public, + PrivateKeyReceiver = KeyingMaterial.JsonWebKeyP256, + TokenValidationParameters = new TokenValidationParameters() + { + TokenDecryptionKey = new ECDsaSecurityKey(KeyingMaterial.JsonWebKeyP256, true), + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer, + IssuerSigningKey = Default.AsymmetricSigningKey + }, + ApuSender = Guid.NewGuid().ToString(), + ApvSender = Guid.NewGuid().ToString() + }; + + return SetAdditionalHeaderParameters(testData); + } + + private static CreateEcdhEsTheoryData EcdhEsCurveP256AEnc256KWNullApuApv() + { + CreateEcdhEsTheoryData testData = new CreateEcdhEsTheoryData("EcdhEsCurveP256AEnc256KW") + { + EncryptingCredentials = new EncryptingCredentials( + new ECDsaSecurityKey(KeyingMaterial.JsonWebKeyP256, true), + SecurityAlgorithms.EcdhEsA256kw, + SecurityAlgorithms.Aes128CbcHmacSha256) + { + KeyExchangePublicKey = KeyingMaterial.JsonWebKeyP256_Public + }, + PublicKeyReceiver = KeyingMaterial.JsonWebKeyP256_Public, + PublicKeySender = KeyingMaterial.JsonWebKeyP256_Public, + PrivateKeyReceiver = KeyingMaterial.JsonWebKeyP256, + TokenValidationParameters = new TokenValidationParameters() + { + TokenDecryptionKey = new ECDsaSecurityKey(KeyingMaterial.JsonWebKeyP256, true), + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer, + IssuerSigningKey = Default.AsymmetricSigningKey + }, + ApuSender = null, + ApvSender = null + }; + + return SetAdditionalHeaderParameters(testData); + } + + private static CreateEcdhEsTheoryData EcdhEsCurveP384EncA256KW() + { + CreateEcdhEsTheoryData testData = new CreateEcdhEsTheoryData("EcdhEsCurveP384EncA256KW") + { + EncryptingCredentials = new EncryptingCredentials( + new ECDsaSecurityKey(KeyingMaterial.JsonWebKeyP384, true), + SecurityAlgorithms.EcdhEsA256kw, + SecurityAlgorithms.Aes128CbcHmacSha256) + { + KeyExchangePublicKey = KeyingMaterial.JsonWebKeyP384_Public + }, + PublicKeyReceiver = KeyingMaterial.JsonWebKeyP384_Public, + PublicKeySender = KeyingMaterial.JsonWebKeyP384_Public, + PrivateKeyReceiver = KeyingMaterial.JsonWebKeyP384, + TokenValidationParameters = new TokenValidationParameters() + { + TokenDecryptionKey = new ECDsaSecurityKey(KeyingMaterial.JsonWebKeyP384, true), + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer, + IssuerSigningKey = Default.AsymmetricSigningKey + }, + ApuSender = Guid.NewGuid().ToString(), + ApvSender = Guid.NewGuid().ToString() + }; + + return SetAdditionalHeaderParameters(testData); + } + + private static CreateEcdhEsTheoryData EcdhEsCurveP512EncA256KW() + { + // use of 521 is actually 512 + CreateEcdhEsTheoryData testData = new CreateEcdhEsTheoryData("EcdhEsCurveP512EncA256KW") + { + EncryptingCredentials = new EncryptingCredentials( + new ECDsaSecurityKey(KeyingMaterial.JsonWebKeyP521, true), + SecurityAlgorithms.EcdhEsA256kw, + SecurityAlgorithms.Aes128CbcHmacSha256) + { + KeyExchangePublicKey = KeyingMaterial.JsonWebKeyP521_Public + }, + PublicKeyReceiver = KeyingMaterial.JsonWebKeyP521_Public, + PublicKeySender = KeyingMaterial.JsonWebKeyP521_Public, + PrivateKeyReceiver = KeyingMaterial.JsonWebKeyP521, + TokenValidationParameters = new TokenValidationParameters() + { + TokenDecryptionKey = new ECDsaSecurityKey(KeyingMaterial.JsonWebKeyP521, true), + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer, + IssuerSigningKey = Default.AsymmetricSigningKey + }, + ApuSender = Guid.NewGuid().ToString(), + ApvSender = Guid.NewGuid().ToString() + }; + + return SetAdditionalHeaderParameters(testData); + } + + private static CreateEcdhEsTheoryData EcdhEsCurveP256EncA192KW() + { + CreateEcdhEsTheoryData testData = new CreateEcdhEsTheoryData("EcdhEsCurveP256EncA192KW") + { + EncryptingCredentials = new EncryptingCredentials( + new ECDsaSecurityKey(KeyingMaterial.JsonWebKeyP256, true), + SecurityAlgorithms.EcdhEsA192kw, + SecurityAlgorithms.Aes192CbcHmacSha384) + { + KeyExchangePublicKey = KeyingMaterial.JsonWebKeyP256_Public + }, + PublicKeyReceiver = KeyingMaterial.JsonWebKeyP256_Public, + PublicKeySender = KeyingMaterial.JsonWebKeyP256_Public, + PrivateKeyReceiver = KeyingMaterial.JsonWebKeyP256, + TokenValidationParameters = new TokenValidationParameters() + { + TokenDecryptionKey = new ECDsaSecurityKey(KeyingMaterial.JsonWebKeyP256, true), + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer, + IssuerSigningKey = Default.AsymmetricSigningKey + }, + ApuSender = Guid.NewGuid().ToString(), + ApvSender = Guid.NewGuid().ToString() + }; + + return SetAdditionalHeaderParameters(testData); + } + + private static CreateEcdhEsTheoryData EcdhEsCurveP256EncA128KW() + { + CreateEcdhEsTheoryData testData = new CreateEcdhEsTheoryData("EcdhEsCurveP256EncA128KW") + { + EncryptingCredentials = new EncryptingCredentials( + new ECDsaSecurityKey(KeyingMaterial.JsonWebKeyP256, true), + SecurityAlgorithms.EcdhEsA128kw, + SecurityAlgorithms.Aes128CbcHmacSha256) + { + KeyExchangePublicKey = KeyingMaterial.JsonWebKeyP256_Public + }, + PublicKeyReceiver = KeyingMaterial.JsonWebKeyP256_Public, + PublicKeySender = KeyingMaterial.JsonWebKeyP256_Public, + PrivateKeyReceiver = KeyingMaterial.JsonWebKeyP256, + TokenValidationParameters = new TokenValidationParameters() + { + TokenDecryptionKey = new ECDsaSecurityKey(KeyingMaterial.JsonWebKeyP256, true), + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer, + IssuerSigningKey = Default.AsymmetricSigningKey + }, + ApuSender = Guid.NewGuid().ToString(), + ApvSender = Guid.NewGuid().ToString() + }; + + return SetAdditionalHeaderParameters(testData); + } + + private static CreateEcdhEsTheoryData SetAdditionalHeaderParameters(CreateEcdhEsTheoryData testData) + { + var epkJObject = new JObject(); + epkJObject.Add(JsonWebKeyParameterNames.Kty, testData.PublicKeySender.Kty); + epkJObject.Add(JsonWebKeyParameterNames.Crv, testData.PublicKeySender.Crv); + epkJObject.Add(JsonWebKeyParameterNames.X, testData.PublicKeySender.X); + epkJObject.Add(JsonWebKeyParameterNames.Y, testData.PublicKeySender.Y); + testData.AdditionalHeaderParams = new Dictionary(); + testData.AdditionalHeaderParams.Add(JsonWebTokens.JwtHeaderParameterNames.Apu, testData.ApuSender); + testData.AdditionalHeaderParams.Add(JsonWebTokens.JwtHeaderParameterNames.Apv, testData.ApvSender); + testData.AdditionalHeaderParams.Add(JsonWebTokens.JwtHeaderParameterNames.Epk, epkJObject); + + return testData; + } + } + + public class CreateEcdhEsTheoryData : TheoryDataBase + { + public CreateEcdhEsTheoryData(string testId) + { + TestId = testId; + } + + public string ApuReceiver { get; set; } + public string ApvReceiver { get; set; } + public string ApuSender { get; set; } + public string ApvSender { get; set; } + public EncryptingCredentials EncryptingCredentials { get; set; } + public JsonWebKey PrivateKeyReceiver { get; set; } + public JsonWebKey PublicKeyReceiver { get; set; } + public JsonWebKey PublicKeySender { get; set; } + public TokenValidationParameters TokenValidationParameters { get; set; } + public bool ExpectedIsValid { get; set; } = true; + public IDictionary AdditionalHeaderParams { get; set; } + } +} + +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant +#endif // !NET45 diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/ReferenceTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/ReferenceTests.cs index 6b009a4367..ff8943c5d5 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/ReferenceTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/ReferenceTests.cs @@ -26,7 +26,12 @@ //------------------------------------------------------------------------------ using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using Microsoft.IdentityModel.JsonWebTokens; using Microsoft.IdentityModel.TestUtils; +using Microsoft.IdentityModel.Tokens; using Xunit; #pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant @@ -39,6 +44,39 @@ namespace Microsoft.IdentityModel.Tokens.Tests /// public class ReferenceTests { + +#if NET472 || NET6_0 + [Fact] + public void ECDH_ESReferenceTest() + { + var context = new CompareContext(); + // arrange + string alg = ECDH_ES.Alg; + string enc = ECDH_ES.Enc; + string apu = ECDH_ES.Apu; + string apv = ECDH_ES.Apv; + + var aliceEcdsaSecurityKey = new ECDsaSecurityKey(ECDH_ES.AliceEphereralPrivateKey, true); + var aliceKeyExchangeProvider = new EcdhKeyExchangeProvider(aliceEcdsaSecurityKey, ECDH_ES.BobEphereralPublicKey, alg, enc); + + var bobEcdsaSecurityKey = new ECDsaSecurityKey(ECDH_ES.BobEphereralPrivateKey, true); + var bobKeyExchangeProvider = new EcdhKeyExchangeProvider(bobEcdsaSecurityKey, ECDH_ES.AliceEphereralPublicKey, alg, enc); + + // act + SecurityKey aliceCek = aliceKeyExchangeProvider.GenerateKdf(apu, apv); + SecurityKey bobCek = bobKeyExchangeProvider.GenerateKdf(apu, apv); + + // assert + // compare KDFs are the same and they're matching with expected + if (!Utility.AreEqual(((SymmetricSecurityKey)aliceCek).Key, ((SymmetricSecurityKey)bobCek).Key)) + context.AddDiff($"!Utility.AreEqual(aliceCek, bobCek)"); + if (!Utility.AreEqual(((SymmetricSecurityKey)aliceCek).Key, ECDH_ES.DerivedKeyBytes)) + context.AddDiff($"!Utility.AreEqual(aliceCek, ECDH_ES.DerivedKeyBytes)"); + + TestUtilities.AssertFailIfErrors(context); + } +#endif + #if NET_CORE [PlatformSpecific(TestPlatforms.Windows)] #endif diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/SecurityTokenExceptionTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/SecurityTokenExceptionTests.cs index aaccb47d14..3f49ef3d90 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/SecurityTokenExceptionTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/SecurityTokenExceptionTests.cs @@ -52,12 +52,16 @@ public void SecurityTokenInvalidIssuerExceptionSerializesValues(SecurityTokenExc var memoryStream = new MemoryStream(); BinaryFormatter formatter = new BinaryFormatter(); +#pragma warning disable SYSLIB0011 // Type or member is obsolete formatter.Serialize(memoryStream, exception); +#pragma warning restore SYSLIB0011 // Type or member is obsolete memoryStream.Seek(0, SeekOrigin.Begin); formatter.Binder = new ExceptionSerializationBinder(); +#pragma warning disable SYSLIB0011 // Type or member is obsolete var serializedException = formatter.Deserialize(memoryStream); +#pragma warning restore SYSLIB0011 // Type or member is obsolete theoryData.ExpectedException.ProcessNoException(context); diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/SignatureProviderTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/SignatureProviderTests.cs index 051a2c2ce3..fccbb5038b 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/SignatureProviderTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/SignatureProviderTests.cs @@ -413,11 +413,11 @@ public void AsymmetricSignatureProvider_SupportedAlgorithms() try { SecurityKey key = null; - if (algorithm.Equals(ALG.EcdsaSha256, StringComparison.Ordinal)) + if (algorithm.Equals(ALG.EcdsaSha256)) { key = KEY.Ecdsa256Key; } - else if (algorithm.Equals(ALG.EcdsaSha384, StringComparison.Ordinal)) + else if (algorithm.Equals(ALG.EcdsaSha384)) { key = KEY.Ecdsa384Key; } diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtPayloadTest.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtPayloadTest.cs index f4c61791b2..eab3b44e9d 100644 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtPayloadTest.cs +++ b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtPayloadTest.cs @@ -194,8 +194,8 @@ public void TestDateTimeClaim() jwtPayload.Add("dateTime", dateTime); var dateTimeClaim = jwtPayload.Claims.First(); - Assert.True(string.Equals(dateTimeClaim.ValueType, ClaimValueTypes.DateTime, StringComparison.Ordinal), "dateTimeClaim.Type != ClaimValueTypes.DateTime"); - Assert.True(string.Equals(dateTimeClaim.Value, dateTime.ToUniversalTime().ToString("o", CultureInfo.InvariantCulture), StringComparison.Ordinal), "dateTimeClaim.Value != dateTime.ToUniversalTime('o', CultureInfo.InvariantCulture).ToString()"); + Assert.True(string.Equals(dateTimeClaim.ValueType, ClaimValueTypes.DateTime), "dateTimeClaim.Type != ClaimValueTypes.DateTime"); + Assert.True(string.Equals(dateTimeClaim.Value, dateTime.ToUniversalTime().ToString("o", CultureInfo.InvariantCulture)), "dateTimeClaim.Value != dateTime.ToUniversalTime('o', CultureInfo.InvariantCulture).ToString()"); } [Fact] diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtReferenceTests.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtReferenceTests.cs index 835f7e59d6..b83dbcb968 100644 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtReferenceTests.cs +++ b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtReferenceTests.cs @@ -40,8 +40,8 @@ public class JwtReferenceTests public void Base64UrlEncoding(string testId, string dataToEncode, string encodedData) { TestUtilities.WriteHeader($"Base64UrlEncoding - {testId}", true); - Assert.True(dataToEncode.Equals(Base64UrlEncoder.Decode(encodedData), StringComparison.Ordinal), "dataToEncode.Equals(Base64UrlEncoder.Decode(encodedData), StringComparison.Ordinal)"); - Assert.True(encodedData.Equals(Base64UrlEncoder.Encode(dataToEncode), StringComparison.Ordinal), "encodedData.Equals(Base64UrlEncoder.Encode(dataToEncode), StringComparison.Ordinal)"); + Assert.True(dataToEncode.Equals(Base64UrlEncoder.Decode(encodedData)), "dataToEncode.Equals(Base64UrlEncoder.Decode(encodedData))"); + Assert.True(encodedData.Equals(Base64UrlEncoder.Encode(dataToEncode)), "encodedData.Equals(Base64UrlEncoder.Encode(dataToEncode))"); } public static TheoryData Base64UrlEncodingTheoryData @@ -63,7 +63,7 @@ public static TheoryData Base64UrlEncodingTheoryData public void JwtEncoding(string testId, JwtHeader header, string encodedData) { TestUtilities.WriteHeader($"JwtEncoding - {testId}", true); - Assert.True(encodedData.Equals(header.Base64UrlEncode(), StringComparison.Ordinal), "encodedData.Equals(header.Base64UrlEncode(), StringComparison.Ordinal)"); + Assert.True(encodedData.Equals(header.Base64UrlEncode()), "encodedData.Equals(header.Base64UrlEncode())"); } public static TheoryData JwtEncodingTheoryData @@ -90,7 +90,7 @@ public void JwtSigning(JwtSigningTestParams testParams) // Signatures aren't necessarily deterministic across different algorithms if (testParams.DeterministicSignatures) - Assert.True(testParams.EncodedSignature.Equals(encodedSignature, StringComparison.Ordinal), "encodedSignature != testParams.EncodedSignature"); + Assert.True(testParams.EncodedSignature.Equals(encodedSignature), "encodedSignature != testParams.EncodedSignature"); Assert.True(providerForVerifying.Verify(Encoding.UTF8.GetBytes(testParams.EncodedData), Base64UrlEncoder.DecodeBytes(testParams.EncodedSignature)), "Verify Failed"); } diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.cs index e07bf560e6..4fea653118 100644 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.cs +++ b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.cs @@ -44,6 +44,209 @@ namespace System.IdentityModel.Tokens.Jwt.Tests { public class JwtSecurityTokenHandlerTests { + + [Theory, MemberData(nameof(CreateJWEWithPayloadStringTheoryData))] + public void CreateJWEWithAdditionalHeaderClaims(CreateTokenTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.CreateJWEWithAdditionalHeaderClaims", theoryData); + var handler = new JwtSecurityTokenHandler(); + + try + { + var jwtToken = handler.CreateEncodedJwt(theoryData.TokenDescriptor); + var jsonToken = handler.ReadJwtToken(jwtToken); + + if (theoryData.TokenDescriptor.AdditionalHeaderClaims.TryGetValue(JwtHeaderParameterNames.Cty, out object ctyValue)) + { + if (!jsonToken.Header.TryGetValue(JwtHeaderParameterNames.Cty, out object headerCtyValue)) + { + context.AddDiff($"'Cty' claim does not exist in the outer header but present in theoryData.AdditionalHeaderClaims."); + } + else + IdentityComparer.AreEqual(ctyValue.ToString(), headerCtyValue.ToString(), context); + } + else if (theoryData.TokenDescriptor.EncryptingCredentials.SetDefaultCtyClaim) + { + if (!jsonToken.Header.TryGetValue(JwtHeaderParameterNames.Cty, out object headerCtyValue)) + { + context.AddDiff($"'Cty' claim does not exist in the outer header. It is expected to have the default value '{JwtConstants.HeaderType}'."); + } + else + IdentityComparer.AreEqual(JwtConstants.HeaderType, headerCtyValue.ToString(), context); + } + else + { + if (jsonToken.Header.TryGetValue(JwtHeaderParameterNames.Cty, out object headerCtyValue)) + { + context.AddDiff($"'Cty' claim does exist in the outer header. It is not expected to exist since SetDefaultCtyClaim is '{theoryData.TokenDescriptor.EncryptingCredentials.SetDefaultCtyClaim}'."); + } + } + + + if (theoryData.TokenDescriptor.AdditionalInnerHeaderClaims != null) + { + theoryData.ValidationParameters.ValidateLifetime = false; + var result = handler.ValidateToken(jwtToken, theoryData.ValidationParameters, out SecurityToken validatedToken); + var token = validatedToken as JwtSecurityToken; + if (theoryData.TokenDescriptor.AdditionalInnerHeaderClaims.TryGetValue(JwtHeaderParameterNames.Cty, out object innerCtyValue)) + { + if (!token.InnerToken.Header.TryGetValue(JwtHeaderParameterNames.Cty, out object headerCtyValue)) + { + context.AddDiff($"'Cty' claim does not exist in the inner header but present in theoryData.AdditionalHeaderClaims."); + } + else + IdentityComparer.AreEqual(innerCtyValue.ToString(), headerCtyValue.ToString(), context); + } + } + } + catch(Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData CreateJWEWithPayloadStringTheoryData + { + get + { + var NoCtyEncryptionCreds = Default.SymmetricEncryptingCredentials; + NoCtyEncryptionCreds.SetDefaultCtyClaim = false; + return new TheoryData + { + new CreateTokenTheoryData + { + First = true, + TestId = "Unsigned", + TokenDescriptor = new SecurityTokenDescriptor + { + EncryptingCredentials = NoCtyEncryptionCreds, + AdditionalHeaderClaims = new Dictionary{ {"int", "123" } } + }, + }, + new CreateTokenTheoryData + { + TestId = "Unsigned_CtyInAdditionalClaims", + TokenDescriptor = new SecurityTokenDescriptor + { + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{{JwtHeaderParameterNames.Cty, "str"}} + }, + }, + new CreateTokenTheoryData + { + TestId = "CtyInBothAdditionalHeaderClaims", + TokenDescriptor = new SecurityTokenDescriptor + { + SigningCredentials = Default.SymmetricSigningCredentials, + CompressionAlgorithm = CompressionAlgorithms.Deflate, + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{{JwtHeaderParameterNames.Cty, "str_outer"}}, + AdditionalInnerHeaderClaims = new Dictionary{{JwtHeaderParameterNames.Cty, "str_inner"}}, + Audience = Default.Audience, + Issuer = Default.Issuer + }, + ValidationParameters = new TokenValidationParameters + { + IssuerSigningKey = Default.SymmetricSigningCredentials.Key, + TokenDecryptionKey = Default.SymmetricEncryptingCredentials.Key, + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer + } + }, + new CreateTokenTheoryData + { + TestId = "Outer_CustomCty_Inner_DefaultCty", + TokenDescriptor = new SecurityTokenDescriptor + { + SigningCredentials = Default.SymmetricSigningCredentials, + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{{JwtHeaderParameterNames.Cty, "str"}}, + AdditionalInnerHeaderClaims = new Dictionary{ {"int", "123" } }, + Audience = Default.Audience, + Issuer = Default.Issuer + }, + ValidationParameters = new TokenValidationParameters + { + IssuerSigningKey = Default.SymmetricSigningCredentials.Key, + TokenDecryptionKey = Default.SymmetricEncryptingCredentials.Key, + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer, + } + }, + new CreateTokenTheoryData + { + TestId = "Inner_CustomCty_Outer_DefaultCty", + TokenDescriptor = new SecurityTokenDescriptor + { + SigningCredentials = Default.SymmetricSigningCredentials, + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{ { "int", "123" } }, + AdditionalInnerHeaderClaims = new Dictionary{ { JwtHeaderParameterNames.Cty, "str" } }, + Audience = Default.Audience, + Issuer = Default.Issuer + }, + ValidationParameters = new TokenValidationParameters + { + IssuerSigningKey = Default.SymmetricSigningCredentials.Key, + TokenDecryptionKey = Default.SymmetricEncryptingCredentials.Key, + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer, + } + }, + new CreateTokenTheoryData + { + TestId = "EmptyAdditionalHeaderClaims", + TokenDescriptor = new SecurityTokenDescriptor + { + SigningCredentials = Default.SymmetricSigningCredentials, + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{ }, + AdditionalInnerHeaderClaims = new Dictionary{ { JwtHeaderParameterNames.Cty, "str" } }, + Audience = Default.Audience, + Issuer = Default.Issuer + }, + ValidationParameters = new TokenValidationParameters + { + IssuerSigningKey = Default.SymmetricSigningCredentials.Key, + TokenDecryptionKey = Default.SymmetricEncryptingCredentials.Key, + ValidAudience = Default.Audience, + ValidIssuer = Default.Issuer, + } + }, + new CreateTokenTheoryData + { + TestId = "DefaultParameterinAdditionalHeaderClaims", + TokenDescriptor = new SecurityTokenDescriptor + { + SigningCredentials = Default.SymmetricSigningCredentials, + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{ { JwtHeaderParameterNames.Enc, "str" } }, + AdditionalInnerHeaderClaims = new Dictionary{ { JwtHeaderParameterNames.Cty, "str" } }, + Audience = Default.Audience, + Issuer = Default.Issuer + }, + ExpectedException = ExpectedException.SecurityTokenEncryptionFailedException("IDX10616:", typeof(SecurityTokenException)) + }, + new CreateTokenTheoryData + { + TestId = "DefaultParameterinAdditionalInnerHeaderClaims", + TokenDescriptor = new SecurityTokenDescriptor + { + SigningCredentials = Default.SymmetricSigningCredentials, + EncryptingCredentials = Default.SymmetricEncryptingCredentials, + AdditionalHeaderClaims = new Dictionary{ { JwtHeaderParameterNames.Cty, "str" } }, + AdditionalInnerHeaderClaims = new Dictionary{ { JwtHeaderParameterNames.Enc, "str" } }, + Audience = Default.Audience, + Issuer = Default.Issuer + }, + ExpectedException = ExpectedException.SecurityTokenException("IDX12742:") + }, + }; + } + } + // Tests checks to make sure that the token string created by the JwtSecurityTokenHandler is consistent with the // token string created by the JsonWebTokenHandler. [Theory, MemberData(nameof(CreateJWEUsingSecurityTokenDescriptorTheoryData))] diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtTestDatasets.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtTestDatasets.cs index 6c9aa9e146..be9fc17d01 100644 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtTestDatasets.cs +++ b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtTestDatasets.cs @@ -328,7 +328,7 @@ public static TheoryData ValidateJwsWithLastKnownGoodTheoryData Token = Default.AsymmetricJws, ValidationParameters = new TokenValidationParameters { - ConfigurationManager = new MockConfigurationManager(incorrectSigningKeysConfig, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.1) }, + ConfigurationManager = new MockConfigurationManager(incorrectSigningKeysConfig, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.000001) }, ValidateIssuerSigningKey = true, RequireSignedTokens = true, ValidateIssuer = true, @@ -343,7 +343,7 @@ public static TheoryData ValidateJwsWithLastKnownGoodTheoryData Token = Default.AsymmetricJws, ValidationParameters = new TokenValidationParameters { - ConfigurationManager = new MockConfigurationManager(invalidIssuerConfig, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.1) }, + ConfigurationManager = new MockConfigurationManager(invalidIssuerConfig, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.000001) }, ValidateIssuerSigningKey = true, RequireSignedTokens = true, ValidateIssuer = true, @@ -358,7 +358,7 @@ public static TheoryData ValidateJwsWithLastKnownGoodTheoryData Token = Default.AsymmetricJws, ValidationParameters = new TokenValidationParameters { - ConfigurationManager = new MockConfigurationManager(incorrectSigningKeysConfigWithMatchingKid, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.1) }, + ConfigurationManager = new MockConfigurationManager(incorrectSigningKeysConfigWithMatchingKid, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.000001) }, ValidateIssuerSigningKey = true, RequireSignedTokens = true, ValidateIssuer = true, @@ -373,7 +373,7 @@ public static TheoryData ValidateJwsWithLastKnownGoodTheoryData Token = Default.AsymmetricJws, ValidationParameters = new TokenValidationParameters { - ConfigurationManager = new MockConfigurationManager(incorrectIssuerAndSigningKeysConfig, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.1) }, + ConfigurationManager = new MockConfigurationManager(incorrectIssuerAndSigningKeysConfig, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.000001) }, ValidateIssuerSigningKey = true, RequireSignedTokens = true, ValidateIssuer = true, @@ -388,7 +388,7 @@ public static TheoryData ValidateJwsWithLastKnownGoodTheoryData Token = Default.AsymmetricJws, ValidationParameters = new TokenValidationParameters { - ConfigurationManager = new MockConfigurationManager(validConfigKeyValidationFails, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.1) }, + ConfigurationManager = new MockConfigurationManager(validConfigKeyValidationFails, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.000001) }, ValidateIssuerSigningKey = true, RequireSignedTokens = true, ValidateIssuer = true, @@ -604,7 +604,7 @@ public static TheoryData ValidateJWEWithLastKnownGoodTheoryData Token = jwe, ValidationParameters = new TokenValidationParameters { - ConfigurationManager = new MockConfigurationManager(incorrectSigningKeysConfig, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.1) }, + ConfigurationManager = new MockConfigurationManager(incorrectSigningKeysConfig, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.000001) }, ValidateIssuerSigningKey = true, RequireSignedTokens = true, ValidateIssuer = true, @@ -620,7 +620,7 @@ public static TheoryData ValidateJWEWithLastKnownGoodTheoryData Token = jwe, ValidationParameters = new TokenValidationParameters { - ConfigurationManager = new MockConfigurationManager(invalidIssuerConfig, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.1) }, + ConfigurationManager = new MockConfigurationManager(invalidIssuerConfig, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.000001) }, ValidateIssuerSigningKey = true, RequireSignedTokens = true, ValidateIssuer = true, @@ -636,7 +636,7 @@ public static TheoryData ValidateJWEWithLastKnownGoodTheoryData Token = jwe, ValidationParameters = new TokenValidationParameters { - ConfigurationManager = new MockConfigurationManager(incorrectSigningKeysConfigWithMatchingKid, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.1) }, + ConfigurationManager = new MockConfigurationManager(incorrectSigningKeysConfigWithMatchingKid, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.000001) }, ValidateIssuerSigningKey = true, RequireSignedTokens = true, ValidateIssuer = true, @@ -652,7 +652,7 @@ public static TheoryData ValidateJWEWithLastKnownGoodTheoryData Token = jwe, ValidationParameters = new TokenValidationParameters { - ConfigurationManager = new MockConfigurationManager(incorrectIssuerAndSigningKeysConfig, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.1) }, + ConfigurationManager = new MockConfigurationManager(incorrectIssuerAndSigningKeysConfig, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.000001) }, ValidateIssuerSigningKey = true, RequireSignedTokens = true, ValidateIssuer = true, @@ -668,7 +668,7 @@ public static TheoryData ValidateJWEWithLastKnownGoodTheoryData Token = jwe, ValidationParameters = new TokenValidationParameters { - ConfigurationManager = new MockConfigurationManager(validConfigKeyValidationFails, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.1) }, + ConfigurationManager = new MockConfigurationManager(validConfigKeyValidationFails, validConfig) {LastKnownGoodLifetime = TimeSpan.FromMilliseconds(.000001) }, ValidateIssuerSigningKey = true, RequireSignedTokens = true, ValidateIssuer = true,