forked from shaba/openuds
Ticket system seems to work
This commit is contained in:
parent
dd5b35b354
commit
c2243b8f48
@ -37,7 +37,7 @@ from uds.REST import RequestError
|
||||
from uds.models import Authenticator
|
||||
from uds.models import DeployedService
|
||||
from uds.models import Transport
|
||||
from django.contrib.sessions.backends.db import SessionStore
|
||||
from uds.core.util.Ticket import Ticket
|
||||
|
||||
|
||||
import datetime
|
||||
@ -134,7 +134,7 @@ class Tickets(Handler):
|
||||
transport = None
|
||||
|
||||
if servicePool is not None:
|
||||
servicePool = DeployedService.objects.get(uuid=servicePool.upper()).uuid
|
||||
servicePool = DeployedService.objects.get(uuid=servicePool.upper())
|
||||
|
||||
transport = self._params.get('transport', None)
|
||||
if transport is not None:
|
||||
@ -149,11 +149,9 @@ class Tickets(Handler):
|
||||
if transport is None:
|
||||
logger.error('Service pool {} does not has transports')
|
||||
raise Exception('Service pool does not has any assigned transports')
|
||||
transport = transport.uuid
|
||||
|
||||
# backUrl = self._params.get('exitUrl', None)
|
||||
# Groups will be checked on user login stage, and invalid groups will be simply ignored
|
||||
# If user is no part of ANY group, access will be denied
|
||||
servicePool = servicePool.uuid
|
||||
transport = transport.uuid
|
||||
|
||||
except Authenticator.DoesNotExist:
|
||||
return Tickets.result(error='Authenticator does not exists')
|
||||
@ -164,15 +162,16 @@ class Tickets(Handler):
|
||||
except Exception as e:
|
||||
return Tickets.result(error=six.text_type(e))
|
||||
|
||||
store = SessionStore()
|
||||
store.set_expiry(time)
|
||||
store['username'] = username
|
||||
store['password'] = password
|
||||
store['realname'] = realname
|
||||
store['groups'] = groups
|
||||
store['auth'] = auth.uuid
|
||||
store['servicePool'] = servicePool
|
||||
store['transport'] = transport
|
||||
store.save()
|
||||
data = {}
|
||||
data['username'] = username
|
||||
data['password'] = password
|
||||
data['realname'] = realname
|
||||
data['groups'] = groups
|
||||
data['auth'] = auth.uuid
|
||||
data['servicePool'] = servicePool
|
||||
data['transport'] = transport
|
||||
|
||||
return Tickets.result(store.session_key)
|
||||
ticket = Ticket()
|
||||
ticket.save(data, time)
|
||||
|
||||
return Tickets.result(ticket.key)
|
||||
|
@ -61,6 +61,9 @@ ROOT_ID = -20091204 # Any negative number will do the trick
|
||||
|
||||
|
||||
def getUDSCookie(request, response=None, force=False):
|
||||
'''
|
||||
Generates a random cookie for uds, used, for example, to encript things
|
||||
'''
|
||||
if 'uds' not in request.COOKIES:
|
||||
import random
|
||||
import string
|
||||
@ -316,12 +319,13 @@ def authLogLogin(request, authenticator, userName, java, os, logStr=''):
|
||||
authLogger.info('|'.join([authenticator.name, userName, javaStr, os['OS'], logStr, request.META.get('HTTP_USER_AGENT', 'Undefined')]))
|
||||
level = (logStr == 'Logged in') and log.INFO or log.ERROR
|
||||
log.doLog(authenticator, level, 'user {0} has {1} from {2} {3} java and os is {4}'.format(userName, logStr,
|
||||
request.ip, java and 'has' or 'has NOT', os['OS']), log.WEB)
|
||||
request.ip, java and 'has' or 'has NOT', os['OS']), log.WEB)
|
||||
|
||||
try:
|
||||
user = authenticator.users.get(name=userName)
|
||||
log.doLog(user, level, '{0} from {1} {2} java and os is {3}'.format(logStr,
|
||||
request.ip, java and 'has' or 'has NOT', os['OS']), log.WEB)
|
||||
log.doLog(user, level,
|
||||
'{0} from {1} {2} java and os is {3}'.format(logStr, request.ip, java and 'has' or 'has NOT', os['OS']), log.WEB
|
||||
)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -62,13 +62,17 @@ class Cache(object):
|
||||
expired = now > c.created + timedelta(seconds=c.validity)
|
||||
if expired:
|
||||
return defValue
|
||||
val = cPickle.loads(c.value.decode(Cache.CODEC).encode('utf-8'))
|
||||
val = cPickle.loads(c.value.decode(Cache.CODEC))
|
||||
return val
|
||||
except dbCache.DoesNotExist: # @UndefinedVariable
|
||||
logger.debug('key not found: {}'.format(skey))
|
||||
return defValue
|
||||
|
||||
def remove(self, skey):
|
||||
'''
|
||||
Removes an stored cached item
|
||||
If cached item does not exists, nothing happens (no exception thrown)
|
||||
'''
|
||||
# logger.debug('Removing key "%s" for uService "%s"' % (skey, self._owner))
|
||||
try:
|
||||
key = self.__getKey(skey)
|
||||
|
76
server/src/uds/core/util/Ticket.py
Normal file
76
server/src/uds/core/util/Ticket.py
Normal file
@ -0,0 +1,76 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from uds.core.util.Cache import Cache
|
||||
from uds.core.managers import cryptoManager
|
||||
|
||||
TICKET_OWNER = 'e6242ba4-62fa-11e4-b7ec-10feed05884b'
|
||||
|
||||
|
||||
class Ticket(object):
|
||||
'''
|
||||
Manages tickets & ticketing save/loading
|
||||
Right now, uses cache as backend
|
||||
'''
|
||||
|
||||
def __init__(self, key=None):
|
||||
self.uuidGenerator = cryptoManager().uuid
|
||||
self.cache = Cache(TICKET_OWNER)
|
||||
self.data = None
|
||||
self.key = key
|
||||
if key is not None:
|
||||
self.load()
|
||||
else:
|
||||
self.key = self.uuidGenerator()
|
||||
|
||||
def save(self, data, validity):
|
||||
'''
|
||||
Stores data inside ticket, and make data persistent (store in db)
|
||||
'''
|
||||
self.data = data
|
||||
self.cache.put(self.key, self.data, validity)
|
||||
return self.key
|
||||
|
||||
def load(self):
|
||||
'''
|
||||
Load data (if still valid) for a ticket
|
||||
'''
|
||||
self.data = self.cache.get(self.key, None)
|
||||
return self.data
|
||||
|
||||
def delete(self):
|
||||
'''
|
||||
Removes a ticket from storage (db)
|
||||
'''
|
||||
self.cache.remove(self.key)
|
@ -71,7 +71,7 @@ urlpatterns = patterns(
|
||||
(r'^authinfo/(?P<authName>.+)', 'web.views.authInfo'),
|
||||
(r'^about', 'web.views.about'),
|
||||
# Ticket authentication
|
||||
(r'^tkauth/(?P<ticketId>.+)/(?P<serviceId>.*)', 'web.views.ticketAuth'),
|
||||
url(r'^tkauth/(?P<ticketId>.+)$', 'web.views.ticketAuth', name='TicketAuth'),
|
||||
|
||||
|
||||
# XMLRPC Processor
|
||||
|
@ -30,7 +30,7 @@
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, HttpResponsePermanentRedirect
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.shortcuts import render_to_response
|
||||
from django.shortcuts import render
|
||||
@ -40,7 +40,6 @@ from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.views.decorators.http import last_modified
|
||||
from django.views.i18n import javascript_catalog
|
||||
from django.contrib.sessions.backends.db import SessionStore
|
||||
from django.utils import timezone
|
||||
|
||||
from uds.core.auths.auth import webLogin, webLogout, webLoginRequired, authenticate, webPassword, authenticateViaCallback, authLogLogin, authLogLogout, getUDSCookie
|
||||
@ -53,6 +52,7 @@ from uds.core.util.Config import GlobalConfig
|
||||
from uds.core.util.Cache import Cache
|
||||
from uds.core.util import OsDetector
|
||||
from uds.core.util import log
|
||||
from uds.core.util.Ticket import Ticket
|
||||
from uds.core.util.State import State
|
||||
from uds.core.ui import theme
|
||||
from uds.core.auths.Exceptions import InvalidUserException
|
||||
@ -465,23 +465,24 @@ def ticketAuth(request, ticketId):
|
||||
'''
|
||||
Used to authenticate an user via a ticket
|
||||
'''
|
||||
session = SessionStore(session_key=ticketId)
|
||||
ticket = Ticket(ticketId)
|
||||
|
||||
try:
|
||||
try:
|
||||
# Extract data from session storage, and remove it if success
|
||||
username = session['username']
|
||||
groups = session['groups']
|
||||
auth = session['auth']
|
||||
realname = session['realname']
|
||||
servicePool = session['servicePool']
|
||||
password = session['password']
|
||||
transport = session['transport']
|
||||
# Extract ticket.data from ticket.data storage, and remove it if success
|
||||
username = ticket.data['username']
|
||||
groups = ticket.data['groups']
|
||||
auth = ticket.data['auth']
|
||||
realname = ticket.data['realname']
|
||||
servicePool = ticket.data['servicePool']
|
||||
password = ticket.data['password']
|
||||
transport = ticket.data['transport']
|
||||
except:
|
||||
logger.error('Ticket stored is not valid')
|
||||
raise InvalidUserException()
|
||||
|
||||
session.delete()
|
||||
# Remove ticket
|
||||
ticket.delete()
|
||||
|
||||
auth = Authenticator.objects.get(uuid=auth)
|
||||
# If user does not exists in DB, create it right now
|
||||
@ -506,26 +507,26 @@ def ticketAuth(request, ticketId):
|
||||
|
||||
# Right now, we assume that user supports java, let's see how this works
|
||||
request.session['java'] = True
|
||||
request['OS'] = OsDetector.getOsFromUA(request.META.get('HTTP_USER_AGENT'))
|
||||
request.session['OS'] = OsDetector.getOsFromUA(request.META.get('HTTP_USER_AGENT'))
|
||||
request.user = usr # Temporaly store this user as "authenticated" user, next requests will be done using session
|
||||
|
||||
# Force cookie generation
|
||||
getUDSCookie(request)
|
||||
webLogin(request, None, usr, password)
|
||||
|
||||
# Check if servicePool is part of the ticket
|
||||
if servicePool is not None:
|
||||
servicePool = DeployedService.objects.get(uuid=servicePool)
|
||||
# Check if servicepool can't be accessed by groups
|
||||
# Check if service pool can't be accessed by groups
|
||||
servicePool.validateUser(usr)
|
||||
transport = Transport.objects.get(uuid=transport)
|
||||
|
||||
response = service(request, servicePool.id, transport.id)
|
||||
response = service(request, 'F' + servicePool.uuid, transport.uuid) # 'A' Indicates 'assigned service'
|
||||
else:
|
||||
response = HttpResponseRedirect(reverse('uds.web.views.index'))
|
||||
response = HttpResponsePermanentRedirect(reverse('uds.web.views.index'))
|
||||
|
||||
# Now ensure cookie is at response
|
||||
# Now ensure uds cookie is at response
|
||||
getUDSCookie(request, response, True)
|
||||
|
||||
webLogin(request, response, usr, password) # Password is passed in by ticket, and probably will be empty
|
||||
return response
|
||||
|
||||
except Authenticator.DoesNotExist:
|
||||
logger.error('Ticket has an non existing authenticator')
|
||||
@ -534,6 +535,7 @@ def ticketAuth(request, ticketId):
|
||||
logger.error('Ticket has an invalid Service Pool')
|
||||
return error(request, InvalidServiceException())
|
||||
except Exception as e:
|
||||
logger.exception('Exception')
|
||||
return errors.exceptionView(request, e)
|
||||
|
||||
return HttpResponse(ticketId, content_type='text/plain')
|
||||
|
Loading…
Reference in New Issue
Block a user