diff options
Diffstat (limited to 'horizon/horizon/views/auth_forms.py')
-rw-r--r-- | horizon/horizon/views/auth_forms.py | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/horizon/horizon/views/auth_forms.py b/horizon/horizon/views/auth_forms.py new file mode 100644 index 00000000..7664b694 --- /dev/null +++ b/horizon/horizon/views/auth_forms.py @@ -0,0 +1,141 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# Copyright 2011 Nebula, Inc. +# +# 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. + +""" +Forms used for Horizon's auth mechanisms. +""" + +import logging + +from django import shortcuts +from django.contrib import messages +from django.utils.translation import ugettext as _ +from openstackx.api import exceptions as api_exceptions + +from horizon import api +from horizon import base +from horizon import exceptions +from horizon import forms +from horizon import users + + +LOG = logging.getLogger(__name__) + + +def _set_session_data(request, token): + request.session['serviceCatalog'] = token.serviceCatalog + request.session['tenant'] = token.tenant['name'] + request.session['tenant_id'] = token.tenant['id'] + request.session['token'] = token.id + request.session['user'] = token.user['name'] + request.session['roles'] = token.user['roles'] + + +class Login(forms.SelfHandlingForm): + """ Form used for logging in a user. + + Handles authentication with Keystone, choosing a tenant, and fetching + a scoped token token for that tenant. Redirects to the URL returned + by :meth:`horizon.get_user_home` if successful. + + Subclass of :class:`~horizon.forms.SelfHandlingForm`. + """ + username = forms.CharField(max_length="20", label=_("User Name")) + password = forms.CharField(max_length="20", label=_("Password"), + widget=forms.PasswordInput(render_value=False)) + + def handle(self, request, data): + try: + if data.get('tenant', None): + token = api.token_create(request, + data.get('tenant'), + data['username'], + data['password']) + + tenants = api.tenant_list_for_token(request, token.id) + tenant = None + for t in tenants: + if t.id == data.get('tenant'): + tenant = t + _set_session_data(request, token) + user = users.get_user_from_request(request) + return shortcuts.redirect(base.Horizon.get_user_home(user)) + + elif data.get('username', None): + token = api.token_create(request, + '', + data['username'], + data['password']) + + # Unscoped token + request.session['unscoped_token'] = token.id + request.user.username = data['username'] + + # Get the tenant list, and log in using first tenant + # FIXME (anthony): add tenant chooser here? + tenants = api.tenant_list_for_token(request, token.id) + + # Abort if there are no valid tenants for this user + if not tenants: + messages.error(request, + _('No tenants present for user: %(user)s') % + {"user": data['username']}) + return + + # Create a token. + # NOTE(gabriel): Keystone can return tenants that you're + # authorized to administer but not to log into as a user, so in + # the case of an Unauthorized error we should iterate through + # the tenants until one succeeds or we've failed them all. + while tenants: + tenant = tenants.pop() + try: + token = api.token_create_scoped(request, + tenant.id, + token.id) + break + except api_exceptions.Unauthorized as e: + token = None + if token is None: + raise exceptions.NotAuthorized( + _("You are not authorized for any available tenants.")) + + _set_session_data(request, token) + user = users.get_user_from_request(request) + return shortcuts.redirect(base.Horizon.get_user_home(user)) + + except api_exceptions.Unauthorized as e: + msg = _('Error authenticating: %s') % e.message + LOG.exception(msg) + messages.error(request, msg) + except api_exceptions.ApiException as e: + messages.error(request, + _('Error authenticating with keystone: %s') % + e.message) + + +class LoginWithTenant(Login): + """ + Exactly like :class:`.Login` but includes the tenant id as a field + so that the process of choosing a default tenant is bypassed. + """ + username = forms.CharField(max_length="20", + widget=forms.TextInput(attrs={'readonly': 'readonly'})) + tenant = forms.CharField(widget=forms.HiddenInput()) |