Allow to specify redirections on single IdP scenarios

In scenarios where the cloud operators have only a single Identity Provider,
we can have a default redirection to remove unnecessary user clicks and
improve user experience.

Closes-bug: #1784368

Change-Id: I251703dcaeac43174fbcba7e0658c6f92098b2e0
This commit is contained in:
Jose Castro Leon 2018-07-27 15:59:47 +02:00
parent a4443f4be7
commit 7fc8018956
9 changed files with 163 additions and 6 deletions

View File

@ -1522,6 +1522,49 @@ Default: ``"credentials"``
Specifies the default authentication mechanism. When user lands on the login
page, this is the first choice they will see.
WEBSSO_DEFAULT_REDIRECT
~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 15.0.0(Stein)
Default: ``False``
Allows to redirect on login to the IdP provider defined on PROTOCOL and REGION
In cases you have a single IdP providing websso, in order to improve user
experience, you can redirect on the login page to the IdP directly by
specifying WEBSSO_DEFAULT_REDIRECT_PROTOCOL and WEBSSO_DEFAULT_REDIRECT_REGION
variables.
WEBSSO_DEFAULT_REDIRECT_PROTOCOL
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 15.0.0(Stein)
Default: ``None``
Allows to specify the protocol for the IdP to contact if the
WEBSSO_DEFAULT_REDIRECT is set to True
WEBSSO_DEFAULT_REDIRECT_REGION
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 15.0.0(Stein)
Default: ``OPENSTACK_KEYSTONE_URL``
Allows to specify thee region of the IdP to contact if the
WEBSSO_DEFAULT_REDIRECT is set to True
WEBSSO_DEFAULT_REDIRECT_LOGOUT
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 15.0.0(Stein)
Default: ``None``
Allows to specify a callback to the IdP to cleanup the SSO resources.
Once the user logs out it will redirect to the IdP log out method.
Neutron
-------

View File

