Sunday, March 5, 2017

ASP.NET MVC: How do SimpleMembership, SQLSession store, Authentication, and Authorization work?

Leave a Comment

I have been struggling with these elements for about 2 months.

The first problem arise when my MVC4 application was recycled. The current logged-in user suddenly cannot access any controller actions which are marked [Authorize]. Also any successful access to controller action which requires database connection produces this error:

Cannot open user default database. Login failed. Login failed for user 'IIS APPPOOL\DefaultAppPool'.

This is weird because if I clear my authentication cookies, it works fine. So there is problem with the ASPXAUTH and .ASPNET_SessionId cookies.

Later I figure out that those error are caused by session invalidation after server restart or recycle. My session setting was in InProc mode. This means the session is lost every time the server is restarted or recycled.

Then I change my session config into Custom Session SQLStore which described in

https://msdn.microsoft.com/en-us/library/ms178588.aspx

and

https://msdn.microsoft.com/en-us/library/ms178589.aspx

The purpose is to store the session data in SQLServer, but the problem seems to not go away. After the server is restarted or recycled, the current logged-in user still having the problem accessing the controller action.

My thought is that the SimpleMembership is not storing the login session in the database. This is how I do login:

WebSecurity.Login(userName, model.Password, persistCookie: true) 

If I am correct, the system will try to match authentication cookies with login session data and determine if the authentication is still valid. This is why my user is keep having the problem because the matching between session and cookies produce some weird things.

I did a lot of research for the past 2 months, I found many similar problem with mine, but I did not find a proper solution.

The temporary solution that I am using is to logged-out the user if the server is getting recycled or restarted. This is not a good solution because if the user is in the middle of important transaction or submission, the data can be lost, and the user is redirected to login page again.


Update

I have my machine key set:

<machineKey validationKey="685DD0E54A38F97FACF4CA27F54D3DA491AB40FE6941110A5A2BA2BC7DDE7411965D45A1E571B7B9283A0D0B382D35A0840B46EDBCE8E05DCE74DE5A37D7A5B3"   decryptionKey="15653D093ED55032EA6EDDBFD63E4AAA479E79038C0F800561DD2CC4597FBC9E"   validation="SHA1" decryption="AES" /> 

I try to debug my custom sql session store, I found out that there is no authentication session is stored in the database. I can only find "__ControllerTempData" retrieved from my sql session, and nothing else.

Please correct me if I am wrong, the way the website reuse the authentication cookies and validates it is by comparing authentication cookie and the authentication session, am I right?

Apparently SimpleMembership Login() does not storing the authentication session into the sql state server.

Then which session key is used for the comparing?

2 Answers

Answers 1

Make sure you've added a machineKey setting to your web.config, otherwise your site uses an auto-generated machine key. If the machine key changes, anything encrypted with the previous key can't be decrypted, which will cause (in part) the error you're seeing.

I posted an answer to a different question that covers adding a machineKey to your web.config, and how to generate the keys yourself, or you can use code from this app I made.

The gist is thus:

1) Add a machine key, like so (filling in the appropriate values)"

<machinekey compatibilitymode="Framework45"             validation="HMACSHA256"             validationkey="YOURVALIDATIONKEYHERE"             decryption="AES"             decryptionkey="YOURDECRYPTIONKEYHERE" /> 

2) Restart the app pool. You'll have one more round of users potentially having issues accessing the site (unless you also change the cookie name), but clearing their cookies will solve that problem.

Answers 2

This is so silly for me. I did not put:

if (!WebSecurity.Initialized)     WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: false); 

in my application intialization (global.asax or any initialization code called from global.asax).

I only call WebSecurity.InitializeDatabaseConnection() when the code need it and somehow the web misses WebSecurity.InitializeDatabaseConnection() when I made request while the server restarted.

There is no connection between session and auth cookie which perform some validation. There is no validation between them. The login auth is purely hold by cookies.

I still need custom sql store session tho. Because TempData becomes persistence. This will not causing form submission to fail while the server is restarted.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment