mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-30 21:50:59 +00:00
Merge branch 'master' into 12.0
This commit is contained in:
commit
d24d71420e
14
frontend/package-lock.json
generated
14
frontend/package-lock.json
generated
@ -14,7 +14,7 @@
|
|||||||
"@gatsbyjs/reach-router": "1.3.9",
|
"@gatsbyjs/reach-router": "1.3.9",
|
||||||
"@seafile/react-image-lightbox": "2.0.2",
|
"@seafile/react-image-lightbox": "2.0.2",
|
||||||
"@seafile/resumablejs": "1.1.16",
|
"@seafile/resumablejs": "1.1.16",
|
||||||
"@seafile/sdoc-editor": "0.5.63",
|
"@seafile/sdoc-editor": "0.5.64",
|
||||||
"@seafile/seafile-calendar": "0.0.12",
|
"@seafile/seafile-calendar": "0.0.12",
|
||||||
"@seafile/seafile-editor": "1.0.82",
|
"@seafile/seafile-editor": "1.0.82",
|
||||||
"@uiw/codemirror-extensions-langs": "^4.19.4",
|
"@uiw/codemirror-extensions-langs": "^4.19.4",
|
||||||
@ -4617,9 +4617,9 @@
|
|||||||
"integrity": "sha512-8rBbmAEuuwOAGHYGCtEzpx+bxAcGS+V30otMmhRe7bPAdh4E57RWgCa8x7pkzHGFlY1t5d+ILz1gojvPVMYQig=="
|
"integrity": "sha512-8rBbmAEuuwOAGHYGCtEzpx+bxAcGS+V30otMmhRe7bPAdh4E57RWgCa8x7pkzHGFlY1t5d+ILz1gojvPVMYQig=="
|
||||||
},
|
},
|
||||||
"node_modules/@seafile/sdoc-editor": {
|
"node_modules/@seafile/sdoc-editor": {
|
||||||
"version": "0.5.63",
|
"version": "0.5.64",
|
||||||
"resolved": "https://registry.npmjs.org/@seafile/sdoc-editor/-/sdoc-editor-0.5.63.tgz",
|
"resolved": "https://registry.npmjs.org/@seafile/sdoc-editor/-/sdoc-editor-0.5.64.tgz",
|
||||||
"integrity": "sha512-qXi1VOSSfREtsVwdVSj7brLhsqIc7+rxBX8WHQlioUmSvv53xd/RBFJRtmla9Ui+LvmyCSGtzZ4oTKZU2/WAGA==",
|
"integrity": "sha512-kDZwJEprBvvo8qCsaEh4zoPJLsKkg5d9co20buJ20raMDTd3IH/iuylj4Pp3hEyiSUFeT4zwOdxMFV2Vr1a+UQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@seafile/print-js": "1.6.5",
|
"@seafile/print-js": "1.6.5",
|
||||||
"@seafile/react-image-lightbox": "2.0.4",
|
"@seafile/react-image-lightbox": "2.0.4",
|
||||||
@ -31292,9 +31292,9 @@
|
|||||||
"integrity": "sha512-8rBbmAEuuwOAGHYGCtEzpx+bxAcGS+V30otMmhRe7bPAdh4E57RWgCa8x7pkzHGFlY1t5d+ILz1gojvPVMYQig=="
|
"integrity": "sha512-8rBbmAEuuwOAGHYGCtEzpx+bxAcGS+V30otMmhRe7bPAdh4E57RWgCa8x7pkzHGFlY1t5d+ILz1gojvPVMYQig=="
|
||||||
},
|
},
|
||||||
"@seafile/sdoc-editor": {
|
"@seafile/sdoc-editor": {
|
||||||
"version": "0.5.63",
|
"version": "0.5.64",
|
||||||
"resolved": "https://registry.npmjs.org/@seafile/sdoc-editor/-/sdoc-editor-0.5.63.tgz",
|
"resolved": "https://registry.npmjs.org/@seafile/sdoc-editor/-/sdoc-editor-0.5.64.tgz",
|
||||||
"integrity": "sha512-qXi1VOSSfREtsVwdVSj7brLhsqIc7+rxBX8WHQlioUmSvv53xd/RBFJRtmla9Ui+LvmyCSGtzZ4oTKZU2/WAGA==",
|
"integrity": "sha512-kDZwJEprBvvo8qCsaEh4zoPJLsKkg5d9co20buJ20raMDTd3IH/iuylj4Pp3hEyiSUFeT4zwOdxMFV2Vr1a+UQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@seafile/print-js": "1.6.5",
|
"@seafile/print-js": "1.6.5",
|
||||||
"@seafile/react-image-lightbox": "2.0.4",
|
"@seafile/react-image-lightbox": "2.0.4",
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"@gatsbyjs/reach-router": "1.3.9",
|
"@gatsbyjs/reach-router": "1.3.9",
|
||||||
"@seafile/react-image-lightbox": "2.0.2",
|
"@seafile/react-image-lightbox": "2.0.2",
|
||||||
"@seafile/resumablejs": "1.1.16",
|
"@seafile/resumablejs": "1.1.16",
|
||||||
"@seafile/sdoc-editor": "0.5.63",
|
"@seafile/sdoc-editor": "0.5.64",
|
||||||
"@seafile/seafile-calendar": "0.0.12",
|
"@seafile/seafile-calendar": "0.0.12",
|
||||||
"@seafile/seafile-editor": "1.0.82",
|
"@seafile/seafile-editor": "1.0.82",
|
||||||
"@uiw/codemirror-extensions-langs": "^4.19.4",
|
"@uiw/codemirror-extensions-langs": "^4.19.4",
|
||||||
|
@ -29,6 +29,7 @@ from saml2.client import Saml2Client
|
|||||||
from saml2.metadata import entity_descriptor
|
from saml2.metadata import entity_descriptor
|
||||||
from djangosaml2.cache import IdentityCache, OutstandingQueriesCache
|
from djangosaml2.cache import IdentityCache, OutstandingQueriesCache
|
||||||
from djangosaml2.conf import get_config
|
from djangosaml2.conf import get_config
|
||||||
|
from djangosaml2.views import LogoutView
|
||||||
|
|
||||||
from seaserv import ccnet_api, seafile_api
|
from seaserv import ccnet_api, seafile_api
|
||||||
|
|
||||||
@ -562,3 +563,7 @@ def adfs_compatible_view(request, url_prefix):
|
|||||||
|
|
||||||
org_id = str(org.org_id)
|
org_id = str(org.org_id)
|
||||||
return HttpResponsePermanentRedirect(request.path.replace(url_prefix, org_id))
|
return HttpResponsePermanentRedirect(request.path.replace(url_prefix, org_id))
|
||||||
|
|
||||||
|
class SamlLogoutView(LogoutView):
|
||||||
|
def do_logout_service(self, request, data, binding, *args, **kwargs):
|
||||||
|
return super(SamlLogoutView, self).do_logout_service(request, data, binding)
|
||||||
|
@ -1,45 +1,32 @@
|
|||||||
# Copyright (c) 2012-2016 Seafile Ltd.
|
# Copyright (c) 2012-2016 Seafile Ltd.
|
||||||
import hashlib
|
|
||||||
import re
|
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
from formtools.wizard.views import SessionWizardView
|
||||||
|
|
||||||
from constance import config
|
from constance import config
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.http import HttpResponseRedirect, Http404
|
from django.http import HttpResponseRedirect
|
||||||
from django.utils.translation import gettext as _
|
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils.http import url_has_allowed_host_and_scheme
|
from django.utils.http import url_has_allowed_host_and_scheme
|
||||||
from django.views.decorators.debug import sensitive_post_parameters
|
from django.views.decorators.debug import sensitive_post_parameters
|
||||||
|
|
||||||
from formtools.wizard.views import SessionWizardView
|
|
||||||
|
|
||||||
|
|
||||||
from seahub.auth import REDIRECT_FIELD_NAME, get_backends
|
from seahub.auth import REDIRECT_FIELD_NAME, get_backends
|
||||||
from seahub.auth import login as auth_login
|
from seahub.auth import login as auth_login
|
||||||
from seahub.base.accounts import User
|
from seahub.base.accounts import User
|
||||||
from seahub.utils.ip import get_remote_ip
|
|
||||||
|
|
||||||
from seahub.profile.models import Profile
|
from seahub.profile.models import Profile
|
||||||
|
from seahub.two_factor.models import StaticDevice, default_device, user_has_device
|
||||||
from seahub.two_factor import login as two_factor_login
|
from seahub.two_factor.forms import BackupTokenAuthForm, AuthenticationTokenForm
|
||||||
from seahub.two_factor.models import (StaticDevice, TOTPDevice, default_device,
|
|
||||||
user_has_device)
|
|
||||||
|
|
||||||
from seahub.two_factor.forms import TOTPTokenAuthForm, BackupTokenAuthForm, AuthenticationTokenForm
|
|
||||||
from seahub.two_factor.views.utils import class_view_decorator
|
from seahub.two_factor.views.utils import class_view_decorator
|
||||||
|
|
||||||
from seahub.utils.auth import get_login_bg_image_path
|
from seahub.utils.auth import get_login_bg_image_path
|
||||||
|
|
||||||
|
|
||||||
# Get an instance of a logger
|
# Get an instance of a logger
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@class_view_decorator(sensitive_post_parameters())
|
@class_view_decorator(sensitive_post_parameters())
|
||||||
@class_view_decorator(never_cache)
|
@class_view_decorator(never_cache)
|
||||||
class TwoFactorVerifyView(SessionWizardView):
|
class TwoFactorVerifyView(SessionWizardView):
|
||||||
@ -99,28 +86,29 @@ class TwoFactorVerifyView(SessionWizardView):
|
|||||||
"""
|
"""
|
||||||
Login the user and redirect to the desired page.
|
Login the user and redirect to the desired page.
|
||||||
"""
|
"""
|
||||||
redirect_to = self.request.session.get(SESSION_KEY_TWO_FACTOR_REDIRECT_URL, '') \
|
redirect_to = (
|
||||||
or self.request.GET.get(self.redirect_field_name, '')
|
self.request.session.get(SESSION_KEY_TWO_FACTOR_REDIRECT_URL, '')
|
||||||
|
or self.request.GET.get(self.redirect_field_name, '')
|
||||||
|
)
|
||||||
|
|
||||||
auth_login(self.request, self.user)
|
auth_login(self.request, self.user)
|
||||||
|
|
||||||
self.reset_two_factor_session()
|
self.reset_two_factor_session()
|
||||||
|
|
||||||
if not url_has_allowed_host_and_scheme(url=redirect_to, allowed_hosts=self.request.get_host()):
|
if not url_has_allowed_host_and_scheme(url=redirect_to,
|
||||||
|
allowed_hosts=self.request.get_host()):
|
||||||
redirect_to = str(settings.LOGIN_REDIRECT_URL)
|
redirect_to = str(settings.LOGIN_REDIRECT_URL)
|
||||||
|
|
||||||
res = HttpResponseRedirect(redirect_to)
|
res = HttpResponseRedirect(redirect_to)
|
||||||
if form_list[0].is_valid():
|
if kwargs.get('remember_me', False):
|
||||||
remember_me = form_list[0].cleaned_data['remember_me']
|
s = remember_device(self.user.username)
|
||||||
if remember_me:
|
res.set_cookie(
|
||||||
s = remember_device(self.user.username)
|
'S2FA', s.session_key,
|
||||||
res.set_cookie(
|
max_age=settings.TWO_FACTOR_DEVICE_REMEMBER_DAYS * 24 * 60 * 60,
|
||||||
'S2FA', s.session_key,
|
domain=settings.SESSION_COOKIE_DOMAIN,
|
||||||
max_age=settings.TWO_FACTOR_DEVICE_REMEMBER_DAYS * 24 * 60 * 60,
|
path=settings.SESSION_COOKIE_PATH,
|
||||||
domain=settings.SESSION_COOKIE_DOMAIN,
|
secure=settings.SESSION_COOKIE_SECURE or None,
|
||||||
path=settings.SESSION_COOKIE_PATH,
|
httponly=settings.SESSION_COOKIE_HTTPONLY or None)
|
||||||
secure=settings.SESSION_COOKIE_SECURE or None,
|
|
||||||
httponly=settings.SESSION_COOKIE_HTTPONLY or None)
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_form_kwargs(self, step=None):
|
def get_form_kwargs(self, step=None):
|
||||||
@ -199,22 +187,28 @@ class TwoFactorVerifyView(SessionWizardView):
|
|||||||
)
|
)
|
||||||
final_form_list.append(form_obj)
|
final_form_list.append(form_obj)
|
||||||
|
|
||||||
|
kwargs['remember_me'] = form.cleaned_data['remember_me']
|
||||||
done_response = self.done(final_form_list, **kwargs)
|
done_response = self.done(final_form_list, **kwargs)
|
||||||
self.storage.reset()
|
self.storage.reset()
|
||||||
return done_response
|
return done_response
|
||||||
|
|
||||||
|
|
||||||
def two_factor_auth_enabled(user):
|
def two_factor_auth_enabled(user):
|
||||||
return config.ENABLE_TWO_FACTOR_AUTH and user_has_device(user)
|
return config.ENABLE_TWO_FACTOR_AUTH and user_has_device(user)
|
||||||
|
|
||||||
|
|
||||||
SESSION_KEY_TWO_FACTOR_AUTH_USERNAME = '2fa-username'
|
SESSION_KEY_TWO_FACTOR_AUTH_USERNAME = '2fa-username'
|
||||||
SESSION_KEY_TWO_FACTOR_REDIRECT_URL = '2fa-redirect-url'
|
SESSION_KEY_TWO_FACTOR_REDIRECT_URL = '2fa-redirect-url'
|
||||||
SESSION_KEY_TWO_FACTOR_FAILED_ATTEMPT = '2fa-failed-attempt'
|
SESSION_KEY_TWO_FACTOR_FAILED_ATTEMPT = '2fa-failed-attempt'
|
||||||
|
|
||||||
|
|
||||||
def handle_two_factor_auth(request, user, redirect_to):
|
def handle_two_factor_auth(request, user, redirect_to):
|
||||||
request.session[SESSION_KEY_TWO_FACTOR_AUTH_USERNAME] = user.username
|
request.session[SESSION_KEY_TWO_FACTOR_AUTH_USERNAME] = user.username
|
||||||
request.session[SESSION_KEY_TWO_FACTOR_REDIRECT_URL] = redirect_to
|
request.session[SESSION_KEY_TWO_FACTOR_REDIRECT_URL] = redirect_to
|
||||||
request.session[SESSION_KEY_TWO_FACTOR_FAILED_ATTEMPT] = 0
|
request.session[SESSION_KEY_TWO_FACTOR_FAILED_ATTEMPT] = 0
|
||||||
return redirect(reverse('two_factor_auth'))
|
return redirect(reverse('two_factor_auth'))
|
||||||
|
|
||||||
|
|
||||||
def verify_two_factor_token(user, token):
|
def verify_two_factor_token(user, token):
|
||||||
"""
|
"""
|
||||||
This function is called when doing the api authentication.
|
This function is called when doing the api authentication.
|
||||||
@ -225,6 +219,7 @@ def verify_two_factor_token(user, token):
|
|||||||
if device:
|
if device:
|
||||||
return device.verify_token(token)
|
return device.verify_token(token)
|
||||||
|
|
||||||
|
|
||||||
def remember_device(s_data):
|
def remember_device(s_data):
|
||||||
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
|
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
|
||||||
s = SessionStore()
|
s = SessionStore()
|
||||||
@ -233,6 +228,7 @@ def remember_device(s_data):
|
|||||||
s.create()
|
s.create()
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
def is_device_remembered(request_header, user):
|
def is_device_remembered(request_header, user):
|
||||||
if not request_header:
|
if not request_header:
|
||||||
return False
|
return False
|
||||||
|
@ -942,6 +942,8 @@ if getattr(settings, 'ENABLE_MULTI_ADFS', False):
|
|||||||
re_path(r'^org/custom/(?P<org_id>\d+)/saml2/metadata/$', metadata, name='org_saml2_metadata'),
|
re_path(r'^org/custom/(?P<org_id>\d+)/saml2/metadata/$', metadata, name='org_saml2_metadata'),
|
||||||
re_path(r'^org/custom/(?P<org_id>\d+)/saml2/connect/$', saml2_connect, name='org_saml2_connect'),
|
re_path(r'^org/custom/(?P<org_id>\d+)/saml2/connect/$', saml2_connect, name='org_saml2_connect'),
|
||||||
re_path(r'^org/custom/(?P<org_id>\d+)/saml2/disconnect/$', saml2_disconnect, name='org_saml2_disconnect'),
|
re_path(r'^org/custom/(?P<org_id>\d+)/saml2/disconnect/$', saml2_disconnect, name='org_saml2_disconnect'),
|
||||||
|
re_path(r'^org/custom/(?P<org_id>\d+)/saml2/ls/$', SamlLogoutView.as_view(), name='org_saml2_ls'),
|
||||||
|
re_path(r'^org/custom/(?P<org_id>\d+)/saml2/ls/post/$', SamlLogoutView.as_view(), name='org_saml2_ls_post'),
|
||||||
re_path(r'^org/custom/(?P<org_id>\d+)/saml2/', include(('djangosaml2.urls', 'djangosaml2'), namespace='org')),
|
re_path(r'^org/custom/(?P<org_id>\d+)/saml2/', include(('djangosaml2.urls', 'djangosaml2'), namespace='org')),
|
||||||
re_path(r'^org/custom/(?P<url_prefix>[a-z_0-9-]+)/saml2/login/$', adfs_compatible_view, name='login_compatible_view'),
|
re_path(r'^org/custom/(?P<url_prefix>[a-z_0-9-]+)/saml2/login/$', adfs_compatible_view, name='login_compatible_view'),
|
||||||
re_path(r'^org/custom/(?P<url_prefix>[a-z_0-9-]+)/saml2/acs/$', adfs_compatible_view, name='acs_compatible_view'),
|
re_path(r'^org/custom/(?P<url_prefix>[a-z_0-9-]+)/saml2/acs/$', adfs_compatible_view, name='acs_compatible_view'),
|
||||||
|
Loading…
Reference in New Issue
Block a user