XSRF-Token, SuperOffice 9 and user getting logged out?

Hi,

we're troubleshooting an issue at an onsite customer where a user is kicked out of the 9.1 webclient several times each day.

One of the leads I'm following is the fact that the logfile complains that "X-XSRF-TOKEN HTTP header not valid", so I'm trying to dig into how XSRF tokens are handled in the GUI, and if this could cause user to be logged out, or if the errormessage is a consequence of another issue. 

My understanding of XSRF in SuperOffice thus far is this;

- XSRF tokens are used as a security mechanism when javascript calls the new REST API in SuperOffice.

- The XSRF token is generated serverside, and remains the same during the entire session. Logging out and back in, or logging in from another browser will assign a new token.

- The token is delivered in two ways from the server to the client - both in a HTML element called 'XSRF_TOKEN', and in a cookie called 'XSRF-TOKEN'.

- When navigating in the GUI many requests are done back to the server, and the token is sent to the server via Cookie for absolutely all requests (even for static images). I don't think sending XSRF token in cookie back to server is used for anything. Token could probably have been stored in local storage instead.

- Requests to the new REST API at /SuperOffice/api/... (typically for getting data for archives) will include a HTTP header called X-XSRF-TOKEN. This is the scenario where the token is actually required since server will return a 400-error if the header does not contain the correct token.

- By intentionally breaking the XSRF token in the GUI (by editing the HTML code for XSRF_TOKEN in Chrome developer tools, and changing the value of the XSRF-TOKEN), and navigating in the client I can observe HTTP Status Code 400 errors from some of the calls. However I'm not logged out.

- Some of the requests from the GUI to the REST API will use the XSRF token retrieved from HTML element, while other requests will use the value from the XSRF-TOKEN cookie.

- I am not sure if WebTools uses X-XSRF-TOKEN, but from the stacktrace in the netserver logfile it might seem so.

Hopefully someone can confirm, ammend or refute some of my assumptions above, so that we can get a good understanding of how this works.

Can problems with XSRF token cause user session to be terminated?

RE: XSRF-Token, SuperOffice 9 and user getting logged out?

XSRF only applies to api calls - it should not affect the user login.

Basically the XSRF value tells the API to use the session state and use the session there rather than try to create its own session using an HTTP Authenticate header.

Af: Christian Mogensen 17. feb 2021

RE: XSRF-Token, SuperOffice 9 and user getting logged out?

Intresting, we have the same issue with an user, onsite SuperOffice 9.3 installation.

We have managed to catch a glimp of the console errors when the user's session was aborted which showed multiple reference the chrome-extension://, we have now disabled all extensions but the issue still occured once. Waiting for it to happen again.

Debugging issue is pretty hard since no server side log is made and the console is cleared from logs since user is redirected to login page.

Af: David Hollegien 18. feb 2021

RE: XSRF-Token, SuperOffice 9 and user getting logged out?

Hi David,

try setting "Preserve log" so that it's not cleared?

Af: Frode Lillerud 18. feb 2021

RE: XSRF-Token, SuperOffice 9 and user getting logged out?

Hi,

We did do that, but last time it happend after we enabled that function the console was still clear. Hasn't happend since so we will see..

Af: David Hollegien 18. feb 2021

RE: XSRF-Token, SuperOffice 9 and user getting logged out?

We also have a SO Web 8.5 onprem customer where several users are being kicked out of SuperOffice several times per day. I cannot say if this is related to XSRF or not, but it looks like this has something to do with Chrome. Tests performed by the customer itself may indicate that Edge is more stable than Chome.

Have you seen any different behavior between different browsers?

Af: Arild Eik 19. feb 2021

RE: XSRF-Token, SuperOffice 9 and user getting logged out?

Got an call from the customer again, console shows this, first an 500 error when doing an GetContextMenu call and then a lot of repeating errors because user is not logged in anymore

Error logs show the following:

Level:   Error
At:      14:20:37

Element:
Message: https:///SuperOffice/Default.aspx
Details:
   at SuperOffice.DCF.Web.SoFormsAuthentication.InitSession()
   at SuperOffice.DCF.Web.ApplicationUtility.ExecuteAjaxMethodImplementation(AjaxMethodPreImplementation preAuthenticateImplementation, AjaxMethodImplementation implementation)

Inner Element:
Message: User is not authenticated with NetServer (HttpContext)
Type:    SuperOffice.Exceptions.SoSessionException
Details:
   at SuperOffice.DCF.Web.SoFormsAuthentication.InitSession()

