Shiro resets the session after 2 min - session-timeout

I am using Apache Shiro in my webapp.
I store some parameters in the session notably the primary key of an object stored in the database.
When the user logs in, I load the object from the database and save the primary key in the session. Then within the app the user can edit the object's data and either hit a cancel or a save button.
Both buttons triggers a RPC that gets the updated data to the server. The object is then updated in the database using the primary key stored in the session.
If the user remains active in the app (making some RPCs) everything works fine. But if he stays inactive for 3 min and subsequently makes a RPC then Shiro's securityUtils.getSubject().getSession() returns null.
The session timeout is set to 1,200,000 ms (20 min) so I don't think this is the issue.
When I go through the sessions stored in the cache of my session manager I can see the user's session org.apache.shiro.session.mgt.SimpleSession,id=6de78f10-b58e-496c-b40a-e2a9a4ad069c but when I try to get the session ID from the cookie and to call SecurityUtils.getSecurityManager().getSession(key) to get the session (where key is a SessionKey implementation): I get an exception.
When I try building a new subject from the session ID I lose all the attributes saved in the session.
I am happy to post some code to help resolve the issue but I tried so many workarounds that I don't know where to start... So please let me know what you need.
Alternatively if someone knows a better documented framework than Shiro I am all ears (Shiro's lack of documentation makes it really too time consuming)

The issue was related to the session config in the ini file. As usual with shiro the order mattered and some of my lines were out of place.
Below is the config that worked for me:
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
#sessionDAO.activeSessionsCacheName = dropship-activeSessionCache
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
sessionManager.sessionDAO = $sessionDAO
# cookie for single sign on
cookie = org.apache.shiro.web.servlet.SimpleCookie
cookie.name = www.foo.com.session
cookie.path = /
sessionManager.sessionIdCookie = $cookie
# 1,800,000 milliseconds = 30 mins
sessionManager.globalSessionTimeout = 1800000
sessionValidationScheduler =
org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler
sessionValidationScheduler.interval = 1800000
sessionManager.sessionValidationScheduler = $sessionValidationScheduler
securityManager.sessionManager = $sessionManager
cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
securityManager.cacheManager = $cacheManager

It sounds as if you have sorted out your problem already. As you discovered, the main thing to keep in mind with the Shiro INI file is that order matters; the file is parsed in order, which can actually be useful for constructing objects used in the configuration.
Since you mentioned Shiro's lack of documentation, I wanted to go ahead and point out two tutorials that I found helpful when starting:
http://www.javacodegeeks.com/2012/05/apache-shiro-part-1-basics.html
and
http://www.ibm.com/developerworks/web/library/wa-apacheshiro/.
There are quite a few other blog posts that provide good information to supplement the official documentation if you look around.
Good luck!

Related

How can I update expiration of a document in Couchbase using Python 3?

We have a lot of docs in Couchbase with expiration = 0, which means that documents stay in Couchbase forever. I am aware that INSERT/UPDATE/DELETE isn't supported by N1QL.
We have 500,000,000 such docs and I would like to do this in parallel using chunks/bulks. How can I update the expiration field using Python 3?
I am trying this:
bucket.touch_multi(('000c4894abc23031eed1e8dda9e3b120', '000f311ea801638b5aba8c8405faea47'), ttl=10)
However I am getting an error like:
_NotFoundError_0xD (generated, catch NotFoundError): <Key=u'000c4894abc23031eed1e8dda9e3b120'
I just tried this:
from couchbase.cluster import Cluster
from couchbase.cluster import PasswordAuthenticator
cluster = Cluster('couchbase://localhost')
authenticator = PasswordAuthenticator('Administrator', 'password')
cluster.authenticate(authenticator)
cb = cluster.open_bucket('default')
keys = []
for i in range(10):
keys.append("key_{}".format(i))
for key in keys:
cb.upsert(key, {"some":"thing"})
print(cb.touch_multi(keys, ttl=5))
and I get no errors, just a dictionary of keys and OperationResults. And they do in fact expire soon thereafter. I'd guess some of your keys are not there.
However maybe you'd really rather set a bucket expiry? That will make all the documents expire in that time, regardless of what the expiry on the individual documents are. In addition to the above answer that mentions that, check out this for more details.
You can use Couchbase Python (Any) SDK Bucket.touch() method Described here https://docs.couchbase.com/python-sdk/current/document-operations.html#modifying-expiraton
If you don't know the document keys you can use N1QL Covered index get the document keys asynchronously inside your python SDK and use the above bucket touch API set expiration from your python SDK.
CREATE INDEX ix1 ON bucket(META().id) WHERE META().expiration = 0;
SELECT RAW META().id
FROM bucket WHERE META().expiration = 0 AND META().id LIKE "a%";
You can issue different SELECT's for different ranges and do in parallel.
Update Operation, You need to write one. As you get each key do (instead of update) bucket.touch(), which only updates document expiration without modifying the actual document. That saves get/put of whole document (https://docs.couchbase.com/python-sdk/current/core-operations.html#setting-document-expiration).

Destroy a session in Load Impact

I have created a user scenario in Load Impact to simulate a couple of hundred users in our web store.
The problem is that I can't seem to simulate the users in our Azure Queue.
The queue is only increasing with +1 users and not the hundreds of users as I want :)
I have created a random correlation id, but it seems like the session is still there.
Is there a way to destroy the session so when the script is looping a new session is created?
I found a LUA reference that says destroy:session but it wont work for me.
function rnd()
return math.random(0000, 9999)
end
{"POST", "http://STORE.////",
headers={["Content-Type"]="application/json;charset=UTF-8"},
data="{\"ChoosenPhoneModelId\":0,\"PricePlanId\":\"phone\",\"CorrelationId\":\"e97bdaf6-ed61-4fb3-".. rnd().."-d3bb09789feb\",\"ChoosenPhoneColor\":{\"Color\":1,\"Code\":\"#d0d0d4\",\"Name\":\"Silver\",\"DeliveryTime\":\"1-2 veckor\",\"$$hashKey\":\"005\"},\"ChoosenAmortization\":{\"AmortizationLength\":24,\"Price\":312,\"$$hashKey\":\"00H\"},\"ChoosenPriceplan\":{\"IsPostpaid\":true,\"IsStudent\":false,\"IsSenior\":false,\"Title\":\"Fast \",\"Description\":\"Hello.\",\"MonthlyAmount\":149,\"AvailiableDataPackages\":null,\"SubscriptionBinding\":1,\"$$hashKey\":\"00M\"},\"ChoosenDataPackage\":{\"Description\":\"20
GB\",\"PricePerMountInKr\":149,\"DataAmountInGb\":20,\"$$hashKey\":\"00U\"}}",
auto_decompress=true}
})
Any tips on how to.
Thanks in advance.
The correlation id isn't a random number. It's set by your server in a cookie. Get and use like this:
local response = http.request_batch({
{"GET", "http://store.///step1", auto_decompress=true},
})
-- extract correlation Id
local strCorrelationId = response[1].cookies['corrIdCookie']
{"POST", "http://STORE.////",
headers={["Content-Type"]="application/json;charset=UTF-8"},
data="{\"ChoosenPhoneModelId\":0,\"PricePlanId\":\"phone\",\"CorrelationId\":\"".. strCorrelationId .. "",\"ChoosenPhoneColor\":{\"Color\":1,\"Code\":\"#d0d0d4\",\"Name\":\"Silver\",\"DeliveryTime\":\"1-2 veckor\",\"$$hashKey\":\"005\"},\"ChoosenAmortization\":{\"AmortizationLength\":24,\"Price\":312,\"$$hashKey\":\"00H\"},\"ChoosenPriceplan\":{\"IsPostpaid\":true,\"IsStudent\":false,\"IsSenior\":false,\"Title\":\"Fast \",\"Description\":\"Hello.\",\"MonthlyAmount\":149,\"AvailiableDataPackages\":null,\"SubscriptionBinding\":1,\"$$hashKey\":\"00M\"},\"ChoosenDataPackage\":{\"Description\":\"20
GB\",\"PricePerMountInKr\":149,\"DataAmountInGb\":20,\"$$hashKey\":\"00U\"}}",
auto_decompress=true}
})
That is what makes your user unique. If you set CorrelationId to just any random number your server will simply not accept the session in your queue.
Once it's unique and correct your server will accept the POST properly.