@ -1237,4 +1237,33 @@ class OpenStackAuthTestsWebSSO(OpenStackAuthTestsMixin,
response = self.client.post(url, form_data)
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
def test_websso_login_default_redirect(self):
origin = 'http://testserver/auth/websso/'
protocol = 'oidc'
redirect_url = ('%s/auth/OS-FEDERATION/websso/%s?origin=%s' %
(settings.OPENSTACK_KEYSTONE_URL, protocol, origin))
settings.WEBSSO_DEFAULT_REDIRECT = True
settings.WEBSSO_DEFAULT_REDIRECT_PROTOCOL = 'oidc'
settings.WEBSSO_DEFAULT_REDIRECT_REGION = (
settings.OPENSTACK_KEYSTONE_URL)
url = reverse('login')
# POST to the page and redirect to keystone.
response = self.client.get(url)
self.assertRedirects(response, redirect_url, status_code=302,
target_status_code=404)
def test_websso_logout_default_redirect(self):
settings.WEBSSO_DEFAULT_REDIRECT = True
settings.WEBSSO_DEFAULT_REDIRECT_LOGOUT = 'http://idptest/logout'
url = reverse('logout')
# POST to the page and redirect to logout method from idp.
response = self.client.get(url)
self.assertRedirects(response, settings.WEBSSO_DEFAULT_REDIRECT_LOGOUT,
status_code=302, target_status_code=301)
load_tests = load_tests_apply_scenarios

View File

@ -12,6 +12,7 @@
# limitations under the License.
from django.conf.urls import url
from django.views import generic
from openstack_auth import utils
from openstack_auth import views
@ -33,4 +34,8 @@ urlpatterns = [
]
if utils.is_websso_enabled():
urlpatterns.append(url(r"^websso/$", views.websso, name='websso'))
urlpatterns += [
url(r"^websso/$", views.websso, name='websso'),
url(r"^error/$",
generic.TemplateView.as_view(template_name="403.html"))
]

View File

@ -38,6 +38,16 @@ def set_session_from_user(request, user):
request.user = user
def unset_session_user_variables(request):
request.session['token'] = None
request.session['user_id'] = None
request.session['region_endpoint'] = None
request.session['services_region'] = None
# Update the user object cached in the request
request._cached_user = None
request.user = None
def create_user_from_token(request, token, endpoint, services_region=None):
# if the region is provided, use that, otherwise use the preferred region
svc_region = services_region or \

View File

@ -146,6 +146,30 @@ def is_websso_enabled():
return websso_enabled and keystonev3_plus
def is_websso_default_redirect():
"""Checks if the websso default redirect is available.
As with websso, this is only supported in Keystone version 3.
"""
websso_default_redirect = getattr(settings,
'WEBSSO_DEFAULT_REDIRECT', False)
keystonev3_plus = (get_keystone_version() >= 3)
return websso_default_redirect and keystonev3_plus
def get_websso_default_redirect_protocol():
return getattr(settings, 'WEBSSO_DEFAULT_REDIRECT_PROTOCOL', None)
def get_websso_default_redirect_region():
return getattr(settings, 'WEBSSO_DEFAULT_REDIRECT_REGION',
settings.OPENSTACK_KEYSTONE_URL)
def get_websso_default_redirect_logout():
return getattr(settings, 'WEBSSO_DEFAULT_REDIRECT_LOGOUT', None)
def build_absolute_uri(request, relative_url):
"""Ensure absolute_uri are relative to WEBROOT."""
webroot = getattr(settings, 'WEBROOT', '')

View File

@ -55,6 +55,17 @@ LOG = logging.getLogger(__name__)
def login(request, template_name=None, extra_context=None, **kwargs):
"""Logs a user in using the :class:`~openstack_auth.forms.Login` form."""
# If the user enabled websso and the default redirect
# redirect to the default websso url
if (request.method == 'GET' and utils.is_websso_enabled and
utils.is_websso_default_redirect()):
protocol = utils.get_websso_default_redirect_protocol()
region = utils.get_websso_default_redirect_region()
origin = request.build_absolute_uri('/auth/websso/')
url = ('%s/auth/OS-FEDERATION/websso/%s?origin=%s' %
(region, protocol, origin))
return shortcuts.redirect(url)
# If the user enabled websso and selects default protocol
# from the dropdown, We need to redirect user to the websso url
if request.method == 'POST':
@ -151,9 +162,12 @@ def websso(request):
request.user = auth.authenticate(request=request, auth_url=auth_url,
token=token)
except exceptions.KeystoneAuthException as exc:
msg = 'Login failed: %s' % six.text_type(exc)
res = django_http.HttpResponseRedirect(settings.LOGIN_URL)
res.set_cookie('logout_reason', msg, max_age=10)
if utils.is_websso_default_redirect():
res = django_http.HttpResponseRedirect(settings.LOGIN_ERROR)
else:
msg = 'Login failed: %s' % six.text_type(exc)
res = django_http.HttpResponseRedirect(settings.LOGIN_URL)
res.set_cookie('logout_reason', msg, max_age=10)
return res
auth_user.set_session_from_user(request, request.user)
@ -178,8 +192,15 @@ def logout(request, login_url=None, **kwargs):
LOG.info(msg)
""" Securely logs a user out. """
return django_auth_views.logout_then_login(request, login_url=login_url,
**kwargs)
if (utils.is_websso_enabled and utils.is_websso_default_redirect() and
utils.get_websso_default_redirect_logout()):
auth_user.unset_session_user_variables(request)
return django_http.HttpResponseRedirect(
utils.get_websso_default_redirect_logout())
else:
return django_auth_views.logout_then_login(request,
login_url=login_url,
**kwargs)
@login_required

View File

@ -26,6 +26,7 @@ DEBUG = True
WEBROOT = '/'
#LOGIN_URL = WEBROOT + 'auth/login/'
#LOGOUT_URL = WEBROOT + 'auth/logout/'
#LOGIN_ERROR = WEBROOT + 'auth/error/'
#
# LOGIN_REDIRECT_URL can be used as an alternative for
# HORIZON_CONFIG.user_home, if user_home is not set.
@ -231,6 +232,21 @@ OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_"
# "acme_saml2": ("acme", "saml2"),
#}
# Enables redirection on login to the identity provider defined on
# WEBSSO_DEFAULT_REDIRECT_PROTOCOL and WEBSSO_DEFAULT_REDIRECT_REGION
#WEBSSO_DEFAULT_REDIRECT = False
# Specifies the protocol to use for default redirection on login
#WEBSSO_DEFAULT_REDIRECT_PROTOCOL = None
# Specifies the region to which the connection will be established on login
#WEBSSO_DEFAULT_REDIRECT_REGION = OPENSTACK_KEYSTONE_URL
# Enables redirection on logout to the method specified on the identity provider.
# Once logout the client will be redirected to the address specified in this
# variable.
#WEBSSO_DEFAULT_REDIRECT_LOGOUT = None
# The Keystone Provider drop down uses Keystone to Keystone federation
# to switch between Keystone service providers.
# Set display name for Identity Provider (dropdown display name)

View File

@ -54,6 +54,7 @@ SITE_BRANDING = 'OpenStack Dashboard'
WEBROOT = '/'
LOGIN_URL = None
LOGOUT_URL = None
LOGIN_ERROR = None
LOGIN_REDIRECT_URL = None
MEDIA_ROOT = None
MEDIA_URL = None
@ -418,6 +419,8 @@ if LOGIN_URL is None:
LOGIN_URL = WEBROOT + 'auth/login/'
if LOGOUT_URL is None:
LOGOUT_URL = WEBROOT + 'auth/logout/'
if LOGIN_ERROR is None:
LOGIN_ERROR = WEBROOT + 'auth/error/'
if LOGIN_REDIRECT_URL is None:
LOGIN_REDIRECT_URL = WEBROOT

View File

@ -0,0 +1,6 @@
---
features:
- Adds the possibility to redirect the login to an identity provider by
default. For that purpose the following variables have been added,
``WEBSSO_DEFAULT_REDIRECT``, ``WEBSSO_DEFAULT_REDIRECT_PROTOCOL``,
``WEBSSO_DEFAULT_REDIRECT_REGION`` and ``WEBSSO_DEFAULT_REDIRECT_LOGOUT``.