Service Gateway / Http Request / Session

Hi Mythz,

When I SendAsync through the Gateway (in process) from the Controller base class the service handler seems to loose reference to the existing session. I’ve put some logging in AuthEvents OnCreated and it appears my session get recreated when the service handles the message.

I thought the http request (which is used to derive the existing session?) was passed through for in process messages.

Anything I might be missing?

Dan

The session gets created on first access. It’s strange it would lose the session as we’re using the same IRequest instance. Is the behavior different when using sync Send()?

Yes its the same with sync Send. Only other thing to mention its not authenticated.

Also in my logging the Id changes as soon as its referenced inside the service - hence confirming its rolling up a new one.

Ok so then it’s just creating a new session when you try to access the Session, doesn’t have anything to do with the gateway. Creating a Session here just means creating a new Session instance since one doesn’t exist - a new instance is created/returned when accessing an unauthenticated session (i.e. instead of returning null) but it’s not saving the Session to the cache.

What do you mean by lose Session though? If they’re unauthenticated they don’t have a persisted session?

Ok sorry bit of a red herring.

Within my service a call to the authentication is taking place. When authenticated this is obviously going to change the id - which explains this. I have the checked the request and the session is passing through the gateway correctly.

So I have changed things for a minute to call to the authenticate service using ResolveService directly from the controller - when this is completed the session is saved in the cache (InMemory) but when I try and reference this within the same request (Via UserSession in the Servicestack controller) it gives me a new one.

Does the request need to complete before the cache is available to read in the manner - or should it be available as soon as authenticated and later on in the request.

By ServiceStack controller do you mean you’re calling and accessing the session from an MVC controller?

I’m having a hard time following, can you provide code showing the issue, i.e. where you’re calling ResolveService and where you’re calling UserSession later within the same Request. A request from MVC isn’t the same as a normal ServiceStack Request. When you’re saying “try and reference this within the same request” do you mean within the same MVC Action?

Yes ServiceStackController and within the same action (http request). Sorry for not being clear.

    public ActionResult LoginSubmit(LoginViewModel model)
    {
        if (!ModelState.IsValid)
        {
            return View("Login", model);
        }

   
        var sr = ServiceResultBase.Create<AuthenticateResponse>();
        using (var service = ResolveService<AuthenticateService>())
        {

            try
            {
                sr.Data = service.Authenticate(new Authenticate()
                {
                    UserName = model.Email,
                    Password = model.Password,
                    RememberMe = model.RememberMe,
                    provider = CredentialsAuthProvider.Name
                });
                
            }
            catch (HttpError ex)
            {

                sr.SetCode((ServiceResultStatus) ex.StatusCode, ex.Message);
            }
        }

        this.AddToastMessage(sr, true);

        var session = UserSession; // this is a new session - not the one stored in the cache
   }

Is session.IsAuthenticated not true?

I’ve just tried calling AuthenticateService locally and I am seeing an Authenticated Session returned, you shouldn’t rely on it being the same instance but I’m also seeing that it’s the same instance that’s in the Memory cache.

Can you add this code below UserSession and let me know if session1 == session2 is true:

var session1 = base.SessionAs<AuthUserSession>();

var sessionKey = SessionFeature.GetSessionKey(ServiceStackRequest);
var cache = ServiceStackRequest.GetCacheClient();
var session2 = cache.Get<AuthUserSession>(sessionKey);

var equals = session1 == session2;
equals.ToString().Print();

You can replace AuthUserSession with your Custom UserSession type.

Not true - but because of the following.

session2 is null and isn’t found in the cache because the sessionKey that is returned is different to the key that is logged in the OnAuthenticated method in the authevents class.

Its like the request isn’t being updated with the authenticated session Id.

Session 1 IsAuthenticated is false.

Can you paste the raw HTTP Request Headers for this Request (you can use Fiddler or WebInspector - please remove any sensitive info) so we can see the Cookies sent with the request as well as the 2 sessionKeys that are different.

Right it’s working now I cleared the cache. It’s because there was already a perm session id in the cookie, but no matching one in the cache, why would this of caused the weird behaviour. I thought authenticating would of cleared the existing auth headers?

Because I’m using the InMemoryCache obviously the session does not exist when I restart the app but the cookie does. But what happens if you clear the cache down for whatever reason in production.

POST /account/loginsubmit HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, */*
Referer: http://localhost:35561/account/login
Accept-Language: en-GB
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Content-Length: 194
Host: localhost:35561
Connection: Keep-Alive
Pragma: no-cache
Cookie: ss-pid=mIkmorMA4B8BYiA3e54M; cb-enabled=accepted; X-UAId=1014; ss-opt=perm; __RequestVerificationToken=qBR23IRlZHLxiaH5DxTXm4xbdu5dl_tJBrM5eIL7DH9I7AStVkkp_hfVNilMwjHImvK4WXX_PKZRF04jwDU0d7qhMoQ1

Are you using the latest version of ServiceStack? Recent versions of ServiceStack with AuthFeature.GenerateNewSessionCookiesOnAuthentication = true (the default) should generate new cookies, although the way Cookies work the Response needs to be sent back to the client for it to use the new Cookies. You can also use the explicit /auth/logout route to clear the Session cookies - which is more direct as you’re not going through MVC. If you can provide a stand-alone repro showing the Issue I can investigate the issue you’re seeing.

If you clear the Cache the Session is lost and the User is Un Authenticated unless you use any of the other distributed Caching Providers.

Right a bit more digging:

If the value of ss-pid cookie does not exist in the cache and the value of ss-opt cookie is perm, when you try to authenticate as temp session then it falls over, it’s like it doesn’t clears the cookies properly.
If I analyse the IRequest inside the authevents OnAuthenticated then it contains the session item and id values which have been added by the auth. However when re-inspecting the IRequest at the end of the Mvc action its not there.

However you authenticate as perm session its fine and clears down the old stale cookie values and the session gets added to the underlying IRequest and everything works fine.

Also what part does the x-UAId cookie play?

Dan

If moving from using permanent to temporary Session Ids was the issue this should be resolved with this commit.

This change is available from v4.0.51 that’s now available on MyGet.

The X-UAId is just metadata containing the User’s Auth Id, it’s not used by ServiceStack but can be useful for proxies and load balancers for reporting, routing or debugging.

Sorry forgot to reply - that sorted the issue. As always thanks for you help.

1 Like