Sencha Touch: Ext.getStore and Ext.getStore.load

What is the difference between these Sencha Touch API functions.
Ext.getStore('myStore') and Ext.getStore('myStore').load()
I found at many places including sencha docs but could not find any appropriate answer.
Let's take a look at this:
var myStore = Ext.getStore( 'myStore' );
myStore.load();
Ext.getStore( id ) will search the StoreManager for a store with the provided id. If it finds one it will return it otherwise it will return null.
If you have a store object you can load it via store.load(); That's a function of the store.
Only getting the store via getStore does not mean that the data is up to date. To assure it you have to load the store.
Update:
Let's assume you have a localstore. You have already stored some data in it. Now the user closes the app and restarts it.
When your store is not set to autoLoad: true sencha will create the store object for you which you can access by var store = Ext.getStore( 'myLocalStore' ); This store object will NOT contain any data from the underlying localstorage. You have to load the store manually by store.load();. Now you can add some more data and sync it, so the underlying localstorage will get the new data.

Kohana sessions and database

I have hard time with kohana sessions, i would like to store my sessions data in database i've already created default sessions table, and i have this config file in
\application\config\session.php
And here is config content: http://pastebin.com/MqqQpH5W
Also my login works just fine, i've tried var_dump(Auth::instance()) and i see some stuff like { ["_session":protected]=> object(Session_Native)#20 so i guess my session does get started, but i'm quite lost on how do i set my session id to the database or some other stuff?
I guess i could just make a normal query for that, but i think there has to be better way to do it.
And btw my main goal is to make list of online users, and i see that i have in table row with name last_active, so my guess is that something should update that table automaticaly, right?
EDIT So after some googling and search in various files i found out that it loads native session type from config file in application/auth, so i've tried to change it to database and now it keeps putting session data in my database every time i refresh page, and login doesn't work anymore, any sugguestions?
In Kohana 3.2 you do it like this:
Put this in your bootstrap.php file:
Session::$default = 'database';
And also make sure your cookie configuration is correct. Put this in your bootstrap.php file also
Kohana_Cookie::$salt = md5('secret');
Kohana_Cookie::$expiration = 1209600; // 14 days
Kohana_Cookie::$domain = '.yourdomain.com';
Where .yourdomain.com will be your host name, make sure you put a dot (.) before it so it will include sub-domains too.

