diff --git a/cas_server/admin.py b/cas_server/admin.py index 3ca00d1..bfa5a73 100644 --- a/cas_server/admin.py +++ b/cas_server/admin.py @@ -14,8 +14,12 @@ from .models import ServiceTicket, ProxyTicket, ProxyGrantingTicket, User, Servi from .models import Username, ReplaceAttributName, ReplaceAttributValue, FilterAttributValue from .forms import TicketForm -tickets_readonly_fields=('validate', 'service', 'service_pattern', 'creation', 'renew', 'single_log_out', 'value') -tickets_fields = ('validate', 'service', 'service_pattern', 'creation', 'renew', 'single_log_out') +tickets_readonly_fields = ('validate', 'service', 'service_pattern', + 'creation', 'renew', 'single_log_out', 'value') +tickets_fields = ('validate', 'service', 'service_pattern', + 'creation', 'renew', 'single_log_out') + + class ServiceTicketInline(admin.TabularInline): """`ServiceTicket` in admin interface""" model = ServiceTicket @@ -23,6 +27,8 @@ class ServiceTicketInline(admin.TabularInline): form = TicketForm readonly_fields = tickets_readonly_fields fields = tickets_fields + + class ProxyTicketInline(admin.TabularInline): """`ProxyTicket` in admin interface""" model = ProxyTicket @@ -30,6 +36,8 @@ class ProxyTicketInline(admin.TabularInline): form = TicketForm readonly_fields = tickets_readonly_fields fields = tickets_fields + + class ProxyGrantingInline(admin.TabularInline): """`ProxyGrantingTicket` in admin interface""" model = ProxyGrantingTicket @@ -38,30 +46,39 @@ class ProxyGrantingInline(admin.TabularInline): readonly_fields = tickets_readonly_fields fields = tickets_fields[1:] + class UserAdmin(admin.ModelAdmin): """`User` in admin interface""" inlines = (ServiceTicketInline, ProxyTicketInline, ProxyGrantingInline) - readonly_fields=('username', 'date', "session_key") + readonly_fields = ('username', 'date', "session_key") fields = ('username', 'date', "session_key") list_display = ('username', 'date', "session_key") + class UsernamesInline(admin.TabularInline): """`Username` in admin interface""" model = Username extra = 0 + + class ReplaceAttributNameInline(admin.TabularInline): """`ReplaceAttributName` in admin interface""" model = ReplaceAttributName extra = 0 + + class ReplaceAttributValueInline(admin.TabularInline): """`ReplaceAttributValue` in admin interface""" model = ReplaceAttributValue extra = 0 + + class FilterAttributValueInline(admin.TabularInline): """`FilterAttributValue` in admin interface""" model = FilterAttributValue extra = 0 + class ServicePatternAdmin(admin.ModelAdmin): """`ServicePattern` in admin interface""" inlines = ( @@ -70,7 +87,8 @@ class ServicePatternAdmin(admin.ModelAdmin): ReplaceAttributValueInline, FilterAttributValueInline ) - list_display = ('pos', 'name', 'pattern', 'proxy', 'single_log_out', 'proxy_callback', 'restrict_users') + list_display = ('pos', 'name', 'pattern', 'proxy', + 'single_log_out', 'proxy_callback', 'restrict_users') admin.site.register(User, UserAdmin) diff --git a/cas_server/auth.py b/cas_server/auth.py index cd40001..3d98651 100644 --- a/cas_server/auth.py +++ b/cas_server/auth.py @@ -19,8 +19,10 @@ try: except ImportError: MySQLdb = None + class DummyAuthUser(object): """A Dummy authentication class""" + def __init__(self, username): self.username = username @@ -36,6 +38,7 @@ class DummyAuthUser(object): class TestAuthUser(DummyAuthUser): """A test authentication class with one user test having alose test as password and some attributes""" + def __init__(self, username): super(TestAuthUser, self).__init__(username) @@ -45,20 +48,21 @@ class TestAuthUser(DummyAuthUser): def attributs(self): """return a dict of user attributes""" - return {'nom':'Nymous', 'prenom':'Ano', 'email':'anonymous@example.net'} + return {'nom': 'Nymous', 'prenom': 'Ano', 'email': 'anonymous@example.net'} class MysqlAuthUser(DummyAuthUser): """A mysql auth class: authentication user agains a mysql database""" user = None + def __init__(self, username): mysql_config = { "user": settings.CAS_SQL_USERNAME, "passwd": settings.CAS_SQL_PASSWORD, "db": settings.CAS_SQL_DBNAME, "host": settings.CAS_SQL_HOST, - "charset":settings.CAS_SQL_DBCHARSET, - "cursorclass":MySQLdb.cursors.DictCursor + "charset": settings.CAS_SQL_DBCHARSET, + "cursorclass": MySQLdb.cursors.DictCursor } if not MySQLdb: raise RuntimeError("Please install MySQLdb before using the MysqlAuthUser backend") @@ -92,9 +96,11 @@ class MysqlAuthUser(DummyAuthUser): else: return self.user + class DjangoAuthUser(DummyAuthUser): """A django auth class: authenticate user agains django internal users""" user = None + def __init__(self, username): try: self.user = User.objects.get(username=username) @@ -102,7 +108,6 @@ class DjangoAuthUser(DummyAuthUser): pass super(DjangoAuthUser, self).__init__(username) - def test_password(self, password): """test `password` agains the user""" if not self.user: diff --git a/cas_server/default_settings.py b/cas_server/default_settings.py index a702998..1e052af 100644 --- a/cas_server/default_settings.py +++ b/cas_server/default_settings.py @@ -11,6 +11,7 @@ """Default values for the app's settings""" from django.conf import settings + def setting_default(name, default_value): """if the config `name` is not set, set it the `default_value`""" value = getattr(settings, name, default_value) @@ -60,7 +61,6 @@ setting_default('CAS_SQL_USERNAME', '') setting_default('CAS_SQL_PASSWORD', '') setting_default('CAS_SQL_DBNAME', '') setting_default('CAS_SQL_DBCHARSET', 'utf8') -setting_default('CAS_SQL_USER_QUERY', 'SELECT user AS usersame, pass AS ' \ - 'password, users.* FROM users WHERE user = %s') -setting_default('CAS_SQL_PASSWORD_CHECK', 'crypt') # crypt or plain - +setting_default('CAS_SQL_USER_QUERY', 'SELECT user AS usersame, pass AS ' + 'password, users.* FROM users WHERE user = %s') +setting_default('CAS_SQL_PASSWORD_CHECK', 'crypt') # crypt or plain diff --git a/cas_server/forms.py b/cas_server/forms.py index 29c66cf..d19e7d0 100644 --- a/cas_server/forms.py +++ b/cas_server/forms.py @@ -17,6 +17,7 @@ from django.utils.translation import ugettext_lazy as _ import utils import models + class UserCredential(forms.Form): """Form used on the login page to retrive user credentials""" username = forms.CharField(label=_('login')) diff --git a/cas_server/management/commands/cas_clean_sessions.py b/cas_server/management/commands/cas_clean_sessions.py index 95594be..da60c1a 100644 --- a/cas_server/management/commands/cas_clean_sessions.py +++ b/cas_server/management/commands/cas_clean_sessions.py @@ -1,8 +1,9 @@ -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from django.utils.translation import ugettext_lazy as _ from ... import models + class Command(BaseCommand): args = '' help = _(u"Clean deleted sessions") diff --git a/cas_server/management/commands/cas_clean_tickets.py b/cas_server/management/commands/cas_clean_tickets.py index a5e8908..d18a7d4 100644 --- a/cas_server/management/commands/cas_clean_tickets.py +++ b/cas_server/management/commands/cas_clean_tickets.py @@ -1,8 +1,9 @@ -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from django.utils.translation import ugettext_lazy as _ from ... import models + class Command(BaseCommand): args = '' help = _(u"Clean old trickets") diff --git a/cas_server/models.py b/cas_server/models.py index 4474b7d..b2d9813 100644 --- a/cas_server/models.py +++ b/cas_server/models.py @@ -31,6 +31,7 @@ import utils SessionStore = import_module(settings.SESSION_ENGINE).SessionStore + class User(models.Model): """A user logged into the CAS""" class Meta: @@ -123,24 +124,32 @@ class User(models.Model): """Return the url to which the user must be redirected to after a Service Ticket has been generated""" ticket = self.get_ticket(ServiceTicket, service, service_pattern, renew) - url = utils.update_url(service, {'ticket':ticket.value}) + url = utils.update_url(service, {'ticket': ticket.value}) return url + class ServicePatternException(Exception): pass + + class BadUsername(ServicePatternException): """Exception raised then an non allowed username try to get a ticket for a service""" pass + + class BadFilter(ServicePatternException): """"Exception raised then a user try to get a ticket for a service and do not reach a condition""" pass + class UserFieldNotDefined(ServicePatternException): """Exception raised then a user try to get a ticket for a service using as username an attribut not present on this user""" pass + + class ServicePattern(models.Model): """Allowed services pattern agains services are tested to""" class Meta: @@ -196,11 +205,10 @@ class ServicePattern(models.Model): default="", blank=True, verbose_name=_(u"single log out callback"), - help_text=_(u"URL where the SLO request will be POST. empty = service url\n" \ + help_text=_(u"URL where the SLO request will be POST. empty = service url\n" u"This is usefull for non HTTP proxied services.") ) - def __unicode__(self): return u"%s: %s" % (self.pos, self.pattern) @@ -226,7 +234,6 @@ class ServicePattern(models.Model): raise UserFieldNotDefined() return True - @classmethod def validate(cls, service): """Check if a Service Patern match `service` and @@ -236,6 +243,7 @@ class ServicePattern(models.Model): return service_pattern raise cls.DoesNotExist() + class Username(models.Model): """A list of allowed usernames on a service pattern""" value = models.CharField( @@ -248,6 +256,7 @@ class Username(models.Model): def __unicode__(self): return self.value + class ReplaceAttributName(models.Model): """A list of replacement of attributs name for a service pattern""" class Meta: @@ -261,8 +270,8 @@ class ReplaceAttributName(models.Model): max_length=255, blank=True, verbose_name=_(u"replace"), - help_text=_(u"name under which the attribut will be show" \ - u"to the service. empty = default name of the attribut") + help_text=_(u"name under which the attribut will be show" + u"to the service. empty = default name of the attribut") ) service_pattern = models.ForeignKey(ServicePattern, related_name="attributs") @@ -272,6 +281,7 @@ class ReplaceAttributName(models.Model): else: return u"%s → %s" % (self.name, self.replace) + class FilterAttributValue(models.Model): """A list of filter on attributs for a service pattern""" attribut = models.CharField( @@ -289,6 +299,7 @@ class FilterAttributValue(models.Model): def __unicode__(self): return u"%s %s" % (self.attribut, self.pattern) + class ReplaceAttributValue(models.Model): """Replacement to apply on attributs values for a service pattern""" attribut = models.CharField( @@ -338,10 +349,10 @@ class Ticket(models.Model): # removing old validated ticket and non validated expired tickets cls.objects.filter( ( - Q(single_log_out=False)&Q(validate=True) - )|( - Q(validate=False)&\ - Q(creation__lt=(timezone.now() - timedelta(seconds=cls.VALIDITY))) + Q(single_log_out=False) & Q(validate=True) + ) | ( + Q(validate=False) + & Q(creation__lt=(timezone.now() - timedelta(seconds=cls.VALIDITY))) ) ).delete() @@ -373,18 +384,18 @@ class Ticket(models.Model): %(ticket)s """ % \ - { - 'id' : os.urandom(20).encode("hex"), - 'datetime' : timezone.now().isoformat(), - 'ticket': self.value - } + { + 'id': os.urandom(20).encode("hex"), + 'datetime': timezone.now().isoformat(), + 'ticket': self.value + } if self.service_pattern.single_log_out_callback: url = self.service_pattern.single_log_out_callback else: - url = self.service + url = self.service return session.post( url.encode('utf-8'), - data={'logoutRequest':xml.encode('utf-8')}, + data={'logoutRequest': xml.encode('utf-8')}, ) except Exception as error: if request is not None: @@ -393,33 +404,40 @@ class Ticket(models.Model): request, messages.WARNING, _(u'Error during service logout %(service)s:\n%(error)s') % - {'service': self.service, 'error':error} + {'service': self.service, 'error': error} ) else: sys.stderr.write("%r\n" % error) + class ServiceTicket(Ticket): """A Service Ticket""" PREFIX = settings.CAS_SERVICE_TICKET_PREFIX value = models.CharField(max_length=255, default=utils.gen_st, unique=True) + def __unicode__(self): return u"ServiceTicket-%s" % self.pk + + class ProxyTicket(Ticket): """A Proxy Ticket""" PREFIX = settings.CAS_PROXY_TICKET_PREFIX value = models.CharField(max_length=255, default=utils.gen_pt, unique=True) + def __unicode__(self): return u"ProxyTicket-%s" % self.pk + + class ProxyGrantingTicket(Ticket): """A Proxy Granting Ticket""" PREFIX = settings.CAS_PROXY_GRANTING_TICKET_PREFIX VALIDITY = settings.CAS_PGT_VALIDITY value = models.CharField(max_length=255, default=utils.gen_pgt, unique=True) - def __unicode__(self): return u"ProxyGrantingTicket-%s" % self.pk + class Proxy(models.Model): """A list of proxies on `ProxyTicket`""" class Meta: @@ -429,4 +447,3 @@ class Proxy(models.Model): def __unicode__(self): return self.url - diff --git a/cas_server/tests.py b/cas_server/tests.py deleted file mode 100644 index 8283f8c..0000000 --- a/cas_server/tests.py +++ /dev/null @@ -1,12 +0,0 @@ -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for -# more details. -# -# You should have received a copy of the GNU General Public License version 3 -# along with this program; if not, write to the Free Software Foundation, Inc., 51 -# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# (c) 2015 Valentin Samir -from django.test import TestCase - diff --git a/cas_server/urls.py b/cas_server/urls.py index c792583..90f4c0a 100644 --- a/cas_server/urls.py +++ b/cas_server/urls.py @@ -21,12 +21,27 @@ urlpatterns = patterns( url('^login$', views.LoginView.as_view(), name='login'), url('^logout$', views.LogoutView.as_view(), name='logout'), url('^validate$', views.Validate.as_view(), name='validate'), - url('^serviceValidate$', views.ValidateService.as_view(allow_proxy_ticket=False), name='serviceValidate'), - url('^proxyValidate$', views.ValidateService.as_view(allow_proxy_ticket=True), name='proxyValidate'), + url( + '^serviceValidate$', + views.ValidateService.as_view(allow_proxy_ticket=False), + name='serviceValidate' + ), + url( + '^proxyValidate$', + views.ValidateService.as_view(allow_proxy_ticket=True), + name='proxyValidate' + ), url('^proxy$', views.Proxy.as_view(), name='proxy'), - url('^p3/serviceValidate$', views.ValidateService.as_view(allow_proxy_ticket=False), name='p3_serviceValidate'), - url('^p3/proxyValidate$', views.ValidateService.as_view(allow_proxy_ticket=True), name='p3_proxyValidate'), + url( + '^p3/serviceValidate$', + views.ValidateService.as_view(allow_proxy_ticket=False), + name='p3_serviceValidate' + ), + url( + '^p3/proxyValidate$', + views.ValidateService.as_view(allow_proxy_ticket=True), + name='p3_proxyValidate' + ), url('^samlValidate$', views.SamlValidate.as_view(), name='samlValidate'), url('^auth$', views.Auth.as_view(), name='auth'), ) - diff --git a/cas_server/utils.py b/cas_server/utils.py index 8e76271..0cf8b59 100644 --- a/cas_server/utils.py +++ b/cas_server/utils.py @@ -21,6 +21,7 @@ import urllib import random import string + def import_attr(path): """transform a python module.attr path to the attr""" if not isinstance(path, str): @@ -28,16 +29,18 @@ def import_attr(path): module, attr = path.rsplit('.', 1) return getattr(import_module(module), attr) + def redirect_params(url_name, params=None): """Redirect to `url_name` with `params` as querystring""" url = reverse(url_name) params = urllib.urlencode(params if params else {}) return HttpResponseRedirect(url + "?%s" % params) + def update_url(url, params): """update params in the `url` query string""" if isinstance(url, unicode): - url = url.encode('utf-8') + url = url.encode('utf-8') for key, value in params.items(): if isinstance(key, unicode): del params[key] @@ -51,6 +54,7 @@ def update_url(url, params): url_parts[4] = urllib.urlencode(query) return urlparse.urlunparse(url_parts).decode('utf-8') + def unpack_nested_exception(error): """If exception are stacked, return the first one""" i = 0 @@ -77,22 +81,27 @@ def _gen_ticket(prefix, lg=settings.CAS_TICKET_LEN): ) ) + def gen_lt(): """Generate a Service Ticket""" return _gen_ticket(settings.CAS_LOGIN_TICKET_PREFIX, settings.CAS_LT_LEN) + def gen_st(): """Generate a Service Ticket""" return _gen_ticket(settings.CAS_SERVICE_TICKET_PREFIX, settings.CAS_ST_LEN) + def gen_pt(): """Generate a Proxy Ticket""" return _gen_ticket(settings.CAS_PROXY_TICKET_PREFIX, settings.CAS_PT_LEN) + def gen_pgt(): """Generate a Proxy Granting Ticket""" return _gen_ticket(settings.CAS_PROXY_GRANTING_TICKET_PREFIX, settings.CAS_PGT_LEN) + def gen_pgtiou(): """Generate a Proxy Granting Ticket IOU""" return _gen_ticket(settings.CAS_PROXY_GRANTING_TICKET_IOU_PREFIX, settings.CAS_PGTIOU_LEN) diff --git a/cas_server/views.py b/cas_server/views.py index eb1a65e..ca73e08 100644 --- a/cas_server/views.py +++ b/cas_server/views.py @@ -33,6 +33,7 @@ import models from .models import ServiceTicket, ProxyTicket, ProxyGrantingTicket from .models import ServicePattern + class AttributesMixin(object): """mixin for the attributs methode""" @@ -49,6 +50,7 @@ class AttributesMixin(object): attributes.append((key, value)) return attributes + class LogoutMixin(object): """destroy CAS session utils""" def clean_session_variables(self): @@ -80,6 +82,7 @@ class LogoutMixin(object): finally: self.clean_session_variables() + class LogoutView(View, LogoutMixin): """destroy CAS session (logout) view""" @@ -94,10 +97,10 @@ class LogoutView(View, LogoutMixin): self.logout() # if service is set, redirect to service after logout if self.service: - list(messages.get_messages(request)) # clean messages before leaving the django app + list(messages.get_messages(request)) # clean messages before leaving the django app return HttpResponseRedirect(self.service) elif self.url: - list(messages.get_messages(request)) # clean messages before leaving the django app + list(messages.get_messages(request)) # clean messages before leaving the django app return HttpResponseRedirect(self.url) # else redirect to login page else: @@ -107,6 +110,7 @@ class LogoutView(View, LogoutMixin): else: return render(request, settings.CAS_LOGOUT_TEMPLATE) + class LoginView(View, LogoutMixin): """credential requestor / acceptor""" @@ -188,10 +192,10 @@ class LoginView(View, LogoutMixin): self.request, values, initial={ - 'service':self.service, - 'method':self.method, - 'warn':self.request.session.get("warn"), - 'lt':self.request.session['lt'] + 'service': self.service, + 'method': self.method, + 'warn': self.request.session.get("warn"), + 'lt': self.request.session['lt'] } ) @@ -207,13 +211,13 @@ class LoginView(View, LogoutMixin): messages.add_message( self.request, messages.WARNING, - _(u"Authentication has been required by service %(name)s (%(url)s)") % \ - {'name':service_pattern.name, 'url':self.service} + _(u"Authentication has been required by service %(name)s (%(url)s)") % + {'name': service_pattern.name, 'url': self.service} ) return render( self.request, settings.CAS_WARN_TEMPLATE, - {'service_ticket_url':self.user.get_service_url( + {'service_ticket_url': self.user.get_service_url( self.service, service_pattern, renew=self.renew @@ -221,7 +225,7 @@ class LoginView(View, LogoutMixin): ) else: # redirect, using method ? - list(messages.get_messages(self.request)) # clean messages before leaving django + list(messages.get_messages(self.request)) # clean messages before leaving django return HttpResponseRedirect( self.user.get_service_url(self.service, service_pattern, renew=self.renew) ) @@ -229,7 +233,7 @@ class LoginView(View, LogoutMixin): messages.add_message( self.request, messages.ERROR, - _(u'Service %(url)s non allowed.') % {'url' : self.service} + _(u'Service %(url)s non allowed.') % {'url': self.service} ) except models.BadUsername: messages.add_message( @@ -247,16 +251,16 @@ class LoginView(View, LogoutMixin): messages.add_message( self.request, messages.ERROR, - _(u"The attribut %(field)s is needed to use" \ - " that service") % {'field':service_pattern.user_field} + _(u"The attribut %(field)s is needed to use" + u" that service") % {'field': service_pattern.user_field} ) # if gateway is set and auth failed redirect to the service without authentication if self.gateway: - list(messages.get_messages(self.request)) # clean messages before leaving django + list(messages.get_messages(self.request)) # clean messages before leaving django return HttpResponseRedirect(self.service) - return render(self.request, settings.CAS_LOGGED_TEMPLATE, {'session':self.request.session}) + return render(self.request, settings.CAS_LOGGED_TEMPLATE, {'session': self.request.session}) def authenticated(self): """Processing authenticated users""" @@ -276,7 +280,7 @@ class LoginView(View, LogoutMixin): return render( self.request, settings.CAS_LOGGED_TEMPLATE, - {'session':self.request.session} + {'session': self.request.session} ) def not_authenticated(self): @@ -285,21 +289,22 @@ class LoginView(View, LogoutMixin): try: service_pattern = ServicePattern.validate(self.service) if self.gateway: - list(messages.get_messages(self.request))# clean messages before leaving django + # clean messages before leaving django + list(messages.get_messages(self.request)) return HttpResponseRedirect(self.service) if self.request.session.get("authenticated") and self.renew: messages.add_message( self.request, messages.WARNING, _(u"Authentication renewal required by service %(name)s (%(url)s).") % - {'name':service_pattern.name, 'url':self.service} + {'name': service_pattern.name, 'url': self.service} ) else: messages.add_message( self.request, messages.WARNING, _(u"Authentication required by service %(name)s (%(url)s).") % - {'name':service_pattern.name, 'url':self.service} + {'name': service_pattern.name, 'url': self.service} ) except ServicePattern.DoesNotExist: messages.add_message( @@ -307,7 +312,7 @@ class LoginView(View, LogoutMixin): messages.ERROR, _(u'Service %s non allowed') % self.service ) - return render(self.request, settings.CAS_LOGIN_TEMPLATE, {'form':self.form}) + return render(self.request, settings.CAS_LOGIN_TEMPLATE, {'form': self.form}) def common(self): """Part execute uppon GET and POST request""" @@ -317,6 +322,7 @@ class LoginView(View, LogoutMixin): else: return self.not_authenticated() + class Auth(View): """A simple view to validate username/password/service tuple""" @method_decorator(csrf_exempt) @@ -342,16 +348,16 @@ class Auth(View): request, request.POST, initial={ - 'service':service, - 'method':'POST', - 'warn':False + 'service': service, + 'method': 'POST', + 'warn': False } ) if form.is_valid(): try: user = models.User.objects.get( username=form.cleaned_data['username'], - session_key=self.request.session.session_key + session_key=request.session.session_key ) # is the service allowed service_pattern = ServicePattern.validate(service) @@ -360,11 +366,12 @@ class Auth(View): if not request.session.get("authenticated"): user.delete() return HttpResponse("yes\n", content_type="text/plain") - except (ServicePattern.DoesNotExist, ServicePatternException) as error: + except (ServicePattern.DoesNotExist, models.ServicePatternException): return HttpResponse("no\n", content_type="text/plain") else: return HttpResponse("no\n", content_type="text/plain") + class Validate(View): """service ticket validation""" @staticmethod @@ -406,7 +413,7 @@ class ValidateError(Exception): return render( request, "cas_server/serviceValidateError.xml", - {'code':self.code, 'msg':self.msg}, + {'code': self.code, 'msg': self.msg}, content_type="text/xml; charset=utf-8" ) @@ -437,12 +444,12 @@ class ValidateService(View, AttributesMixin): try: self.ticket, proxies = self.process_ticket() params = { - 'username':self.ticket.user.username, - 'attributes':self.attributes(), - 'proxies':proxies + 'username': self.ticket.user.username, + 'attributes': self.attributes(), + 'proxies': proxies } - if self.ticket.service_pattern.user_field and \ - self.ticket.user.attributs.get(self.ticket.service_pattern.user_field): + if (self.ticket.service_pattern.user_field and + self.ticket.user.attributs.get(self.ticket.service_pattern.user_field)): params['username'] = self.ticket.user.attributs.get( self.ticket.service_pattern.user_field ) @@ -458,7 +465,6 @@ class ValidateService(View, AttributesMixin): except ValidateError as error: return error.render(request) - def process_ticket(self): """fetch the ticket angains the database and check its validity""" try: @@ -489,7 +495,6 @@ class ValidateService(View, AttributesMixin): except (ServiceTicket.DoesNotExist, ProxyTicket.DoesNotExist): raise ValidateError('INVALID_TICKET', 'ticket not found') - def process_pgturl(self, params): """Handle PGT request""" try: @@ -502,7 +507,7 @@ class ValidateService(View, AttributesMixin): service_pattern=pattern, single_log_out=pattern.single_log_out ) - url = utils.update_url(self.pgt_url, {'pgtIou':proxyid, 'pgtId':pticket.value}) + url = utils.update_url(self.pgt_url, {'pgtIou': proxyid, 'pgtId': pticket.value}) try: ret = requests.get(url, verify=settings.CAS_PROXY_CA_CERTIFICATE_PATH) if ret.status_code == 200: @@ -529,6 +534,7 @@ class ValidateService(View, AttributesMixin): 'callback url not allowed by configuration' ) + class Proxy(View): """proxy ticket service""" @@ -552,7 +558,6 @@ class Proxy(View): except ValidateError as error: return error.render(request) - def process_proxy(self): """handle PT request""" try: @@ -579,7 +584,7 @@ class Proxy(View): return render( self.request, "cas_server/proxy.xml", - {'ticket':pticket.value}, + {'ticket': pticket.value}, content_type="text/xml; charset=utf-8" ) except ProxyGrantingTicket.DoesNotExist: @@ -593,7 +598,6 @@ class Proxy(View): ) - class SamlValidateError(Exception): """handle saml validation error""" def __init__(self, code, msg=""): @@ -610,27 +614,14 @@ class SamlValidateError(Exception): request, "cas_server/samlValidateError.xml", { - 'code':self.code, - 'msg':self.msg, - 'IssueInstant':timezone.now().isoformat(), - 'ResponseID':utils.gen_saml_id() + 'code': self.code, + 'msg': self.msg, + 'IssueInstant': timezone.now().isoformat(), + 'ResponseID': utils.gen_saml_id() }, content_type="text/xml; charset=utf-8" ) -def _saml_validate_error(request, code, msg=""): - """render the samlValidateError.xml templace using `code` and `msg`""" - return render( - request, - "cas_server/samlValidateError.xml", - { - 'code':code, - 'msg':msg, - 'IssueInstant':timezone.now().isoformat(), - 'ResponseID':utils.gen_saml_id() - }, - content_type="text/xml; charset=utf-8" - ) class SamlValidate(View, AttributesMixin): """SAML ticket validation""" @@ -651,19 +642,19 @@ class SamlValidate(View, AttributesMixin): self.root = etree.fromstring(request.body) try: self.ticket = self.process_ticket() - expire_instant = (self.ticket.creation + \ - timedelta(seconds=self.ticket.VALIDITY)).isoformat() + expire_instant = (self.ticket.creation + + timedelta(seconds=self.ticket.VALIDITY)).isoformat() attributes = self.attributes() params = { - 'IssueInstant':timezone.now().isoformat(), - 'expireInstant':expire_instant, - 'Recipient':self.target, - 'ResponseID':utils.gen_saml_id(), - 'username':self.ticket.user.username, - 'attributes':attributes + 'IssueInstant': timezone.now().isoformat(), + 'expireInstant': expire_instant, + 'Recipient': self.target, + 'ResponseID': utils.gen_saml_id(), + 'username': self.ticket.user.username, + 'attributes': attributes } if self.ticket.service_pattern.user_field and \ - self.ticket.user.attributs.get(self.ticket.service_pattern.user_field): + self.ticket.user.attributs.get(self.ticket.service_pattern.user_field): params['username'] = self.ticket.user.attributs.get( self.ticket.service_pattern.user_field )