Add function to recreate ec2 credential

At the moment, we can view the credentials of ec2 in Horizon.
But we can not delete or update it.
When information of access key and secret key were leaked out,
it would be nice if we can regenerate a credentials via not only
CLI but also Horizon.

Thus we need to provide a function user can change ec2
credentials when user want to do it.

Change-Id: Ibaebad73eb9a869564bd7d52e2f6b69a503a60c3
Closes-Bug: #1519764
This commit is contained in:
kenji-ishii 2015-12-02 22:50:53 +09:00 committed by Kenji Ishii
parent 8cade6356e
commit a9e9d715bb
9 changed files with 170 additions and 3 deletions

View File

@ -715,6 +715,10 @@ def get_user_ec2_credentials(request, user_id, access_token):
return ec2_manager(request).get(user_id, access_token)
def delete_user_ec2_credentials(request, user_id, access_token):
return ec2_manager(request).delete(user_id, access_token)
def keystone_can_edit_domain():
backend_settings = getattr(settings, "OPENSTACK_KEYSTONE_BACKEND", {})
can_edit_domain = backend_settings.get('can_edit_domain', True)

View File

@ -0,0 +1,68 @@
# Copyright 2016 NEC Corporation
#
# 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 horizon import exceptions
from horizon import forms
from horizon import messages
from openstack_dashboard import api
from openstack_dashboard import policy
def get_ec2_credentials(request):
if not policy.check((("identity", "identity:ec2_list_credentials"),),
request):
return None
project_id = request.user.project_id
all_keys = api.keystone.list_ec2_credentials(request,
request.user.id)
keys = [x for x in all_keys if x.tenant_id == project_id]
if not keys:
return None
return {'ec2_access_key': keys[0].access,
'ec2_secret_key': keys[0].secret}
class RecreateCredentials(forms.SelfHandlingForm):
def handle(self, request, context):
try:
credential = get_ec2_credentials(request)
if credential:
api.keystone.delete_user_ec2_credentials(
request,
request.user.id,
credential['ec2_access_key'])
except Exception:
exceptions.handle(
request, _('Unable to recreate ec2 credentials. '
'Failed to delete ec2 credentials.'))
return False
try:
api.keystone.create_ec2_credentials(
request,
request.user.id,
request.user.project_id)
message = _('Successfully recreated ec2 credentials.')
messages.success(request, message)
return True
except Exception:
exceptions.handle(
request, _('Unable to recreate ec2 credentials. '
'Failed to create ec2 credentials.'))
return False

View File

@ -19,6 +19,9 @@ from openstack_auth import utils
from horizon import tables
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.access_and_security.api_access \
import forms as project_forms
from openstack_dashboard import policy
def pretty_service_names(name):
@ -69,6 +72,29 @@ class ViewCredentials(tables.LinkAction):
url = "horizon:project:access_and_security:api_access:view_credentials"
class RecreateCredentials(tables.LinkAction):
name = "recreate_credentials"
verbose_name = _("Recreate EC2 Credentials")
classes = ("ajax-modal", "btn-danger")
icon = "refresh"
url = \
"horizon:project:access_and_security:api_access:recreate_credentials"
policy_rules = (("compute", "compute_extension:certificates"))
def allowed(self, request, datum=None):
try:
target = {"target.credential.user_id": request.user.id}
if (api.base.is_service_enabled(request, 'ec2') and
project_forms.get_ec2_credentials(request) and
policy.check((("identity", "identity:ec2_create_credential"),
("identity", "identity:ec2_delete_credential")),
request, target=target)):
return True
except Exception:
pass
return False
class EndpointsTable(tables.DataTable):
api_name = tables.Column('type',
verbose_name=_("Service"),
@ -81,4 +107,4 @@ class EndpointsTable(tables.DataTable):
verbose_name = _("API Endpoints")
multi_select = False
table_actions = (DownloadOpenRCv2, DownloadOpenRC, DownloadEC2,
ViewCredentials)
ViewCredentials, RecreateCredentials)

View File

