sso: Fixes for regressions after adding captcha and axes

- Change sso refresh url to refresh-pubtkt since refresh was conflicting with
  captcha's image refresh url.
- Fix datetime.timedelta calculation for refresh interval. Now validity of
  ticket is 30 seconds as it was intended to be. It was wrongly set to 30 days
  earlier.

Signed-off-by: Joseph Nuthalapati <njoseph@thoughtworks.com>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Joseph Nuthalapati 2017-11-07 19:09:44 +05:30 committed by James Valleroy
parent 1fe9bb317a
commit 111f8f9145
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
5 changed files with 41 additions and 25 deletions

View File

@ -89,18 +89,21 @@ def subcommand_create_key_pair(_):
os.chmod(fil, 0o440) os.chmod(fil, 0o440)
def create_ticket(pkey, uid, validuntil, ip=None, tokens=None, def create_ticket(pkey,
udata=None, graceperiod=None, extra_fields=None): uid,
validuntil,
ip=None,
tokens=None,
udata=None,
graceperiod=None,
extra_fields=None):
"""Create and return a signed mod_auth_pubtkt ticket.""" """Create and return a signed mod_auth_pubtkt ticket."""
fields = [ fields = [
'uid={}'.format(uid), 'uid={}'.format(uid), 'validuntil={}'.format(validuntil, type='d'), ip
'validuntil={}'.format(validuntil, type='d'), and 'cip={}'.format(ip), tokens and 'tokens={}'.format(tokens),
ip and 'cip={}'.format(ip), graceperiod and 'graceperiod={}'.format(graceperiod, type='d'), udata
tokens and 'tokens={}'.format(tokens), and 'udata={}'.format(udata), extra_fields
graceperiod and 'graceperiod={}'.format(graceperiod, type='d'), and ';'.join(['{}={}'.format(k, v) for k, v in extra_fields])
udata and 'udata={}'.format(udata),
extra_fields and ';'.join(
['{}={}'.format(k, v) for k, v in extra_fields])
] ]
data = ';'.join(filter(None, fields)) data = ';'.join(filter(None, fields))
signature = 'sig={}'.format(sign(pkey, data)) signature = 'sig={}'.format(sign(pkey, data))
@ -120,15 +123,22 @@ def subcommand_generate_ticket(arguments):
tokens = arguments.tokens tokens = arguments.tokens
with open(private_key_file, 'r') as fil: with open(private_key_file, 'r') as fil:
pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, fil.read().encode()) pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, fil.read().encode())
valid_until = minutes_from_now(30) valid_until = seconds_from_now(30)
grace_period = minutes_from_now(25) grace_period = seconds_from_now(25)
print(create_ticket( print(create_ticket(
pkey, uid, valid_until, tokens=tokens, graceperiod=grace_period)) pkey, uid, valid_until, tokens=tokens, graceperiod=grace_period))
def minutes_from_now(minutes): # def minutes_from_now(minutes):
"""Return a timestamp at the given number of minutes from now.""" # """Return a timestamp at the given number of minutes from now."""
return (datetime.datetime.now() + datetime.timedelta(minutes)).timestamp() # return (datetime.datetime.now() + datetime.timedelta(
# 0, minutes * 60)).timestamp()
def seconds_from_now(seconds):
"""Return a timestamp at the given number of seconds from now."""
return (
datetime.datetime.now() + datetime.timedelta(0, seconds)).timestamp()
def main(): def main():

View File

@ -3,7 +3,7 @@
TKTAuthLoginURL /plinth/accounts/sso/login/ TKTAuthLoginURL /plinth/accounts/sso/login/
TKTAuthBackArgName next TKTAuthBackArgName next
TKTAuthDigest SHA512 TKTAuthDigest SHA512
TKTAuthRefreshURL /plinth/accounts/sso/refresh/ TKTAuthRefreshURL /plinth/accounts/sso/refresh-pubtkt/
TKTAuthUnauthURL /plinth TKTAuthUnauthURL /plinth
AuthType mod_auth_pubtkt AuthType mod_auth_pubtkt
AuthName "FreedomBox Single Sign On" AuthName "FreedomBox Single Sign On"

View File

@ -20,11 +20,15 @@ URLs for the Single Sign On module.
from django.conf.urls import url from django.conf.urls import url
from .views import SSOLoginView, refresh from .views import SSOLoginView, refresh
from stronghold.decorators import public from stronghold.decorators import public
from plinth.utils import non_admin_view
urlpatterns = [ urlpatterns = [
url(r'^accounts/sso/login/$', public(SSOLoginView.as_view()), name='sso-login'), url(r'^accounts/sso/login/$',
url(r'^accounts/sso/refresh/$', refresh, name='sso-refresh'), public(SSOLoginView.as_view()),
name='sso-login'),
url(r'^accounts/sso/refresh-pubtkt/$',
non_admin_view(refresh),
name='sso-refresh'),
] ]

View File

@ -23,7 +23,6 @@ import os
import urllib import urllib
from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import LoginView, LogoutView from django.contrib.auth.views import LoginView, LogoutView
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
@ -112,10 +111,11 @@ class SSOLogoutView(LogoutView):
return response return response
@login_required
def refresh(request): def refresh(request):
"""Simulate cookie refresh - redirect logged in user with a new cookie""" """Simulate cookie refresh - redirect logged in user with a new cookie"""
redirect_url = request.GET.get(REDIRECT_FIELD_NAME, '') redirect_url = request.GET.get(REDIRECT_FIELD_NAME, '')
response = HttpResponseRedirect(redirect_url) response = HttpResponseRedirect(redirect_url)
response.delete_cookie(SSO_COOKIE_NAME) response.delete_cookie(SSO_COOKIE_NAME)
# Redirect with cookie doesn't work with 300 series
response.status_code = 200
return set_ticket_cookie(request.user, response) return set_ticket_cookie(request.user, response)

View File

@ -34,11 +34,13 @@ urlpatterns = [
# captcha urls are public # captcha urls are public
url(r'image/(?P<key>\w+)/$', url(r'image/(?P<key>\w+)/$',
public(cviews.captcha_image), name='captcha-image', public(cviews.captcha_image), name='captcha-image', kwargs={
kwargs={'scale': 1}), 'scale': 1
}),
url(r'image/(?P<key>\w+)@2/$', url(r'image/(?P<key>\w+)@2/$',
public(cviews.captcha_image), name='captcha-image-2x', public(cviews.captcha_image), name='captcha-image-2x', kwargs={
kwargs={'scale': 2}), 'scale': 2
}),
url(r'audio/(?P<key>\w+)/$', url(r'audio/(?P<key>\w+)/$',
public(cviews.captcha_audio), name='captcha-audio'), public(cviews.captcha_audio), name='captcha-audio'),
url(r'refresh/$', public(cviews.captcha_refresh), name='captcha-refresh'), url(r'refresh/$', public(cviews.captcha_refresh), name='captcha-refresh'),