SessionCache in Redis - strange entries

I use Redis as data store for users and session cache.
I use the following code in my services:

var redisOpsManAdminPool = new PooledRedisClientManager(myConfiguration.GetRedisAdminConnString());
var redisCachePool = new PooledRedisClientManager(myConfiguration.GetRedisCacheConnString());
container.Register(c => new BizBusUserRepository(redisOpsManAdminPool));
container.Register<IRedisClientsManager>(c => redisOpsManAdminPool);
container.Register<IAuthRepository>(c => new RedisAuthRepository(redisOpsManAdminPool));

I use API keys to authenticate server to server REST calls. So I enabled the following ServiceStack plugin:

Plugins.Add(new AuthFeature(() => new AuthUserSession(),
    new IAuthProvider[]
    {
          new BizBusAuthProvider(),
          new ApiKeyAuthProvider(AppSettings)
          {
                KeyTypes = new[] {"secret"},
                RequireSecureConnection = false,
           },
    }
    )
    {
            ValidUserNameRegEx = new Regex(@"^(?=.{5,53}$)([\p{L}\w][.!_-]?)*$", RegexOptions.Compiled),
    });

To establish a connection with another server I use

public JsonServiceClient BbDataExchangeService
{
    get
{
    if (_bbDataExchangeService == null || string.IsNullOrEmpty(_bbDataExchangeService.BearerToken))
        {
	  _bbDataExchangeService = new JsonServiceClient(MyServiceConfig.ServerConfiguration.GetDataExchangeServiceUri())
               {
	        BearerToken = MyServiceConfig.ServerConfiguration.MyApiKey
	   };
    }
    return _bbDataExchangeService;
    }
 private set => _bbDataExchangeService = value;
}

This is a property of an object registered in the IOC container with singleton scope. So if the session times out, it is automatically re-created.

Now the strange thing on Redis (Only in the datacenter, in my dev environment I have never seen this)
I have hundreds of sessions which look as follows and which get never cleaned up:

{
  "__type": "ServiceStack.AuthUserSession, ServiceStack",
  "id": "AcjKamHpcYqvgWwggIan",
  "createdAt": "\/Date(1548064695604)\/",
  "lastModified": "\/Date(1548064695604)\/",
  "isAuthenticated": false,
  "fromToken": false,
  "tag": 0,
  "providerOAuthAccess": [],
  "meta": {
	
  }
}

Of course such sessions end up with 401 and 403 errors. Out of about 30 entries only one is correct!!

A correct cache entry should look similar to this:

{
  "__type": "ServiceStack.AuthUserSession, ServiceStack",
  "id": "13Ea0sYGJRVYEk5VvTKr",
  "userAuthId": "1",
  "userAuthName": "bbopsmanager",
  "userName": "bbopsmanager",
  "displayName": "BizBus bbopsmanager server on bbopman01-lfdev-t74-app01",
  "fullName": "BizBus bbopsmanager server on computer bbopman01-lfdev-t74-app01",
  "createdAt": "\/Date(1548065075640)\/",
  "lastModified": "\/Date(1548065076985)\/",
  "roles": [
	"SomeServiceRole"
  ],
  "permissions": [],
  "isAuthenticated": true,
  "fromToken": false,
  "tag": 0,
  "authProvider": "apikey",
  "providerOAuthAccess": [],
  "meta": {
	
  }
}

I have seen up to 1000 entries with empty, unauthenticated objects and they remain there forever until I remove them manually!

Does anybody had similar issues with Redis session cache? Any idea what could be wrong here??

This is an example of saving an empty (i.e. Un Authenticated) UserSession somewhere, I can’t see anywhere in ServiceStack where it would save an UnAuthenticated Session so I’d look at anywhere you’re using SaveSession() in your code.

You can prevent it by overriding OnSaveSession in your AppHost, e.g:

public override void OnSaveSession(
    IRequest httpReq, IAuthSession session, TimeSpan? expiresIn = null) 
{ 
    if (!session.IsAuthenticated)
        throw new Exception("Don't save UnAuthenticated Sessions");

    base.OnSaveSession(httpReq, session, expiresIn); 
}

The Exception StackTrace should indicate which code is calling SaveSession() that’s saving the UnAuthenticated User Session.

Hi Demis,
Interesting, I did a grep on my entire project disk and I found that code! I have only very few services which do not require authentication, one is called by a monitoring system (which could explain the hundreds of entries…)

The code is in my sliding authentication implementation:

//sliding authentication
GlobalResponseFilters.Add((httpReq, httpRes, dto) =>
{
	var session = httpReq.GetSession();
	httpReq.SaveSession(session, TimeSpan.FromMinutes(CommonConstants.SessionExpiryInMinutes));
});

I wrote this code two or three years ago and it is in all my servers. I followed a recipe in this Book. I saw that in the online documentation the code has slightly changed:

GlobalResponseFilters.Add((req, res, dto) =>
{
    var session = req.GetSession();
    if (session != null)
        req.SaveSession(session, TimeSpan.FromMinutes(10));
});

It checks if (session != null) .... Does that mean that unauthenticated sessions are NULL?

Thanks a lot for the hint!

I think I better replace the code with:

//sliding authentication
GlobalResponseFilters.Add((httpReq, httpRes, dto) =>
{
	var session = httpReq.GetSession();
	if (!session.IsAuthenticated)
	{
		httpReq.SaveSession(session, TimeSpan.FromMinutes(CommonConstants
			.SessionExpiryInMinutes));
	}
});

GetSession() returns an empty session if they’re not authenticated so you should check for session.IsAuthenticated

Ok, one last question: What data type is

"createdAt": "\/Date(1548099839487)\/",
"lastModified": "\/Date(1548099839580)\/",

Which I can see in the Redis database. It is not a DateTime…

It is a serialized DateTime, which uses the WCF JSON Serialization DateTime format by default.