Cryptographic security of Captcha hash cookie

My company's CRM system utilizes a captcha system at each login and in order to utilize certain administrative functions. The original implementation stored the current captcha value for in a server-side session variable.
We're now required to redevelop this to store all necessary captcha verification information in a hashed client-side cookie. This is due to a parent IT policy which is intended to reduce overhead by disallowing use of sessions for users who are not already authenticated to the application. Thus, the authentication process itself is disallowed from using server-side storage or sessions.
The design was a bit of a group effort, and I have my doubts as to its overall efficacy. My question is, can anyone see any obvious security issues with the implementation shown below, and is it overkill or insufficient in any way?
EDIT: Further discussion has led to an updated implementation, so I've replaced the original code with the new version and edited the description to talk to this revision.
(The code below is a kind of pseudo-code; the original uses some idiosyncratic legacy libraries and structure which make it difficult to read. Hopefully this style is easy enough to understand.)
// Generate a "session" cookie unique to a particular machine and timeframe
String generateSessionHash(timestamp) {
return sha256( ""
+ (int)(timestamp / CAPTCHA_VALIDITY_SECONDS)
+ "|" + request.getRemoteAddr()
+ "|" + request.getUserAgent()
+ "|" + BASE64_8192BIT_SECRET_A
);
}
// Generate a hash of the captcha, salted with secret key and session id
String generateCaptchaHash(captchaValue, session_hash) {
return sha256( ""
+ captchaValue
+ "|" + BASE64_8192BIT_SECRET_B
+ "|" + session_hash
);
}
// Set cookie with hash matching the provided captcha image
void setCaptchaCookie(CaptchaGenerator captcha) {
String session_hash = generateSessionHash(time());
String captcha_hash = generateCaptchaHash(captcha.getValue(), session_hash);
response.setCookie(CAPTCHA_COOKIE, captcha_hash + session_hash);
}
// Return true if user's input matches the cookie captcha hash
boolean isCaptchaValid(userInputValue) {
String cookie = request.getCookie(CAPTCHA_COOKIE);
String cookie_captcha_hash = substring(cookie, 0, 64);
String cookie_session_hash = substring(cookie, 64, 64);
String session_hash = generateSessionHash(time());
if (!session_hash.equals(cookie_session_hash)) {
session_hash = generateSessionHash(time() - CAPTCHA_VALIDITY_SECONDS);
}
String captcha_hash = generateCaptchaHash(userInputValue, session_hash);
return captcha_hash.equals(cookie_captcha_hash);
}
Concept:
The "session_hash" is intended to prevent the same cookie from being used on multiple machines, and enforces a time period after which it becomes invalid.
Both the "session_hash" and "captcha_hash" have their own secret salt keys.
These BASE64_8192BIT_SECRET_A and _B salt keys are portions of an RSA private key stored on the server.
The "captcha_hash" is salted with both the secret and the "session_hash".
Delimiters are added where client-provided data is used, to avoid splicing attacks.
The "captcha_hash" and "session_hash" are both stored in the client-side cookie.
EDIT: re:Kobi Thanks for the feedback!
(I would reply in comments, but it doesn't seem to accept the formatting that works in questions?)
Each time they access the login page, the captcha is replaced; This does however assume that they don't simply resubmit without reloading the login form page. The session-based implementation uses expiration times to avoid this problem. We could also add a nonce to the login page, but we would need server-side session storage for that as well.
Per Kobi's suggestion, an expiration timeframe is now included in the hashed data, but consensus is to add it to the session_hash instead, since it's intuitive for a session to have a timeout.
This idea of hashing some data and including another hash in that data seems suspect to me. Is there really any benefit, or are we better off with a single hash containing all of the relevant data (time, IP, User-agent, Captcha value, and secret key). In this implementation we are basically telling the user part of the hashed plaintext.
Questions:
Are there any obvious deficiencies?
Are there any subtle deficiencies?
Is there a more robust approach?
Is salting the hash with another hash helping anything?
Is there a simpler and equally robust approach?
New question:
I personally think that we're better off leaving it as a server-side session; can anybody point me to any papers or articles proving or disproving the inherent risk of sending all verification data to the client side only?
Assuming no other security than stated here:
It seems an attacker can solve the captcha once, and save the cookie.
She then has her constant session_hash and captcha_hash. Nothing prevents her from submitting the same cookie with the same hashed data - possibly breaking your system.
This can be avoided by using time as part of captcha_hash (you'll need to round it to an even time, possibly a few minutes - and checking for two options - the current time and the previous)
To calrifiy, you said:
The "session_hash" is intended to prevent the same cookie from being used on multiple machines.
Is that true?
On isCaptchaValid you're doing String session_hash = substring(cookie, 64, 64); - that is: you're relying on data in the cookie. How can you tell it wasn't copied from another computer? - you're not hashing the client data again to confirm it (in fact, you have a random number there, so it may not be possible). How can you tell it's new request, and hadn't been used?
I realize the captcha is replaced with each login, but how can you know that when a request was made? You aren't checking the new captcha on isCaptchaValid - your code will still validate the request, even if it doesn't match the displayed captcha.
Consider the following scenario (can be automated):
Eve open the login page.
Gets a new cookie and a new captcha.
Replaces it with her old cookie, with hashed data of her old cptcha.
Submits the old cookie, and userInputValue with the old captcha word.
With this input, isCaptchaValid validates the request - captcha_hash, session_hash, userInputValue and BASE64_8192BIT_SECRET are all the same as they were on the first request.
by the way, in most systems you'll need a nonce anyway, to avoid XSS, and having one also solves your problem.

Resources