white.devils
white.devils

Reputation: 131

ServiceStack ServiceClient stores wrong cookies after authentication

i have a strange problem with Servicestack Authentication. I've developed an Asp .Net Core web app (.net core 3.1) in which is implemented a servicestack authentication with credentials auth provider. Everything work correctly if i authenticate with any browsers.

Instead if i try to authenticate from external application with JsonServiceClient pointing to servicestack /auth/{provider} api i've this problem: authentication goes well but the JsonServiceClient object stores a SessionId in cookies (s-id/s-pid) different from the SessionId of AuthenticateResponse. Here my example.

Authenticate request = new Authenticate()
{
  provider = "credentials",
  UserName = username,
  Password = password,
  RememberMe = true
};
var client = new JsonServiceClient(webappUrl);
AuthenticateResponse response = await client.PostAsync(request);
var cookies = client.GetCookieValues();

If i check values in cookies variable i see that there are s-id and s-pid completely different from the sessionId of the response.

The other strange thing is that if i repeat the authentication a second time under those lines of code, now the s-pid cookie is equal to sessionId of response! Why??

In the startup of web app i have these lines of code:

public new void ConfigureServices(IServiceCollection services)
{

  services.AddMvc(options => options.EnableEndpointRouting = false);

  // Per accedere all'httpcontext della request
  services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
  // Per accedere alla request context della request
  services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();

  // Registro il json di configurazione (innietta l'appSettings)
  services.AddSingleton(Configuration);

  // Filters
  services.AddSingleton<ModulePermissionFilter>();

  services.Configure<CookiePolicyOptions>(options =>
  {
    // This lambda determines whether user consent for non-essential cookies is needed for a given request.
    options.CheckConsentNeeded = context => false;
    options.MinimumSameSitePolicy = SameSiteMode.None;
  });

  services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);

  ... other lines of code
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IBackgroundJobClient backgroundJobs)
{
  app.UseStaticFiles();
  app.UseCookiePolicy();
  app.UseAuthentication();

  app.UseServiceStack(new AppHost
  {
    AppSettings = new NetCoreAppSettings(Configuration)
  });
}

public class AppHost : AppHostBase
{
  public AppHost() : base("webapp", typeof(BaseServices).Assembly) { }

  // Configure your AppHost with the necessary configuration and dependencies your App needs
  public override void Configure(Container container)
  {
    SetConfig(new HostConfig
    {
        UseCamelCase = false,
        WriteErrorsToResponse = true,
        ReturnsInnerException = true,
        AllowNonHttpOnlyCookies = false,
        DebugMode = AppSettings.Get(nameof(HostConfig.DebugMode), HostingEnvironment.IsDevelopment()),

        // Restrict cookies to domain level in order to support PflowV2
        RestrictAllCookiesToDomain = !string.IsNullOrEmpty(AppSettings.Get("RestrictAllCookiesToDomain", "")) && AppSettings.Get("RestrictAllCookiesToDomain", "").ToLower() != "localhost" ? AppSettings.Get("RestrictAllCookiesToDomain", "") : null
    });

     // Create DBFactory for cache
    var defaultConnection = appHost.AppSettings.Get<string>("ConnectionStrings:Webapp");
    var dbFactory = new OrmLiteConnectionFactory(defaultConnection, SqlServerDialect.Provider);

    // Register ormlite sql session and cache
    appHost.Register<IDbConnectionFactory>(dbFactory);
    appHost.RegisterAs<OrmLiteCacheClient, ICacheClient>();
    appHost.Resolve<ICacheClient>().InitSchema();
    appHost.Register<ISessionFactory>(new SessionFactory(appHost.Resolve<ICacheClient>()));

    //Tell ServiceStack you want to persist User Auth Info in SQL Server
    appHost.Register<IAuthRepository>(new OrmLiteAuthRepository(dbFactory));
    appHost.Resolve<IAuthRepository>().InitSchema();

    var sessionMinute = appHost.AppSettings.Get("SessionTimeoutMinute", 15);

    // Adding custom usersession and custom auth provider
    Plugins.Add(new AuthFeature(() => new CustomUserSession(), new IAuthProvider[] { new CustomCredentialsAuthProvider(), new ApiKeyAuthProvider() })
    {
        HtmlRedirect = "/Account/Login", // Redirect to login if session is expired
        IncludeAssignRoleServices = false,
        SessionExpiry = TimeSpan.FromHours(sessionMinute),
    });

    Plugins.Add(new SessionFeature());
  }
}

Upvotes: 0

Views: 164

Answers (0)

Related Questions