mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-09-19 04:59:01 +00:00
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:
parent
1fe9bb317a
commit
111f8f9145
@ -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():
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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'),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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'),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user