diff --git a/openstack_dashboard/api/keystone.py b/openstack_dashboard/api/keystone.py index ed22f24f0b..ea9adf45f8 100644 --- a/openstack_dashboard/api/keystone.py +++ b/openstack_dashboard/api/keystone.py @@ -163,6 +163,7 @@ def keystoneclient(request, admin=False): endpoint=endpoint, original_ip=remote_addr, insecure=insecure, + auth_url=endpoint, debug=settings.DEBUG) setattr(request, cache_attr, conn) return conn @@ -314,6 +315,15 @@ def user_update_password(request, user, password, admin=True): return manager.update(user, password=password) +def user_update_own_password(request, origpassword, password): + client = keystoneclient(request, admin=False) + if VERSIONS.active < 3: + client.user_id = request.user.id + return client.users.update_own_password(origpassword, password) + else: + return client.users.update(request.user.id, password=password) + + def user_update_tenant(request, user, project, admin=True): manager = keystoneclient(request, admin=admin).users if VERSIONS.active < 3: diff --git a/openstack_dashboard/dashboards/settings/dashboard.py b/openstack_dashboard/dashboards/settings/dashboard.py index cb2db2ddd1..15116f201e 100644 --- a/openstack_dashboard/dashboards/settings/dashboard.py +++ b/openstack_dashboard/dashboards/settings/dashboard.py @@ -23,7 +23,7 @@ import horizon class Settings(horizon.Dashboard): name = _("Settings") slug = "settings" - panels = ('user',) + panels = ('user', 'password', ) default_panel = 'user' nav = False diff --git a/openstack_dashboard/dashboards/settings/password/__init__.py b/openstack_dashboard/dashboards/settings/password/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openstack_dashboard/dashboards/settings/password/forms.py b/openstack_dashboard/dashboards/settings/password/forms.py new file mode 100644 index 0000000000..cbe3929435 --- /dev/null +++ b/openstack_dashboard/dashboards/settings/password/forms.py @@ -0,0 +1,68 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Centrin Data Systems Ltd. +# +# 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. + +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse +from django.forms import ValidationError +from django.views.decorators.debug import sensitive_variables + +from horizon import forms +from horizon import messages +from horizon import exceptions +from horizon.utils import validators +from openstack_dashboard import api + + +class PasswordForm(forms.SelfHandlingForm): + current_password = forms.CharField(label=_("Current password"), + widget=forms.PasswordInput(render_value=False)) + new_password = forms.RegexField(label=_("New password"), + widget=forms.PasswordInput(render_value=False), + regex=validators.password_validator(), + error_messages={'invalid': + validators.password_validator_msg()}) + confirm_password = forms.CharField(label=_("Confirm new password"), + widget=forms.PasswordInput(render_value=False)) + + def clean(self): + '''Check to make sure password fields match.''' + data = super(forms.Form, self).clean() + if 'new_password' in data: + if data['new_password'] != data.get('confirm_password', None): + raise ValidationError(_('Passwords do not match.')) + return data + + # We have to protect the entire "data" dict because it contains the + # oldpassword and newpassword strings. + @sensitive_variables('data') + def handle(self, request, data): + user_is_editable = api.keystone.keystone_can_edit_user() + + if user_is_editable: + try: + passwd = api.keystone.user_update_own_password(request, + data['current_password'], + data['new_password']) + messages.success(request, _('Password changed.')) + except: + exceptions.handle(request, + _('Unable to change password.')) + return False + else: + messages.error(request, _('Changing password is not supported.')) + return False + + return True diff --git a/openstack_dashboard/dashboards/settings/password/panel.py b/openstack_dashboard/dashboards/settings/password/panel.py new file mode 100644 index 0000000000..c9aba34512 --- /dev/null +++ b/openstack_dashboard/dashboards/settings/password/panel.py @@ -0,0 +1,29 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Centrin Data Systems Ltd. +# +# 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. + +from django.utils.translation import ugettext_lazy as _ + +import horizon + +from openstack_dashboard.dashboards.settings import dashboard + + +class PasswordPanel(horizon.Panel): + name = _("Change Password") + slug = 'password' + + +dashboard.Settings.register(PasswordPanel) diff --git a/openstack_dashboard/dashboards/settings/password/templates/password/_change.html b/openstack_dashboard/dashboards/settings/password/templates/password/_change.html new file mode 100644 index 0000000000..7c258cdebf --- /dev/null +++ b/openstack_dashboard/dashboards/settings/password/templates/password/_change.html @@ -0,0 +1,27 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} +{% load url from future %} + +{% block form_id %}change_password_modal{% endblock %} +{% block form_action %}{% url 'horizon:settings:password:index' %}{% endblock %} + +{% block modal_id %}change_password_modal{% endblock %} +{% block modal-header %}{% trans "Change Password" %}{% endblock %} + +{% block modal-body %} +
{% trans "From here you can change your password. We highly recommend you create a strong one. " %}
+