Environment info:
Ip-address:                    
From page:                      /SuperOffice/default.aspx?diary.day.diarysalearchive?diaryowner_id=44&appointment_id=21838&sale_id=621&document_id=3647
Browser-type:                   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36
Absolute URI:                  /SuperOffice/clientapi/sessionrequiredmethods/method?ajaxmethod=SuperOffice.CRM.Web.AjaxMethods.ContextMenu.GetContextMenu
Server:                         
ASP.NET state:                  HttpRequest.IsAuthenticated = False; HttpContext is available; HttpContext.SkipAuthorization = False; HttpSessionState.IsNewSession = False; HttpSessionState.IsReadOnly = False; HttpSessionState.Mode = InProc; HttpSessionState.Keys = [SoHttpContextProvider] [SoCrmUserPreferences] [SoCrmCachedPreferences] [SoCrmCurrentUserCulture] [SoCrmCurrentUserUICulture] [temp] [SoHttpContextProvider.SetNull.StackTrace] [SoHttpContextProvider.SetNull.ThreadName] [SoHttpContextProvider.SetNull.User] ; 
SuperState:                     User not authenticated with NetServer.
SingleThreadMode:               False
AjaxMethod.method:              SuperOffice.CRM.Web.AjaxMethods.ContextMenu.GetContextMenu
AjaxMethod.superstatecopy:      
AjaxMethod.parameters.0:        headingmenu
AjaxMethod.parameters.1:        personal
AjaxMethod.parameters.2:        0
SoHttpContextProvider.SetNull.User:
(null identity)

SoHttpContextProvider.SetNull.StackTrace:
   at SuperOffice.Web.Security.HttpContextProvider.SetCurrentContext(SoContextContainer newContext)
   at SuperOffice.SoContext.Authenticate(SecurityToken[] tokens)
   at SuperOffice.DCF.Web.SoFormsAuthentication.LoginIn(SoSession& soSession, LoginOperation loginOperation)
   at SuperOffice.DCF.Web.SoFormsAuthentication.TryAutomatedLogin(SoSession& session, SetLicenseFailure licenseFailure, Boolean testForImplicitLogin, AutomatedLoginAction action)
   at SuperOffice.DCF.Web.SoFormsAuthentication.RedirectIfNotAuthenticated(Boolean allowExceptions)
   at SuperOffice.DCF.Web.Protocol.SoProtocolModule.<>c.<Init>b__3_0(Object sender, EventArgs args)
   at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
   at System.Web.HttpApplication.PipelineStepManager.ResumeSteps(Exception error)
   at System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb)
   at System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)
   at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)


SoHttpContextProvider.SetNull.ThreadName:
(null)

TS.SoHttpContextProvider.SetNull.User:
SuperOffice.Security.Principal.SoCredentialsIdentity

