175 lines
6.6 KiB
Python
175 lines
6.6 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
# implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import logging
|
|
|
|
from threading import Thread
|
|
|
|
from django import shortcuts
|
|
from django.conf import settings
|
|
from django.contrib.auth import REDIRECT_FIELD_NAME
|
|
from django.contrib.auth.views import (login as django_login,
|
|
logout_then_login as django_logout)
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.views.decorators.debug import sensitive_post_parameters
|
|
from django.utils.functional import curry
|
|
from django.views.decorators.cache import never_cache
|
|
from django.views.decorators.csrf import csrf_protect
|
|
|
|
try:
|
|
from django.utils.http import is_safe_url
|
|
except ImportError:
|
|
from .utils import is_safe_url
|
|
|
|
from keystoneclient.v2_0 import client as keystone_client_v2
|
|
from keystoneclient import exceptions as keystone_exceptions
|
|
|
|
from .forms import Login
|
|
from .user import set_session_from_user, create_user_from_token, Token
|
|
from .utils import get_keystone_client
|
|
from .utils import get_keystone_version
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
@sensitive_post_parameters()
|
|
@csrf_protect
|
|
@never_cache
|
|
def login(request):
|
|
""" Logs a user in using the :class:`~openstack_auth.forms.Login` form. """
|
|
# Get our initial region for the form.
|
|
initial = {}
|
|
current_region = request.session.get('region_endpoint', None)
|
|
requested_region = request.GET.get('region', None)
|
|
regions = dict(getattr(settings, "AVAILABLE_REGIONS", []))
|
|
if requested_region in regions and requested_region != current_region:
|
|
initial.update({'region': requested_region})
|
|
|
|
if request.method == "POST":
|
|
form = curry(Login, request)
|
|
else:
|
|
form = curry(Login, initial=initial)
|
|
|
|
extra_context = {'redirect_field_name': REDIRECT_FIELD_NAME}
|
|
|
|
if request.is_ajax():
|
|
template_name = 'auth/_login.html'
|
|
extra_context['hide'] = True
|
|
else:
|
|
template_name = 'auth/login.html'
|
|
|
|
res = django_login(request,
|
|
template_name=template_name,
|
|
authentication_form=form,
|
|
extra_context=extra_context)
|
|
# Set the session data here because django's session key rotation
|
|
# will erase it if we set it earlier.
|
|
if request.user.is_authenticated():
|
|
set_session_from_user(request, request.user)
|
|
regions = dict(Login.get_region_choices())
|
|
region = request.user.endpoint
|
|
region_name = regions.get(region)
|
|
request.session['region_endpoint'] = region
|
|
request.session['region_name'] = region_name
|
|
return res
|
|
|
|
|
|
def logout(request):
|
|
msg = 'Logging out user "%(username)s".' % \
|
|
{'username': request.user.username}
|
|
LOG.info(msg)
|
|
if 'token_list' in request.session:
|
|
t = Thread(target=delete_all_tokens,
|
|
args=(list(request.session['token_list']),))
|
|
t.start()
|
|
""" Securely logs a user out. """
|
|
return django_logout(request)
|
|
|
|
|
|
def delete_all_tokens(token_list):
|
|
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
|
|
for token_tuple in token_list:
|
|
try:
|
|
endpoint = token_tuple[0]
|
|
token = token_tuple[1]
|
|
if get_keystone_version() < 3:
|
|
client = keystone_client_v2.Client(endpoint=endpoint,
|
|
token=token,
|
|
insecure=insecure,
|
|
debug=settings.DEBUG)
|
|
client.tokens.delete(token=token)
|
|
else:
|
|
# FIXME: KS-client does not have delete token available
|
|
# Need to add this later when it is exposed.
|
|
pass
|
|
except keystone_exceptions.ClientException as e:
|
|
LOG.info('Could not delete token')
|
|
|
|
|
|
@login_required
|
|
def switch(request, tenant_id, redirect_field_name=REDIRECT_FIELD_NAME):
|
|
""" Switches an authenticated user from one project to another. """
|
|
LOG.debug('Switching to tenant %s for user "%s".'
|
|
% (tenant_id, request.user.username))
|
|
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
|
|
endpoint = request.user.endpoint
|
|
try:
|
|
if get_keystone_version() >= 3:
|
|
endpoint = endpoint.replace('v2.0', 'v3')
|
|
|
|
client = get_keystone_client().Client(tenant_id=tenant_id,
|
|
token=request.user.token.id,
|
|
auth_url=endpoint,
|
|
insecure=insecure,
|
|
debug=settings.DEBUG)
|
|
auth_ref = client.auth_ref
|
|
msg = 'Project switch successful for user "%(username)s".' % \
|
|
{'username': request.user.username}
|
|
LOG.info(msg)
|
|
except keystone_exceptions.ClientException:
|
|
msg = 'Project switch failed for user "%(username)s".' % \
|
|
{'username': request.user.username}
|
|
LOG.warning(msg)
|
|
auth_ref = None
|
|
LOG.exception('An error occurred while switching sessions.')
|
|
|
|
# Ensure the user-originating redirection url is safe.
|
|
# Taken from django.contrib.auth.views.login()
|
|
redirect_to = request.REQUEST.get(redirect_field_name, '')
|
|
if not is_safe_url(url=redirect_to, host=request.get_host()):
|
|
redirect_to = settings.LOGIN_REDIRECT_URL
|
|
|
|
if auth_ref:
|
|
user = create_user_from_token(request, Token(auth_ref), endpoint)
|
|
set_session_from_user(request, user)
|
|
return shortcuts.redirect(redirect_to)
|
|
|
|
|
|
def switch_region(request, region_name,
|
|
redirect_field_name=REDIRECT_FIELD_NAME):
|
|
"""
|
|
Switches the non-identity services region that is being managed
|
|
for the scoped project.
|
|
"""
|
|
if region_name in request.user.available_services_regions:
|
|
request.session['services_region'] = region_name
|
|
LOG.debug('Switching services region to %s for user "%s".'
|
|
% (region_name, request.user.username))
|
|
|
|
redirect_to = request.REQUEST.get(redirect_field_name, '')
|
|
if not is_safe_url(url=redirect_to, host=request.get_host()):
|
|
redirect_to = settings.LOGIN_REDIRECT_URL
|
|
|
|
return shortcuts.redirect(redirect_to)
|