Here is the first bit of my patch to enable web2py to handle a cookieless
login and session reconnect:
1. in main.py around line 401
static_file = False
try:
try:
try:
change to
static_file = False
isSessionRecordCreated = False # dlypka mod
try:
try:
try:
2. In main.py starting around line 526
# ##################################################
# try load session or create new session file
# ##################################################
if not env.web2py_disable_session:
session.connect(request, response)
change to
# ##################################################
# try load session or create new session file
# ##################################################
session.connect(request, response, db) # dlypka mod -
added ,db
newsessionid = 0 # dlypka mod
if 'sessioncookieval_fromweb2py' in request.post_vars: #
dlypka mod
newsessionid = session._try_store_in_db(request,
response) # dlypka mod
if newsessionid > 0: # dlypka mod
isSessionRecordCreated = True; # dlypka mod
3. then in main.py around line 551:
# ##################################################
# on success, try store session in database
# ##################################################
session._try_store_in_db(request, response)
change to
# ##################################################
# on success, try store session in database
# ##################################################
if isSessionRecordCreated == False: # dlypka mod
session._try_store_in_db(request, response)
4. In globals.py around line 348
"""
separate can be separate=lambda(session_name): session_name[-2:]
and it is used to determine a session prefix.
separate can be True and it is set to session_name[-2:]
"""
change to
"""
separate can be separate=lambda(session_name): session_name[-2:]
and it is used to determine a session prefix.
separate can be True and it is set to session_name[-2:]
"""
if "session_id_name" in response.keys(): # dlypka mod
return # dlypka mod - avoids unnecessary session.connect()
coming from db.py
5. In globals.py around line 624
try:
# Get session data out of the database
(record_id, unique_key) = response.session_id.split(':')
if record_id == '0':
raise Exception('record_id == 0')
# Select from database
if not session_cookie_data:
rows = db(table.id == record_id).select()
# Make sure the session data exists in the database
if len(rows) == 0 or rows[0].unique_key != unique_key:
raise Exception('No record')
# rows[0].update_record(locked=True)
# Unpickle the data
session_data = cPickle.loads(rows[0].session_data)
self.update(session_data)
Change to
try:
# Get session data out of the database
if 'sessioncookieval_fromweb2py' in request.post_vars: #
dlypka mod for cookieless client
key = request.post_vars['sessioncookieval_fromweb2py']
# dlypka e.g. '72:d602d501-877d-42aa-9b52-0e58a91b8336'
else:
key = response.session_id
(record_id, unique_key) = key.split(':')
record_id = int(record_idstr) # dlypka patch to use int
instead of string for the id
if record_id == 0: # dlypka patch to use int instead of
string for the id
raise Exception, 'record_id == 0'
# Select from database
if not session_cookie_data:
rows = db(table.id == record_id).select()
# Make sure the session data exists in the database
if len(rows) == 0 or rows[0].unique_key != unique_key:
raise Exception('No record')
# rows[0].update_record(locked=True)
# Unpickle the data
session_data = cPickle.loads(rows[0].session_data)
self.update(session_data)
6. In globals.py around line 713:
def _try_store_in_db(self, request, response):
# don't save if file-based sessions,
# no session id, or session being forgotten
# or no changes to session
if response.session_storage_type != 'db' or not response.session_id
\
or self._forget or self._unchanged():
return False
table = response.session_db_table
record_id = response.session_db_record_id
unique_key = response.session_db_unique_key
dd = dict(locked=False,
client_ip=request.client.replace(':', '.'),
modified_datetime=request.now,
session_data=cPickle.dumps(dict(self)),
unique_key=unique_key)
if record_id:
table._db(table.id == record_id).update(**dd)
else:
record_id = table.insert(**dd)
cookies, session_id_name = response.cookies,
response.session_id_name
cookies[session_id_name] = '%s:%s' % (record_id, unique_key)
cookies[session_id_name]['path'] = '/'
return True
change to
def _try_store_in_db(self, request, response):
# don't save if file-based sessions,
# no session id, or session being forgotten
# or no changes to session
if response.session_storage_type != 'db' or not response.session_id
\
or self._forget or self._unchanged():
return 0
table = response.session_db_table
record_id = response.session_db_record_id
unique_key = response.session_db_unique_key
dd = dict(locked=False,
client_ip=request.client.replace(':', '.'),
modified_datetime=request.now,
session_data=cPickle.dumps(dict(self)),
unique_key=unique_key)
if record_id:
table._db(table.id == record_id).update(**dd)
else:
record_id = table.insert(**dd)
response.session_record_id = record_id # dlypka mod - useful to
pass back to a client which does not support cookies, such as PhoneGap
cookies, session_id_name = response.cookies,
response.session_id_name
cookies[session_id_name] = '%s:%s' % (record_id, unique_key)
cookies[session_id_name]['path'] = '/'
return record_id
# ======== End of web2py changes by Dave Lypka ===============
In followup posting I will show how to write the controller to use this new
functionality and lastly I will show
how to write the client app.
In my controller I created
def isloggedin_mobile()
and also
def login_mobile():
I will give the code in a followup posting later this week.
- Dave Lypka.
On Friday, November 16, 2012 11:17:53 PM UTC-6, dlypka wrote:
>
> I intend to create some sample code fragments.
> I will try to post something by Monday.
>
> On Thursday, November 15, 2012 9:16:09 PM UTC-6, Jim S wrote:
>>
>> I would be interested in learning more. do you have any samples you could
>> share?
>> On Nov 15, 2012 8:52 PM, "dlypka" <[email protected]> wrote:
>>
>>> I recently devised some changes to globals.py and main.py to allow a
>>> non-cookies client to log into web2py and keep the same
>>> session record between requests, just as a browser does. In my case the
>>> client is a PhoneGap app and I hit web2py through
>>> HTTP. I store the web2py session record id on the client in HTML 5 local
>>> storage, so that the client can sent it along with
>>> each request to tell web2py what session to reconnect to. A similar
>>> approach would probably work from a Windows App.
>>>
>>> On Thursday, November 15, 2012 4:34:22 PM UTC-6, Jim S wrote:
>>>>
>>>> My main concern is that with this being a desktop app that I don't want
>>>> to have to keep the latest versions of those files on the client machines.
>>>>
>>>> I switched my desktop authorization to read the Windows username and
>>>> then match it to a username in the auth_user table and rely on the Windows
>>>> authentication to ensure that user is logged in properly. I validate that
>>>> they are on the proper domain and they are logged in with an id in the
>>>> table.
>>>>
>>>> Now I don't need to worry about keep those files current on multiple
>>>> clients.
>>>>
>>>> -Jim
>>>>
>>>> On Thursday, November 15, 2012 2:01:12 PM UTC-6, Niphlod wrote:
>>>>>
>>>>> ehm.... validators.py (if not all, just crypt and lazycrypt, plus
>>>>> Validator original class), utils.py and pbkdf2 is all you need.
>>>>>
>>>>> On Thursday, November 15, 2012 6:32:03 PM UTC+1, Jim S wrote:
>>>>>>
>>>>>> Sounds like there is no easy way to do it. I looked through that
>>>>>> code and it seems pretty involved. I was hoping to do this without
>>>>>> needing
>>>>>> the web2py libs and such.
>>>>>>
>>>>>> -Jim
>>>>>>
>>>>>> On Thursday, November 15, 2012 11:14:09 AM UTC-6, Niphlod wrote:
>>>>>>>
>>>>>>> https://github.com/web2py/**web2py/blob/master/gluon/**
>>>>>>> tools.py#L1776<https://github.com/web2py/web2py/blob/master/gluon/tools.py#L1776>
>>>>>>> that basically calls the validators attached by default to a
>>>>>>> password field
>>>>>>> https://github.com/web2py/**web2py/blob/master/gluon/**
>>>>>>> tools.py#L1479<https://github.com/web2py/web2py/blob/master/gluon/tools.py#L1479>
>>>>>>> i.e. you just have to import the validator CRYPT and check with that
>>>>>>> passing the correct parameters
>>>>>>> https://github.com/web2py/**web2py/blob/master/gluon/**
>>>>>>> validators.py#L2659<https://github.com/web2py/web2py/blob/master/gluon/validators.py#L2659>
>>>>>>>
>>>>>>> PS: CRYPT was easier to follow before the introduction of the pdfbk2
>>>>>>> algo, but it's quite straightforward if you are willing to cut off
>>>>>>> backward-compatibility
>>>>>>> (that required lazycrypt https://github.com/web2py/**
>>>>>>> web2py/blob/master/gluon/**validators.py#L2581<https://github.com/web2py/web2py/blob/master/gluon/validators.py#L2581>
>>>>>>> )
>>>>>>>
>>>>>>> --
>>>
>>>
>>>
>>>
>>
--