Add Login Ticket to prevent login replay + by ticket len options
This commit is contained in:
		@@ -21,7 +21,18 @@ setting_default('CAS_WARN_TEMPLATE', 'cas_server/warn.html')
 | 
			
		||||
setting_default('CAS_LOGGED_TEMPLATE', 'cas_server/logged.html')
 | 
			
		||||
setting_default('CAS_LOGOUT_TEMPLATE', 'cas_server/logout.html')
 | 
			
		||||
setting_default('CAS_AUTH_CLASS', 'cas_server.auth.DjangoAuthUser')
 | 
			
		||||
setting_default('CAS_ST_LEN', 30)
 | 
			
		||||
# All CAS implementation MUST support ST and PT up to 32 chars,
 | 
			
		||||
# PGT and PGTIOU up to 64 chars and it is RECOMMENDED that all
 | 
			
		||||
# tickets up to 256 chars are supports so we use 64 for the default
 | 
			
		||||
# len.
 | 
			
		||||
setting_default('CAS_TICKET_LEN', 64)
 | 
			
		||||
 | 
			
		||||
setting_default('CAS_LT_LEN', settings.CAS_TICKET_LEN)
 | 
			
		||||
setting_default('CAS_ST_LEN', settings.CAS_TICKET_LEN)
 | 
			
		||||
setting_default('CAS_PT_LEN', settings.CAS_TICKET_LEN)
 | 
			
		||||
setting_default('CAS_PGT_LEN', settings.CAS_TICKET_LEN)
 | 
			
		||||
setting_default('CAS_PGTIOU_LEN', settings.CAS_TICKET_LEN)
 | 
			
		||||
 | 
			
		||||
setting_default('CAS_TICKET_VALIDITY', 300)
 | 
			
		||||
setting_default('CAS_TICKET_TIMEOUT', 24*3600)
 | 
			
		||||
setting_default('CAS_PROXY_CA_CERTIFICATE_PATH', True)
 | 
			
		||||
@@ -29,9 +40,18 @@ setting_default('CAS_REDIRECT_TO_LOGIN_AFTER_LOGOUT', False)
 | 
			
		||||
 | 
			
		||||
setting_default('CAS_AUTH_SHARED_SECRET', '')
 | 
			
		||||
 | 
			
		||||
setting_default('CAS_LOGIN_TICKET_PREFIX', 'LT')
 | 
			
		||||
# Service tickets MUST begin with the characters ST so you should not change this
 | 
			
		||||
# Services MUST be able to accept service tickets of up to 32 characters in length
 | 
			
		||||
setting_default('CAS_SERVICE_TICKET_PREFIX', 'ST')
 | 
			
		||||
# Proxy tickets SHOULD begin with the characters, PT.
 | 
			
		||||
# Back-end services MUST be able to accept proxy tickets of up to 32 characters.
 | 
			
		||||
setting_default('CAS_PROXY_TICKET_PREFIX', 'PT')
 | 
			
		||||
# Proxy-granting tickets SHOULD begin with the characters PGT
 | 
			
		||||
# Services MUST be able to handle proxy-granting tickets of up to 64
 | 
			
		||||
setting_default('CAS_PROXY_GRANTING_TICKET_PREFIX', 'PGT')
 | 
			
		||||
# Proxy-granting ticket IOUs SHOULD begin with the characters, PGTIOU
 | 
			
		||||
# Services MUST be able to handle PGTIOUs of up to 64 characters in length.
 | 
			
		||||
setting_default('CAS_PROXY_GRANTING_TICKET_IOU_PREFIX', 'PGTIOU')
 | 
			
		||||
 | 
			
		||||
setting_default('CAS_SQL_HOST', 'localhost')
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@ class UserCredential(forms.Form):
 | 
			
		||||
    username = forms.CharField(label=_('login'))
 | 
			
		||||
    service = forms.CharField(widget=forms.HiddenInput(), required=False)
 | 
			
		||||
    password = forms.CharField(label=_('password'), widget=forms.PasswordInput)
 | 
			
		||||
    lt = forms.CharField(widget=forms.HiddenInput())
 | 
			
		||||
    method = forms.CharField(widget=forms.HiddenInput(), required=False)
 | 
			
		||||
    warn = forms.BooleanField(label=_('warn'), required=False)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -66,32 +66,36 @@ def unpack_nested_exception(error):
 | 
			
		||||
    return error
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _gen_ticket(prefix):
 | 
			
		||||
