cookies-based sessions

Related: https://pagure.io/koji/issue/3393
This commit is contained in:
Tomas Kopecek 2022-06-27 12:29:25 +02:00
parent 08a9fb8879
commit 850a161e2b
3 changed files with 48 additions and 21 deletions

View file

@ -19,6 +19,7 @@
# Mike McLean <mikem@redhat.com> # Mike McLean <mikem@redhat.com>
import datetime import datetime
import http.cookies
import inspect import inspect
import logging import logging
import os import os
@ -811,6 +812,19 @@ def application(environ, start_response):
('Content-Length', str(len(response))), ('Content-Length', str(len(response))),
('Content-Type', "text/xml"), ('Content-Type', "text/xml"),
] ]
cookies = http.cookies.SimpleCookie(environ.get('HTTP_SET_COOKIE'))
if hasattr(context, 'session') and context.session.logged_in:
cookies['session-id'] = context.session.id
cookies['session-key'] = context.session.key
cookies['callnum'] = context.session.callnum
cookies['logged_in'] = "1"
else:
# good for not mistaking for the older hub with small overhead
cookies['logged_in'] = "0"
for c in cookies.values():
c.path = '/'
c.secure = True
headers.append(('Set-Cookie', c.OutputString()))
start_response('200 OK', headers) start_response('200 OK', headers)
if h.traceback: if h.traceback:
# rollback # rollback

View file

@ -57,6 +57,7 @@ except ImportError: # pragma: no cover
from fnmatch import fnmatch from fnmatch import fnmatch
import dateutil.parser import dateutil.parser
import http.cookies
import requests import requests
import six import six
import six.moves.configparser import six.moves.configparser
@ -2701,10 +2702,11 @@ class ClientSession(object):
return self._prepUpload(*args, **kwargs) return self._prepUpload(*args, **kwargs)
args = encode_args(*args, **kwargs) args = encode_args(*args, **kwargs)
if self.logged_in: if self.logged_in:
sinfo = self.sinfo.copy() for c in self.rsession.cookies:
sinfo['callnum'] = self.callnum if c.name == 'callnum':
c.value = str(self.callnum)
self.callnum += 1 self.callnum += 1
handler = "%s?%s" % (self.baseurl, six.moves.urllib.parse.urlencode(sinfo)) handler = self.baseurl
elif name == 'sslLogin': elif name == 'sslLogin':
handler = self.baseurl + '/ssllogin' handler = self.baseurl + '/ssllogin'
else: else:
@ -2799,6 +2801,13 @@ class ClientSession(object):
warnings.simplefilter("ignore") warnings.simplefilter("ignore")
r = self.rsession.post(handler, **callopts) r = self.rsession.post(handler, **callopts)
r.raise_for_status() r.raise_for_status()
if self.logged_in and len(r.cookies.items()) == 0:
# we have session, sent the cookies, but server is old
# and didn't sent them back, use old url-encoded style
sinfo = self.sinfo.copy()
handler = "%s?%s" % (handler, six.moves.urllib.parse.urlencode(sinfo))
r = self.rsession.post(handler, **callopts)
r.raise_for_status()
try: try:
ret = self._read_xmlrpc_response(r) ret = self._read_xmlrpc_response(r)
finally: finally:

View file

@ -29,7 +29,6 @@ import string
import six import six
from six.moves import range, urllib from six.moves import range, urllib
import koji import koji
from .context import context from .context import context
from .util import to_list from .util import to_list
@ -79,24 +78,23 @@ class Session(object):
self._perms = None self._perms = None
self._groups = None self._groups = None
self._host_id = '' self._host_id = ''
# get session data from request environ = getattr(context, 'environ', {})
if args is None: # prefer new cookie-based sessions
environ = getattr(context, 'environ', {}) if 'HTTP_COOKIE' in environ:
args = environ.get('QUERY_STRING', '') cookies = http.cookies.SimpleCookie(environ['HTTP_COOKIE'])
if not args: try:
self.message = 'no session args' id = int(cookies['session-id'].value)
return key = str(cookies['session-key'].value)
args = urllib.parse.parse_qs(args, strict_parsing=True) except KeyError as field:
raise koji.AuthError('%s not specified in session args' % field)
try:
callnum = int(cookies['callnum'].value)
except KeyError:
callnum = None
else:
self.message = 'no session cookies'
return
hostip = self.get_remote_ip(override=hostip) hostip = self.get_remote_ip(override=hostip)
try:
id = int(args['session-id'][0])
key = args['session-key'][0]
except KeyError as field:
raise koji.AuthError('%s not specified in session args' % field)
try:
callnum = args['callnum'][0]
except Exception:
callnum = None
# lookup the session # lookup the session
# sort for stability (unittests) # sort for stability (unittests)
@ -500,6 +498,12 @@ class Session(object):
insert.execute() insert.execute()
context.cnx.commit() context.cnx.commit()
# update it here, so it can be propagated to the cookies in kojixmlrpc.py
context.session.id = session_id
context.session.key = key
context.session.logged_in = True
context.session.callnum = 0
# return session info # return session info
return {'session-id': session_id, 'session-key': key} return {'session-id': session_id, 'session-key': key}