@ -22,11 +22,13 @@ from openstack_dashboard import api
from openstack_dashboard.test import helpers as test
INDEX_URL = reverse('horizon:project:access_and_security:index')
API_URL = "horizon:project:access_and_security:api_access"
EC2_URL = reverse(API_URL + ":ec2")
OPENRC_URL = reverse(API_URL + ":openrc")
OPENRCV2_URL = reverse(API_URL + ":openrcv2")
CREDS_URL = reverse(API_URL + ":view_credentials")
RECREATE_CREDS_URL = reverse(API_URL + ":recreate_credentials")
class APIAccessTests(test.TestCase):
@ -96,3 +98,40 @@ class APIAccessTests(test.TestCase):
self.assertEqual(self.user.id, res.context['openrc_creds']['user'].id)
self.assertEqual(certs[0].access,
res.context['ec2_creds']['ec2_access_key'])
@test.create_stubs({api.keystone: ("list_ec2_credentials",
"create_ec2_credentials",
"delete_user_ec2_credentials",)})
def _test_recreate_user_credentials(self, exists_credentials=True):
old_creds = self.ec2.list() if exists_credentials else []
new_creds = self.ec2.first()
api.keystone.list_ec2_credentials(
IsA(HttpRequest),
self.user.id).AndReturn(old_creds)
if exists_credentials:
api.keystone.delete_user_ec2_credentials(
IsA(HttpRequest),
self.user.id,
old_creds[0].access).AndReturn([])
api.keystone.create_ec2_credentials(
IsA(HttpRequest),
self.user.id,
self.tenant.id).AndReturn(new_creds)
self.mox.ReplayAll()
res_get = self.client.get(RECREATE_CREDS_URL)
self.assertEqual(res_get.status_code, 200)
credentials = \
'project/access_and_security/api_access/recreate_credentials.html'
self.assertTemplateUsed(res_get, credentials)
res_post = self.client.post(RECREATE_CREDS_URL)
self.assertNoFormErrors(res_post)
self.assertRedirectsNoFollow(res_post, INDEX_URL)
def test_recreate_user_credentials(self):
self._test_recreate_user_credentials()
def test_recreate_user_credentials_with_no_existing_creds(self):
self._test_recreate_user_credentials(exists_credentials=False)

View File

@ -29,5 +29,7 @@ urlpatterns = patterns(
url(r'^openrc/$', views.download_rc_file, name='openrc'),
url(r'^openrcv2/$', views.download_rc_file_v2, name='openrcv2'),
url(r'^view_credentials/$', views.CredentialsView.as_view(),
name='view_credentials')
name='view_credentials'),
url(r'^recreate_ec2_credentials/$',
views.RecreateCredentialsView.as_view(), name='recreate_credentials'),
)

View File

@ -17,6 +17,7 @@ import logging
import tempfile
import zipfile
from django.core.urlresolvers import reverse_lazy
from django import http
from django import shortcuts
from django.template.loader import render_to_string
@ -30,7 +31,8 @@ from horizon import messages
from horizon import views
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.access_and_security.api_access \
import forms as project_forms
LOG = logging.getLogger(__name__)
@ -167,3 +169,15 @@ class CredentialsView(forms.ModalFormMixin, views.HorizonTemplateView):
exceptions.handle(self.request,
_('Unable to get EC2 credentials'))
return context
class RecreateCredentialsView(forms.ModalFormView):
form_class = project_forms.RecreateCredentials
form_id = "recreate_credentials"
modal_header = _("Recreate EC2 Credentials")
template_name = \
'project/access_and_security/api_access/recreate_credentials.html'
submit_label = _("Recreate EC2 Credentials")
submit_url = reverse_lazy(
"horizon:project:access_and_security:api_access:recreate_credentials")
success_url = reverse_lazy('horizon:project:access_and_security:index')

View File

@ -0,0 +1,6 @@
{% extends "horizon/common/_modal_form.html" %}
{% load i18n %}
{% block modal-body %}
{% trans "This action cannot be undone. Current EC2 credentials will be deleted and not recoverable." %}
{% endblock %}

View File

@ -0,0 +1,7 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Recreate EC2 Credentials" %}{% endblock %}
{% block main %}
{% include 'project/access_and_security/api_access/_recreate_credentials.html' %}
{% endblock %}

View File

@ -46,6 +46,7 @@ $icon-swap: (
plus: 'plus',
question-circle: 'help-circle',
random: 'shuffle',
refresh: 'refresh',
remove: 'close',
save: 'floppy',
search: 'magnify',