def _gen_ticket(prefix, lg=settings.CAS_TICKET_LEN):
 | 
			
		||||
    """Generate a ticket with prefix `prefix`"""
 | 
			
		||||
    return '%s-%s' % (
 | 
			
		||||
        prefix,
 | 
			
		||||
        ''.join(
 | 
			
		||||
            random.choice(
 | 
			
		||||
                string.ascii_letters + string.digits
 | 
			
		||||
            ) for _ in range(settings.CAS_ST_LEN)
 | 
			
		||||
            ) for _ in range(lg - len(prefix) - 1)
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
    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)
 | 
			
		||||
    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)
 | 
			
		||||
    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)
 | 
			
		||||
    return _gen_ticket(settings.CAS_PROXY_GRANTING_TICKET_IOU_PREFIX, settings.CAS_PGTIOU_LEN)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gen_saml_id():
 | 
			
		||||
 
 | 
			
		||||
@@ -123,15 +123,26 @@ class LoginView(View, LogoutMixin):
 | 
			
		||||
        self.gateway = request.POST.get('gateway')
 | 
			
		||||
        self.method = request.POST.get('method')
 | 
			
		||||
 | 
			
		||||
        if not request.session.get("authenticated") or self.renew:
 | 
			
		||||
            self.form = forms.UserCredential(
 | 
			
		||||
                request.POST,
 | 
			
		||||
                initial={
 | 
			
		||||
                    'service':self.service,
 | 
			
		||||
                    'method':self.method,
 | 
			
		||||
                    'warn':request.session.get("warn")
 | 
			
		||||
                }
 | 
			
		||||
        # save LT for later check
 | 
			
		||||
        lt_valid = request.session.get('lt')
 | 
			
		||||
        lt_send = request.POST.get('lt')
 | 
			
		||||
        # generate a new LT
 | 
			
		||||
        request.session['lt'] = utils.gen_lt()
 | 
			
		||||
 | 
			
		||||
        # check if send LT is valid
 | 
			
		||||
        if lt_valid is None or lt_valid != lt_send:
 | 
			
		||||
            messages.add_message(
 | 
			
		||||
                self.request,
 | 
			
		||||
                messages.ERROR,
 | 
			
		||||
                _(u"Invalid login ticket")
 | 
			
		||||
            )
 | 
			
		||||
            values = request.POST.copy()
 | 
			
		||||
            # if not set a new LT and fail
 | 
			
		||||
            values['lt'] = request.session['lt']
 | 
			
		||||
            self.init_form(values)
 | 
			
		||||
 | 
			
		||||
        elif not request.session.get("authenticated") or self.renew:
 | 
			
		||||
            self.init_form(request.POST)
 | 
			
		||||
            if self.form.is_valid():
 | 
			
		||||
                self.user = models.User.objects.get(username=self.form.cleaned_data['username'])
 | 
			
		||||
                request.session.set_expiry(0)
 | 
			
		||||
@@ -152,17 +163,24 @@ class LoginView(View, LogoutMixin):
 | 
			
		||||
        self.gateway = request.GET.get('gateway')
 | 
			
		||||
        self.method = request.GET.get('method')
 | 
			
		||||
 | 
			
		||||
        if not request.session.get("authenticated") or self.renew:
 | 
			
		||||
            self.form = forms.UserCredential(
 | 
			
		||||
                initial={
 | 
			
		||||
                    'service':self.service,
 | 
			
		||||
                    'method':self.method,
 | 
			
		||||
                    'warn':request.session.get("warn")
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
        # generate a new LT
 | 
			
		||||
        request.session['lt'] = utils.gen_lt()
 | 
			
		||||
 | 
			
		||||
        if not request.session.get("authenticated") or self.renew:
 | 
			
		||||
            self.init_form()
 | 
			
		||||
        return self.common()
 | 
			
		||||
 | 
			
		||||
    def init_form(self, values=None):
 | 
			
		||||
        self.form = forms.UserCredential(
 | 
			
		||||
            values,
 | 
			
		||||
            initial={
 | 
			
		||||
                'service':self.service,
 | 
			
		||||
                'method':self.method,
 | 
			
		||||
                'warn':self.request.session.get("warn"),
 | 
			
		||||
                'lt':self.request.session['lt']
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def service_login(self):
 | 
			
		||||
        """Perform login agains a service"""
 | 
			
		||||
        try:
 | 
			
		||||
@@ -231,7 +249,7 @@ class LoginView(View, LogoutMixin):
 | 
			
		||||
            self.user = models.User.objects.get(username=self.request.session.get("username"))
 | 
			
		||||
        except models.User.DoesNotExist:
 | 
			
		||||
            self.logout()
 | 
			
		||||
            return utils.redirect_params("cas_server:login", params=dict(self.request.GET))
 | 
			
		||||
            return utils.redirect_params("cas_server:login", params=self.request.GET)
 | 
			
		||||
 | 
			
		||||
        # if login agains a service is self.requestest
 | 
			
		||||
        if self.service:
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user