Login/Logout redirects with Django variables
The login/logout url patterns now use
the Django LOGIN_URL and LOGOUT_URL
The default redirect url after a successful login
now uses as default the Django LOGIN_REDIRECT_URL
with possible override using HORIZON_CONFIG.user_home
in settings file. There are 3 cases:
* no user_home in settings.HORIZON_CONFIG - uses
Django LOGIN_REDIRECT_URL
* user_home = None in settings.HORIZON_CONFIG -
will default to the primary dashboard(the current
fall-back behavior)
* user_home = 'something' - it will be used to
determine the actual redirect url
Fixes bug 980434
Patch Set 2:
Restored the previous behavior - splash page('/')
redirects to /nova or /syspanel, depending on the user,
while /home/ will redirect to the 'user_home' setting
(or LOGIN_REDIRECT_URL if user_home is not set).
The same logic will be applied after user logs in.
Change-Id: I28e25566199393382639da9ca2022d1850f25a94
This commit is contained in:
@@ -52,7 +52,8 @@ HORIZON_CONFIG = {
|
|||||||
'dashboards': None,
|
'dashboards': None,
|
||||||
# Name of a default dashboard; defaults to first alphabetically if None
|
# Name of a default dashboard; defaults to first alphabetically if None
|
||||||
'default_dashboard': None,
|
'default_dashboard': None,
|
||||||
'user_home': None,
|
# Default redirect url for users' home
|
||||||
|
'user_home': settings.LOGIN_REDIRECT_URL,
|
||||||
'exceptions': {'unauthorized': [],
|
'exceptions': {'unauthorized': [],
|
||||||
'not_found': [],
|
'not_found': [],
|
||||||
'recoverable': []}
|
'recoverable': []}
|
||||||
@@ -700,9 +701,11 @@ class Site(Registry, HorizonComponent):
|
|||||||
{"user_home": "/home",} # A URL
|
{"user_home": "/home",} # A URL
|
||||||
{"user_home": "my_module.get_user_home",} # Path to a function
|
{"user_home": "my_module.get_user_home",} # Path to a function
|
||||||
{"user_home": lambda user: "/" + user.name,} # A function
|
{"user_home": lambda user: "/" + user.name,} # A function
|
||||||
|
{"user_home": None,} # Will always return the default dashboard
|
||||||
|
|
||||||
This can be useful if the default dashboard may not be accessible
|
This can be useful if the default dashboard may not be accessible
|
||||||
to all users.
|
to all users. When user_home is missing from HORIZON_CONFIG,
|
||||||
|
it will default to the settings.LOGIN_REDIRECT_URL value.
|
||||||
"""
|
"""
|
||||||
user_home = self._conf['user_home']
|
user_home = self._conf['user_home']
|
||||||
if user_home:
|
if user_home:
|
||||||
|
|||||||
@@ -19,14 +19,17 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from django.conf.urls.defaults import patterns, url, include
|
from django.conf.urls.defaults import patterns, url, include
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from horizon.views.auth import LoginView
|
from horizon.views.auth import LoginView
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = patterns('horizon.views.auth',
|
urlpatterns = patterns('horizon.views.auth',
|
||||||
url(r'home/$', 'user_home', name='user_home'),
|
url(r'home/$', 'user_home', name='user_home'),
|
||||||
url(r'auth/login/$', LoginView.as_view(), name='auth_login'),
|
url(r"^%s$" % settings.LOGIN_URL.lstrip('/'), LoginView.as_view(),
|
||||||
url(r'auth/logout/$', 'logout', name='auth_logout'),
|
name='auth_login'),
|
||||||
|
url(r"^%s$" % settings.LOGOUT_URL.lstrip('/'), 'logout',
|
||||||
|
name='auth_logout'),
|
||||||
url(r'auth/switch/(?P<tenant_id>[^/]+)/$', 'switch_tenants',
|
url(r'auth/switch/(?P<tenant_id>[^/]+)/$', 'switch_tenants',
|
||||||
name='auth_switch'))
|
name='auth_switch'))
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from django import http
|
from django import http
|
||||||
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from keystoneclient import exceptions as keystone_exceptions
|
from keystoneclient import exceptions as keystone_exceptions
|
||||||
from mox import IsA
|
from mox import IsA
|
||||||
@@ -72,19 +73,25 @@ class AuthViewTests(test.TestCase):
|
|||||||
|
|
||||||
self.assertTemplateUsed(res, 'horizon/auth/login.html')
|
self.assertTemplateUsed(res, 'horizon/auth/login.html')
|
||||||
|
|
||||||
|
@test.create_stubs({api: ('token_create', 'tenant_list_for_token',
|
||||||
|
'token_create_scoped')})
|
||||||
def test_login(self):
|
def test_login(self):
|
||||||
form_data = {'method': 'Login',
|
form_data = {'method': 'Login',
|
||||||
'region': 'http://localhost:5000/v2.0',
|
'region': 'http://localhost:5000/v2.0',
|
||||||
'password': self.user.password,
|
'password': self.user.password,
|
||||||
'username': self.user.name}
|
'username': self.user.name}
|
||||||
|
|
||||||
self.mox.StubOutWithMock(api, 'token_create')
|
|
||||||
self.mox.StubOutWithMock(api, 'tenant_list_for_token')
|
|
||||||
self.mox.StubOutWithMock(api, 'token_create_scoped')
|
|
||||||
|
|
||||||
aToken = self.tokens.unscoped_token
|
aToken = self.tokens.unscoped_token
|
||||||
bToken = self.tokens.scoped_token
|
bToken = self.tokens.scoped_token
|
||||||
|
|
||||||
|
api.token_create(IsA(http.HttpRequest), "", self.user.name,
|
||||||
|
self.user.password).AndReturn(aToken)
|
||||||
|
api.tenant_list_for_token(IsA(http.HttpRequest),
|
||||||
|
aToken.id).AndReturn([self.tenants.first()])
|
||||||
|
api.token_create_scoped(IsA(http.HttpRequest),
|
||||||
|
self.tenant.id,
|
||||||
|
aToken.id).AndReturn(bToken)
|
||||||
|
|
||||||
api.token_create(IsA(http.HttpRequest), "", self.user.name,
|
api.token_create(IsA(http.HttpRequest), "", self.user.name,
|
||||||
self.user.password).AndReturn(aToken)
|
self.user.password).AndReturn(aToken)
|
||||||
api.tenant_list_for_token(IsA(http.HttpRequest),
|
api.tenant_list_for_token(IsA(http.HttpRequest),
|
||||||
@@ -98,6 +105,12 @@ class AuthViewTests(test.TestCase):
|
|||||||
res = self.client.post(reverse('horizon:auth_login'), form_data)
|
res = self.client.post(reverse('horizon:auth_login'), form_data)
|
||||||
self.assertRedirectsNoFollow(res, DASH_INDEX_URL)
|
self.assertRedirectsNoFollow(res, DASH_INDEX_URL)
|
||||||
|
|
||||||
|
# Test default Django LOGIN_REDIRECT_URL
|
||||||
|
user_home = settings.HORIZON_CONFIG.pop('user_home')
|
||||||
|
res = self.client.post(reverse('horizon:auth_login'), form_data)
|
||||||
|
self.assertRedirectsNoFollow(res, settings.LOGIN_REDIRECT_URL)
|
||||||
|
settings.HORIZON_CONFIG['user_home'] = user_home
|
||||||
|
|
||||||
def test_login_first_tenant_invalid(self):
|
def test_login_first_tenant_invalid(self):
|
||||||
form_data = {'method': 'Login',
|
form_data = {'method': 'Login',
|
||||||
'region': 'http://localhost:5000/v2.0',
|
'region': 'http://localhost:5000/v2.0',
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
|
|
||||||
socket.setdefaulttimeout(1)
|
socket.setdefaulttimeout(1)
|
||||||
|
|
||||||
|
LOGIN_URL = '/auth/login/'
|
||||||
|
LOGOUT_URL = '/auth/logout/'
|
||||||
|
LOGIN_REDIRECT_URL = '/'
|
||||||
|
|
||||||
ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
|
ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
TESTSERVER = 'http://testserver'
|
TESTSERVER = 'http://testserver'
|
||||||
@@ -101,6 +105,7 @@ HORIZON_CONFIG = {
|
|||||||
"regex": '^.{8,18}$',
|
"regex": '^.{8,18}$',
|
||||||
"help_text": _("Password must be between 8 and 18 characters.")
|
"help_text": _("Password must be between 8 and 18 characters.")
|
||||||
},
|
},
|
||||||
|
'user_home': None
|
||||||
}
|
}
|
||||||
|
|
||||||
AVAILABLE_REGIONS = [
|
AVAILABLE_REGIONS = [
|
||||||
|
|||||||
@@ -34,7 +34,11 @@ TEMPLATE_DEBUG = DEBUG
|
|||||||
SITE_ID = 1
|
SITE_ID = 1
|
||||||
SITE_BRANDING = 'OpenStack'
|
SITE_BRANDING = 'OpenStack'
|
||||||
|
|
||||||
LOGIN_URL = '/auth/login'
|
LOGIN_URL = '/auth/login/'
|
||||||
|
LOGOUT_URL = '/auth/logout/'
|
||||||
|
# LOGIN_REDIRECT_URL can be used as an alternative for
|
||||||
|
# HORIZON_CONFIG.user_home, if user_home is not set.
|
||||||
|
# Do not set it to '/home/', as this will cause circular redirect loop
|
||||||
LOGIN_REDIRECT_URL = '/'
|
LOGIN_REDIRECT_URL = '/'
|
||||||
|
|
||||||
MEDIA_ROOT = os.path.abspath(os.path.join(ROOT_PATH, '..', 'media'))
|
MEDIA_ROOT = os.path.abspath(os.path.join(ROOT_PATH, '..', 'media'))
|
||||||
|
|||||||
Reference in New Issue
Block a user