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:
Tihomir Trifonov
2012-06-20 00:05:08 +03:00
parent 6174eae5ae
commit f0fe2029f3
5 changed files with 37 additions and 9 deletions

View File

@@ -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:

View File

@@ -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'))

View File

@@ -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',

View File

@@ -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 = [

View File

@@ -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'))