Added a modal dialog with the user credentials details

The modal contains all the credentials used to access the user's
openstack and EC2 instance.

Change-Id: I750b2922a34dd06b2098eff95d817c852a18be07
Implements: blueprint api-access-page-enhancements
Co-Authored-By: Cédric Soulas <cedric.soulas@cloudwatt.com>
This commit is contained in:
George Peristerakis 2014-06-12 10:41:39 -04:00
parent c88e944b97
commit aa3dc6b30b
8 changed files with 182 additions and 49 deletions

View File

@ -48,6 +48,14 @@ class DownloadOpenRC(tables.LinkAction):
url = "horizon:project:access_and_security:api_access:openrc"
class ViewCredentials(tables.LinkAction):
name = "view_credentials"
verbose_name = _("View Credentials")
classes = ("ajax-modal", )
icon = "plus"
url = "horizon:project:access_and_security:api_access:view_credentials"
class EndpointsTable(tables.DataTable):
api_name = tables.Column('type',
verbose_name=_("Service"),
@ -59,4 +67,4 @@ class EndpointsTable(tables.DataTable):
name = "endpoints"
verbose_name = _("API Endpoints")
multi_select = False
table_actions = (DownloadOpenRC, DownloadEC2,)
table_actions = (DownloadOpenRC, DownloadEC2, ViewCredentials)

View File

@ -21,7 +21,10 @@ from openstack_dashboard import api
from openstack_dashboard.test import helpers as test
EC2_URL = reverse("horizon:project:access_and_security:api_access:ec2")
API_URL = "horizon:project:access_and_security:api_access"
EC2_URL = reverse(API_URL + ":ec2")
OPENRC_URL = reverse(API_URL + ":openrc")
CREDS_URL = reverse(API_URL + ":view_credentials")
class APIAccessTests(test.TestCase):
@ -47,3 +50,29 @@ class APIAccessTests(test.TestCase):
res = self.client.get(EC2_URL)
self.assertEqual(res.status_code, 200)
self.assertEqual(res['content-type'], 'application/zip')
def test_openrc_credentials(self):
res = self.client.get(OPENRC_URL)
self.assertEqual(res.status_code, 200)
openrc = 'project/access_and_security/api_access/openrc.sh.template'
self.assertTemplateUsed(res, openrc)
name = 'export OS_USERNAME="{}"'.format(self.request.user.username)
id = 'export OS_TENANT_ID={}'.format(self.request.user.tenant_id)
self.assertTrue(name in res.content)
self.assertTrue(id in res.content)
@test.create_stubs({api.keystone: ("list_ec2_credentials",)})
def test_credential_api(self):
certs = self.ec2.list()
api.keystone.list_ec2_credentials(IsA(HttpRequest), self.user.id) \
.AndReturn(certs)
self.mox.ReplayAll()
res = self.client.get(CREDS_URL)
self.assertEqual(res.status_code, 200)
credentials = 'project/access_and_security/api_access/credentials.html'
self.assertTemplateUsed(res, credentials)
self.assertEqual(self.user.id, res.context['openrc_creds']['user'].id)
self.assertEqual(certs[0].access,
res.context['ec2_creds']['ec2_access_key'])

View File

@ -27,4 +27,6 @@ urlpatterns = patterns(
'',
url(r'^ec2/$', views.download_ec2_bundle, name='ec2'),
url(r'^openrc/$', views.download_rc_file, name='openrc'),
url(r'^view_credentials/$', views.CredentialsView.as_view(),
name='view_credentials')
)

View File

@ -21,8 +21,10 @@ from django import http
from django import shortcuts
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _
from django.views import generic
from horizon import exceptions
from horizon import forms
from horizon import messages
from openstack_dashboard import api
@ -31,31 +33,16 @@ from openstack_dashboard import api
LOG = logging.getLogger(__name__)
def download_ec2_bundle(request):
def _get_ec2_credentials(request):
tenant_id = request.user.tenant_id
tenant_name = request.user.tenant_name
all_keys = api.keystone.list_ec2_credentials(request,
request.user.id)
# Gather or create our EC2 credentials
try:
credentials = api.nova.get_x509_credentials(request)
cacert = api.nova.get_x509_root_certificate(request)
all_keys = api.keystone.list_ec2_credentials(request,
request.user.id)
keys = None
for key in all_keys:
if key.tenant_id == tenant_id:
keys = key
if keys is None:
keys = api.keystone.create_ec2_credentials(request,
request.user.id,
tenant_id)
except Exception:
exceptions.handle(request,
_('Unable to fetch EC2 credentials.'),
redirect=request.build_absolute_uri())
# Get our S3 endpoint if it exists
key = next((x for x in all_keys if x.tenant_id == tenant_id), None)
if not key:
key = api.keystone.create_ec2_credentials(request,
request.user.id,
tenant_id)
try:
s3_endpoint = api.base.url_for(request,
's3',
@ -63,7 +50,6 @@ def download_ec2_bundle(request):
except exceptions.ServiceCatalogException:
s3_endpoint = None
# Get our EC2 endpoint (it should exist since we just got creds for it)
try:
ec2_endpoint = api.base.url_for(request,
'ec2',
@ -71,11 +57,36 @@ def download_ec2_bundle(request):
except exceptions.ServiceCatalogException:
ec2_endpoint = None
# Build the context
context = {'ec2_access_key': keys.access,
'ec2_secret_key': keys.secret,
'ec2_endpoint': ec2_endpoint,
's3_endpoint': s3_endpoint}
return {'ec2_access_key': key.access,
'ec2_secret_key': key.secret,
'ec2_endpoint': ec2_endpoint,
's3_endpoint': s3_endpoint}
def _get_openrc_credentials(request):
keystone_url = api.base.url_for(request,
'identity',
endpoint_type='publicURL')
credentials = dict(tenant_id=request.user.tenant_id,
tenant_name=request.user.tenant_name,
auth_url=keystone_url,
user=request.user,
region=getattr(request.user, 'services_region') or "")
return credentials
def download_ec2_bundle(request):
tenant_name = request.user.tenant_name
# Gather or create our EC2 credentials
try:
credentials = api.nova.get_x509_credentials(request)
cacert = api.nova.get_x509_root_certificate(request)
context = _get_ec2_credentials(request)
except Exception:
exceptions.handle(request,
_('Unable to fetch EC2 credentials.'),
redirect=request.build_absolute_uri())
# Create our file bundle
template = 'project/access_and_security/api_access/ec2rc.sh.template'
@ -102,24 +113,9 @@ def download_ec2_bundle(request):
def download_rc_file(request):
tenant_id = request.user.tenant_id
tenant_name = request.user.tenant_name
region = request.user.services_region
if region is None:
region = ""
template = 'project/access_and_security/api_access/openrc.sh.template'
try:
keystone_url = api.base.url_for(request,
'identity',
endpoint_type='publicURL')
context = {'user': request.user,
'auth_url': keystone_url,
'tenant_id': tenant_id,
'tenant_name': tenant_name,
'region': region}
context = _get_openrc_credentials(request)
response = shortcuts.render(request,
template,
@ -127,7 +123,7 @@ def download_rc_file(request):
content_type="text/plain")
response['Content-Disposition'] = ('attachment; '
'filename="%s-openrc.sh"'
% tenant_name)
% context['tenant_name'])
response['Content-Length'] = str(len(response.content))
return response
@ -135,3 +131,22 @@ def download_rc_file(request):
LOG.exception("Exception in DownloadOpenRCForm.")
messages.error(request, _('Error Downloading RC File: %s') % e)
return shortcuts.redirect(request.build_absolute_uri())
class CredentialsView(forms.ModalFormMixin, generic.TemplateView):
template_name = 'project/access_and_security/api_access/credentials.html'
def get_context_data(self, **kwargs):
context = super(CredentialsView, self).get_context_data(**kwargs)
try:
context['openrc_creds'] = _get_openrc_credentials(self.request)
except Exception:
exceptions.handle(self.request,
_('Unable to get openrc credentials'))
if api.base.is_service_enabled(self.request, 'ec2'):
try:
context['ec2_creds'] = _get_ec2_credentials(self.request)
except Exception:
exceptions.handle(self.request,
_('Unable to get EC2 credentials'))
return context

View File

@ -0,0 +1,62 @@
{% extends "horizon/common/_modal.html" %}
{% load i18n %}
{% load url from future %}
{% block modal-header %}{% trans "User Credentials" %}{% endblock %}
{% block modal-body %}
<div class="row-fluid view-credentials">
<form>
{% if openrc_creds %}
<div class="left">
<fieldset>
<div class="form-group">
<label class="control-label">{% trans "User Name" %}</label>
<input type="text" class="form-control" readonly value="{{ openrc_creds.user }}">
</div>
<div class="form-group">
<label class="control-label">{% trans "Project Name" %}</label>
<input type="text" class="form-control" readonly value="{{ openrc_creds.tenant_name }}">
</div>
<div class="form-group">
<label class="control-label">{% trans "Project ID" %}</label>
<input type="text" class="form-control" readonly value="{{ openrc_creds.tenant_id }}">
</div>
<div class="form-group">
<label class="control-label">{% trans "Authentication URL" %}</label>
<input type="text" class="form-control" readonly value="{{ openrc_creds.auth_url }}">
</div>
</fieldset>
</div>
{% endif %}
{% if ec2_creds %}
<div class="right">
<fieldset>
<div class="form-group">
<label class="control-label">{% trans "EC2 URL" %}</label><input type="text" class="form-control" readonly value="{{ ec2_creds.ec2_endpoint }}">
</div>
<div class="form-group">
<label class="control-label">{% trans "S3 URL" %}</label><input type="text" class="form-control" readonly value="{{ ec2_creds.s3_endpoint }}">
</div>
{% if ec2_creds.ec2_access_key %}
<div class="form-group">
<label class="control-label">{% trans "EC2 Access Key" %}</label>
<input type="text" class="form-control" readonly value="{{ ec2_creds.ec2_access_key }}">
</div>
{% endif %}
{% if ec2_creds.ec2_secret_key %}
<div class="form-group">
<label class="control-label">{% trans "EC2 Secret Key" %}</label>
<input type="password" class="form-control" readonly value="{{ ec2_creds.ec2_secret_key }}">
</div>
{% endif %}
</fieldset>
</div>
{% endif %}
</form>
</div>
{% endblock %}
{% block modal-footer %}
<a href="{% url 'horizon:project:access_and_security:index' %}" class="btn btn-default secondary cancel close">{% trans "Close" %}</a>
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "User Credentials" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("User Credentials Details") %}
{% endblock page_header %}
{% block main %}
{% include 'project/access_and_security/api_access/_credentials.html' %}
{% endblock %}

View File

@ -2196,6 +2196,11 @@ label.log-length {
}
}
/* Read only text fields */
.form-control[readonly], .view-credentials input {
cursor: text;
}
/**** Popover ****/
a.link-popover { cursor: default; }

View File

@ -364,5 +364,6 @@ def data(TEST):
TEST.tokens.unscoped_token = unscoped_token
access_secret = ec2.EC2(ec2.CredentialsManager, {"access": "access",
"secret": "secret"})
"secret": "secret",
"tenant_id": tenant.id})
TEST.ec2.add(access_secret)