Search code examples
c#identityserver4

The default requested state parameter value length is not supported for my external authorization request in identity server 4 .Net Core


1. Tried to customize the state parameter with the below code



options.Events = new OpenIdConnectEvents
                    {
                        OnRedirectToIdentityProvider = (RedirectContext context) =>
                        {
                            //context.ProtocolMessage.SetParameter("CustomParameter", "Test");
                            //context.Properties.Items.Add(OpenIdConnectDefaults.RedirectUriForCodePropertiesKey, context.ProtocolMessage.RedirectUri);
                            //context.ProtocolMessage.State = context.Options.StateDataFormat.Protect(context.Properties);
                            context.ProtocolMessage.State = Guid.NewGuid().ToString();
                            context.Response.Redirect(context.ProtocolMessage.CreateAuthenticationRequestUrl());
                            context.HandleResponse();
                            return Task.CompletedTask;
                        }

Getting the below error after authenticated with external login screen.

2021-08-25 15:17:52.713 +00:00 [ERR] 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.
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
   at IdentityServer4.Hosting.FederatedSignOut.AuthenticationRequestHandlerWrapper.HandleRequestAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext

context) at IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)

Q1: Is there any way to customize the state parameter value? Default generated value length is my only concern. 
Q2: Is it possible to set guid as status param value?

Please advise.

Solution

  • By default context Authentication properties are encrypted by Protect method in OnRedirectToIdentityProvider and then from the successful authentication state, it will be decrypted by UnProtect method in OnMessageReceived. We have to in between mapping the data of the custom guid and the protected string later to Unprotect the Authentication properties.

        options.Events = new OpenIdConnectEvents
                            {
                                OnRedirectToIdentityProvider = (RedirectContext context) =>
                                {
                                    //context.ProtocolMessage.SetParameter("CustomParameter", "Test");
                                    context.Properties.Items.Add(OpenIdConnectDefaults.RedirectUriForCodePropertiesKey, context.ProtocolMessage.RedirectUri); ;
                                    context.ProtocolMessage.State = CacheHelper.SetMemoryCache(Guid.NewGuid().ToString(), context.Options.StateDataFormat.Protect(context.Properties));
                                    context.Response.Redirect(context.ProtocolMessage.CreateAuthenticationRequestUrl());
                                    context.HandleResponse();
                                    return Task.CompletedTask;
                                },
                                OnMessageReceived = (MessageReceivedContext context) =>
                                {
                                    context.ProtocolMessage.State = CacheHelper.GetMemoryCache(context.ProtocolMessage.State);
                                    context.Properties = context.Options.StateDataFormat.Unprotect(context.ProtocolMessage.State);
                                    return Task.CompletedTask;
                                },
                                OnAuthorizationCodeReceived = (AuthorizationCodeReceivedContext context) =>
                                {
                                    return Task.CompletedTask;
                                }
                            };