TS.SoHttpContextProvider.SetNull.StackTrace:
   at SuperOffice.Web.Security.HttpContextProvider.SetCurrentContext(SoContextContainer newContext)
   at SuperOffice.SoSession.Dispose()
   at SuperOffice.WebTools.AspNet.NetserverUserContextProvider.GetFor(IRequest request)
   at SuperOffice.WebTools.AspNet.Web.WebToolsConnection.<>c__DisplayClass1_0.<AuthorizeRequest>b__0()
   at SuperOffice.WebTools.AspNet.Web.WebToolsConnection.WithWebToolsLogContext[T](Func`1 action)
   at Microsoft.AspNet.SignalR.PersistentConnection.ProcessRequest(IDictionary`2 environment)
   at Microsoft.Owin.Mapping.MapMiddleware.<Invoke>d__3.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[TStateMachine](TStateMachine& stateMachine)
   at Microsoft.Owin.Mapping.MapMiddleware.Invoke(IDictionary`2 environment)
   at Microsoft.Owin.Mapping.MapMiddleware.<Invoke>d__3.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[TStateMachine](TStateMachine& stateMachine)
   at Microsoft.Owin.Mapping.MapMiddleware.Invoke(IDictionary`2 environment)
   at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContextStage.<RunApp>d__7.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[TStateMachine](TStateMachine& stateMachine)
   at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContextStage.RunApp(Func`2 entryPoint, IDictionary`2 environment, TaskCompletionSource`1 tcs, StageAsyncResult result)
   at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContextStage.BeginEvent(Object sender, EventArgs e, AsyncCallback cb, Object extradata)
   at System.Web.HttpApplication.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
   at System.Web.HttpApplication.PipelineStepManager.ResumeSteps(Exception error)
   at System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb)
   at System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)
   at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)


TS.SoHttpContextProvider.SetNull.ThreadName:
(null)

Database type:                  MSSQL - 12
Database:                       \\\
SerialNumber:                   
Version:                        SuperOffice 9.2 R3 NetServer 9.2 Release (Build: Release92_C-2020.12.09-02)
Version.Assembly:               9.2.0.0
Version.File:                   9.2.7648.1007
Version.BuildLabel:             Release92_C-2020.12.09-02
ContextIdentifier:              Default
MachineName:                    
StackTrace:                        at SuperOffice.DCF.Web.ApplicationUtility.HandleException(Page page, Exception ex, Boolean logErrorAsWarning)
   at SuperOffice.DCF.Web.ApplicationUtility.ExecuteAjaxMethodImplementation(AjaxMethodPreImplementation preAuthenticateImplementation, AjaxMethodImplementation implementation)
   at SuperOffice.DCF.Web.AjaxMethods.AjaxMethodReciever.Execute(String method, String superstatecopy, Object[] parameters)
   at SuperOffice.Web.Controllers.MethodControllerBase._method(Object data)
   at lambda_method(Closure , Object , Object[] )
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at System.Web.Http.Controllers.ApiControllerActionInvoker.InvokeActionAsyncCore(HttpActionContext actionContext, CancellationToken cancellationToken)
   at System.Web.Http.Controllers.ApiControllerActionInvoker.InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at System.Web.Http.Controllers.ActionFilterResult.ExecuteAsync(CancellationToken cancellationToken)
   at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Web.Http.Cors.CorsMessageHandler.<HandleCorsRequestAsync>d__5.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at System.Web.Http.Cors.CorsMessageHandler.HandleCorsRequestAsync(HttpRequestMessage request, CorsRequestContext corsRequestContext, CancellationToken cancellationToken)
   at System.Web.Http.Cors.CorsMessageHandler.<SendAsync>d__0.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at System.Web.Http.Cors.CorsMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at SuperOffice.Services.WebApi.Handlers.SoResponseHandler.<SendAsync>d__0.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at SuperOffice.Services.WebApi.Handlers.SoResponseHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at SuperOffice.Services.WebApi.Handlers.SoWebApiAuthenticationHandler.<ExecuteRequest>d__1.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at SuperOffice.Services.WebApi.Handlers.SoWebApiAuthenticationHandler.ExecuteRequest(HttpRequestMessage request, CancellationToken cancellationToken)
   at SuperOffice.Services.WebApi.Handlers.SoWebApiAuthenticationHandler.AuthenticateAndExecute(HttpRequestMessage request, CancellationToken cancellationToken, Func`3 executeRequest)
   at SuperOffice.Services.WebApi.Handlers.SoWebApiAuthenticationHandler.<SendAsync>d__0.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at SuperOffice.Services.WebApi.Handlers.SoWebApiAuthenticationHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at SuperOffice.Services.WebApi.Handlers.SoHeadersHandler.<SendAsync>d__7.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at SuperOffice.Services.WebApi.Handlers.SoHeadersHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at SuperOffice.Web.WebApi.Handlers.SoSuperStateCopyHandler.<SendAsync>d__0.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at SuperOffice.Web.WebApi.Handlers.SoSuperStateCopyHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Web.Http.HttpServer.<SendAsync>d__0.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at System.Web.Http.HttpServer.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Web.Http.WebHost.HttpControllerHandler.<ProcessRequestAsyncCore>d__0.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[TStateMachine](TStateMachine& stateMachine)
   at System.Web.Http.WebHost.HttpControllerHandler.ProcessRequestAsyncCore(HttpContextBase contextBase)
   at System.Web.TaskAsyncHelper.BeginTask(Func`1 taskFunc, AsyncCallback callback, Object state)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
   at System.Web.HttpApplication.PipelineStepManager.ResumeSteps(Exception error)
   at System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb)
   at System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)
   at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
Af: David Hollegien 19. feb 2021

RE: XSRF-Token, SuperOffice 9 and user getting logged out?

I get exactly the same log entries in our case. Some days we get way over 3000 entries of this message in the log

Af: Arild Eik 19. feb 2021

RE: XSRF-Token, SuperOffice 9 and user getting logged out?

Did you get any further with this Frode? I have created a separate thread about issues we are having at customers, which also seem to be caused by an invalid/expired XSRF-TOKEN

Af: David Hollegien 23. feb 2021

RE: XSRF-Token, SuperOffice 9 and user getting logged out?

Hi David, no nothing concrete yet. Did some simple experiments based on your other thread yesterday, but no solid conclusions came from it. I don't know if our customers have experienced the funky GUI problems that you showed.

We have several customers getting kicked out, but few good leads as to why, yet.

The image you showed where the XSRF token sent in the header and the cookie were different seems fishy to me, but I've got a feeling this is a symptom, not the root cause.

Af: Frode Lillerud 23. feb 2021

RE: XSRF-Token, SuperOffice 9 and user getting logged out?

Looking at this some more again tonight. Have left Edge open for half an hour or so, and see that out of the blue it ends up with this request that fails with a 500-error, and the response tells the browser to clear its cookies and go to the loginpage.

Looking at the network request history there is a successful request to the same endpoint 30 minutes earlier, and after that there has only been made /signalr related requests. 

On my machine I also get different behavior in Edge and Chrome. My edge is kicking me out, while chrome is stable. At the customer it's the other way around.

One theory could also be that it is related to the new "sleeping tabs" functionality in chromium, although that is just an idea at this point.

Af: Frode Lillerud 25. feb 2021