Skip to content

OpenIdConnectOptions DI StateDataFormat/DataProtector different purposes #13316

@joshhubers

Description

@joshhubers

Describe the bug

When I dependency inject my OpenIdConnectOptions and access the StateDataFormat the DataProtector that is used has a different purpose than what is being used internally by the rest of the framework.

I have a custom Open Id Connect server with a custom endpoint that requires the 'state' parameter to be manually created. (Login/Logout functionality working fine. Can post Startup config if needed) To create the state I use the following:

  private string GenerateState()
  {
    var state = GenerateNonce();
    AuthenticationProperties authProperties = new AuthenticationProperties
    (
      new Dictionary<string, string>
      {
        { OpenIdConnectDefaults.UserstatePropertiesKey, state },
      }
    );

    authProperties.RedirectUri = "http://localhost:5000";

    //This StateDataFormat does not use the correct DataProtector
    return OpenIdOptions.CurrentValue.StateDataFormat.Protect(authProperties);
  }

Where openIdOptions is direct injected. From verbose logging I can see when the method is called and uses the behind the scenes DataProtector:

trce: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector[31]
Performing protect operation to key {cdf7e79b-8d1a-4e7e-a093-fea402dbba8c} with purposes ('/app/DataManager', 'Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler', '', 'v1').

Later down the pipe the authentication happens on the Open Id Connect server and when the server comes back to the client I get the following error:

An unhandled exception has occurred while executing the request.                                                                                                                                             
System.Exception: An error was encountered while handling the remote login.                                           
System.Exception: Unable to unprotect the message.State.

Source code location

My assumption is that the state is not being decrypted properly when it returns to the client because I see this in the logs:

trce: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector[5]
Performing unprotect operation to key {cdf7e79b-8d1a-4e7e-a093-fea402dbba8c} with purposes ('/app/DataManager', 'Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler', 'oidc', 'v1').

Unprotect happening in the framework here

The key difference being when encrypting it has an empty purpose, and when decrypting it includes 'oidc' in it's purpose.

I'm new to the whole data protection realm, but from the docs it says that the purpose is hashed in the encryption process which may be the source of the decryption issue.

I have also tried to manually set the DataProtectionProvider on the OpenIdConnectOptions to use a provider that would return a DataProtector with the same purpose, but internally it would still use the same DataProtector as if it were instantiating a new protector regardless of the one supplied.

Default protector/StateDataFormat being created here

Expected behavior

I would expect that the DataProtector used behind the scenes in the framework and the one that is DI from OpenIdConnectOptions to be the same with the same purposes.

Additional context

.NET Core SDK (reflecting any global.json):
 Version:   3.0.100-preview8-013656
 Commit:    8bf06ffc8d

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  19.04
 OS Platform: Linux
 RID:         ubuntu.19.04-x64
 Base Path:   /usr/share/dotnet/sdk/3.0.100-preview8-013656/

Host (useful for support):
  Version: 3.0.0-preview8-28405-07
  Commit:  d01b2fb7bc

.NET Core SDKs installed:
  3.0.100-preview8-013656 [/usr/share/dotnet/sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.App 3.0.0-preview8.19405.7 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.0.0-preview8-28405-07 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

Using docker image - mcr.microsoft.com/dotnet/core/sdk:3.0.100-preview8-disco

Metadata

Metadata

Assignees

Labels

area-authIncludes: Authn, Authz, OAuth, OIDC, Bearer

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions