Add basic CRUD for federation mapping
Change-Id: Ie3991efda6d2437821f67e3c87e111886578e830 Partially-Implements: blueprint keystone-federation-mapping
This commit is contained in:
parent
78bfa9727d
commit
fbf10e9dad
@ -795,3 +795,31 @@ def identity_provider_delete(request, idp_id):
|
|||||||
def identity_provider_list(request):
|
def identity_provider_list(request):
|
||||||
manager = keystoneclient(request, admin=True).federation.identity_providers
|
manager = keystoneclient(request, admin=True).federation.identity_providers
|
||||||
return manager.list()
|
return manager.list()
|
||||||
|
|
||||||
|
|
||||||
|
def mapping_create(request, mapping_id, rules):
|
||||||
|
manager = keystoneclient(request, admin=True).federation.mappings
|
||||||
|
try:
|
||||||
|
return manager.create(mapping_id=mapping_id, rules=rules)
|
||||||
|
except keystone_exceptions.Conflict:
|
||||||
|
raise exceptions.Conflict()
|
||||||
|
|
||||||
|
|
||||||
|
def mapping_get(request, mapping_id):
|
||||||
|
manager = keystoneclient(request, admin=True).federation.mappings
|
||||||
|
return manager.get(mapping_id)
|
||||||
|
|
||||||
|
|
||||||
|
def mapping_update(request, mapping_id, rules):
|
||||||
|
manager = keystoneclient(request, admin=True).federation.mappings
|
||||||
|
return manager.update(mapping_id, rules=rules)
|
||||||
|
|
||||||
|
|
||||||
|
def mapping_delete(request, mapping_id):
|
||||||
|
manager = keystoneclient(request, admin=True).federation.mappings
|
||||||
|
return manager.delete(mapping_id)
|
||||||
|
|
||||||
|
|
||||||
|
def mapping_list(request):
|
||||||
|
manager = keystoneclient(request, admin=True).federation.mappings
|
||||||
|
return manager.list()
|
||||||
|
86
openstack_dashboard/dashboards/identity/mappings/forms.py
Normal file
86
openstack_dashboard/dashboards/identity/mappings/forms.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
# Copyright (C) 2015 Yahoo! Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 json
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
class CreateMappingForm(forms.SelfHandlingForm):
|
||||||
|
id = forms.CharField(label=_("Mapping ID"),
|
||||||
|
max_length=64,
|
||||||
|
help_text=_("User-defined unique id to identify "
|
||||||
|
"the mapping."))
|
||||||
|
rules = forms.CharField(label=_("Rules"),
|
||||||
|
widget=forms.widgets.Textarea(attrs={'rows': 4}),
|
||||||
|
help_text=_("Set of rules to map federation "
|
||||||
|
"protocol attributes to Identity "
|
||||||
|
"API objects."))
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
rules = json.loads(data["rules"])
|
||||||
|
new_mapping = api.keystone.mapping_create(
|
||||||
|
request,
|
||||||
|
data["id"],
|
||||||
|
rules=rules)
|
||||||
|
messages.success(request,
|
||||||
|
_("Mapping created successfully."))
|
||||||
|
return new_mapping
|
||||||
|
except exceptions.Conflict:
|
||||||
|
msg = _('Mapping ID "%s" is already used.') % data["id"]
|
||||||
|
messages.error(request, msg)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
msg = _("Unable to create mapping. Rules has malformed JSON data.")
|
||||||
|
messages.error(request, msg)
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_("Unable to create mapping."))
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateMappingForm(forms.SelfHandlingForm):
|
||||||
|
id = forms.CharField(label=_("Mapping ID"),
|
||||||
|
widget=forms.TextInput(
|
||||||
|
attrs={'readonly': 'readonly'}),
|
||||||
|
help_text=_("User-defined unique id to "
|
||||||
|
"identify the mapping."))
|
||||||
|
rules = forms.CharField(label=_("Rules"),
|
||||||
|
widget=forms.widgets.Textarea(attrs={'rows': 4}),
|
||||||
|
help_text=_("Set of rules to map federation "
|
||||||
|
"protocol attributes to Identity "
|
||||||
|
"API objects."))
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
rules = json.loads(data["rules"])
|
||||||
|
api.keystone.mapping_update(
|
||||||
|
request,
|
||||||
|
data['id'],
|
||||||
|
rules=rules)
|
||||||
|
messages.success(request,
|
||||||
|
_("Mapping updated successfully."))
|
||||||
|
return True
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
msg = _("Unable to update mapping. Rules has malformed JSON data.")
|
||||||
|
messages.error(request, msg)
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Unable to update mapping.'))
|
30
openstack_dashboard/dashboards/identity/mappings/panel.py
Normal file
30
openstack_dashboard/dashboards/identity/mappings/panel.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Copyright (C) 2015 Yahoo! Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.api import keystone
|
||||||
|
|
||||||
|
|
||||||
|
class Mappings(horizon.Panel):
|
||||||
|
name = _("Mappings")
|
||||||
|
slug = 'mappings'
|
||||||
|
policy_rules = (("identity", "identity:list_mappings"),)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def can_register():
|
||||||
|
return (keystone.VERSIONS.active >= 3 and
|
||||||
|
keystone.is_federation_management_enabled())
|
91
openstack_dashboard/dashboards/identity/mappings/tables.py
Normal file
91
openstack_dashboard/dashboards/identity/mappings/tables.py
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# Copyright (C) 2015 Yahoo! Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 json
|
||||||
|
|
||||||
|
from django.utils import safestring
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.utils.translation import ungettext_lazy
|
||||||
|
|
||||||
|
from horizon import tables
|
||||||
|
|
||||||
|
from openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
|
class CreateMappingLink(tables.LinkAction):
|
||||||
|
name = "create"
|
||||||
|
verbose_name = _("Create Mapping")
|
||||||
|
url = "horizon:identity:mappings:create"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "plus"
|
||||||
|
policy_rules = (("identity", "identity:create_mapping"),)
|
||||||
|
|
||||||
|
|
||||||
|
class EditMappingLink(tables.LinkAction):
|
||||||
|
name = "edit"
|
||||||
|
verbose_name = _("Edit")
|
||||||
|
url = "horizon:identity:mappings:update"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "pencil"
|
||||||
|
policy_rules = (("identity", "identity:update_mapping"),)
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteMappingsAction(tables.DeleteAction):
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Delete Mapping",
|
||||||
|
u"Delete Mappings",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Deleted Mapping",
|
||||||
|
u"Deleted Mappings",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
policy_rules = (("identity", "identity:delete_mapping"),)
|
||||||
|
|
||||||
|
def delete(self, request, obj_id):
|
||||||
|
api.keystone.mapping_delete(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class MappingFilterAction(tables.FilterAction):
|
||||||
|
def filter(self, table, mappings, filter_string):
|
||||||
|
"""Naive case-insensitive search."""
|
||||||
|
q = filter_string.lower()
|
||||||
|
return [mapping for mapping in mappings
|
||||||
|
if q in mapping.ud.lower()]
|
||||||
|
|
||||||
|
|
||||||
|
def get_rules_as_json(mapping):
|
||||||
|
rules = getattr(mapping, 'rules', None)
|
||||||
|
if rules:
|
||||||
|
rules = json.dumps(rules, indent=4)
|
||||||
|
return safestring.mark_safe(rules)
|
||||||
|
|
||||||
|
|
||||||
|
class MappingsTable(tables.DataTable):
|
||||||
|
id = tables.Column('id', verbose_name=_('Mapping ID'))
|
||||||
|
description = tables.Column(get_rules_as_json,
|
||||||
|
verbose_name=_('Rules'))
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "idp_mappings"
|
||||||
|
verbose_name = _("Attribute Mappings")
|
||||||
|
row_actions = (EditMappingLink, DeleteMappingsAction)
|
||||||
|
table_actions = (MappingFilterAction, CreateMappingLink,
|
||||||
|
DeleteMappingsAction)
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Create a mapping." %}</p>
|
||||||
|
<p>{% trans "A mapping is a set of rules to map federation protocol attributes to Identity API objects. An identity provider can have a single mapping specified per protocol. A mapping is simply a list of rules. The only Identity API objects that will support mapping are: user and group." %}</p>
|
||||||
|
<p>{% trans "A rule contains a remote attribute description and the destination local attribute." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,8 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Edit the mapping's details." %}</p>
|
||||||
|
<p>{% trans "A rule contains a remote attribute description and the destination local attribute." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,7 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Create Mapping" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'identity/mappings/_create.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,7 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Mappings" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{{ table.render }}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,7 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Update Mapping" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'identity/mappings/_update.html' %}
|
||||||
|
{% endblock %}
|
107
openstack_dashboard/dashboards/identity/mappings/tests.py
Normal file
107
openstack_dashboard/dashboards/identity/mappings/tests.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
# Copyright (C) 2015 Yahoo! Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 json
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django import http
|
||||||
|
|
||||||
|
from mox3.mox import IgnoreArg # noqa
|
||||||
|
from mox3.mox import IsA # noqa
|
||||||
|
|
||||||
|
from openstack_dashboard import api
|
||||||
|
from openstack_dashboard.test import helpers as test
|
||||||
|
|
||||||
|
|
||||||
|
MAPPINGS_INDEX_URL = reverse('horizon:identity:mappings:index')
|
||||||
|
MAPPINGS_CREATE_URL = reverse('horizon:identity:mappings:create')
|
||||||
|
MAPPINGS_UPDATE_URL = reverse('horizon:identity:mappings:update',
|
||||||
|
args=['mapping_1'])
|
||||||
|
|
||||||
|
|
||||||
|
class MappingsViewTests(test.BaseAdminViewTests):
|
||||||
|
@test.create_stubs({api.keystone: ('mapping_list',)})
|
||||||
|
def test_index(self):
|
||||||
|
api.keystone.mapping_list(IgnoreArg()). \
|
||||||
|
AndReturn(self.idp_mappings.list())
|
||||||
|
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
res = self.client.get(MAPPINGS_INDEX_URL)
|
||||||
|
|
||||||
|
self.assertTemplateUsed(res, 'identity/mappings/index.html')
|
||||||
|
self.assertItemsEqual(res.context['table'].data,
|
||||||
|
self.idp_mappings.list())
|
||||||
|
|
||||||
|
@test.create_stubs({api.keystone: ('mapping_create', )})
|
||||||
|
def test_create(self):
|
||||||
|
mapping = self.idp_mappings.first()
|
||||||
|
|
||||||
|
api.keystone.mapping_create(IgnoreArg(),
|
||||||
|
mapping.id,
|
||||||
|
rules=mapping.rules). \
|
||||||
|
AndReturn(mapping)
|
||||||
|
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
formData = {'method': 'CreateMappingForm',
|
||||||
|
'id': mapping.id,
|
||||||
|
'rules': json.dumps(mapping.rules)}
|
||||||
|
res = self.client.post(MAPPINGS_CREATE_URL, formData)
|
||||||
|
|
||||||
|
self.assertNoFormErrors(res)
|
||||||
|
self.assertMessageCount(success=1)
|
||||||
|
|
||||||
|
@test.create_stubs({api.keystone: ('mapping_get',
|
||||||
|
'mapping_update')})
|
||||||
|
def test_update(self):
|
||||||
|
mapping = self.idp_mappings.first()
|
||||||
|
new_rules = [{"local": [], "remote": []}]
|
||||||
|
|
||||||
|
api.keystone.mapping_get(IsA(http.HttpRequest),
|
||||||
|
mapping.id). \
|
||||||
|
AndReturn(mapping)
|
||||||
|
api.keystone.mapping_update(IsA(http.HttpRequest),
|
||||||
|
mapping.id,
|
||||||
|
rules=new_rules). \
|
||||||
|
AndReturn(None)
|
||||||
|
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
formData = {'method': 'UpdateMappingForm',
|
||||||
|
'id': mapping.id,
|
||||||
|
'rules': json.dumps(new_rules)}
|
||||||
|
|
||||||
|
res = self.client.post(MAPPINGS_UPDATE_URL, formData)
|
||||||
|
|
||||||
|
self.assertNoFormErrors(res)
|
||||||
|
self.assertMessageCount(success=1)
|
||||||
|
|
||||||
|
@test.create_stubs({api.keystone: ('mapping_list',
|
||||||
|
'mapping_delete')})
|
||||||
|
def test_delete(self):
|
||||||
|
mapping = self.idp_mappings.first()
|
||||||
|
|
||||||
|
api.keystone.mapping_list(IsA(http.HttpRequest)) \
|
||||||
|
.AndReturn(self.idp_mappings.list())
|
||||||
|
api.keystone.mapping_delete(IsA(http.HttpRequest),
|
||||||
|
mapping.id) \
|
||||||
|
.AndReturn(None)
|
||||||
|
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
formData = {'action': 'idp_mappings__delete__%s' % mapping.id}
|
||||||
|
res = self.client.post(MAPPINGS_INDEX_URL, formData)
|
||||||
|
|
||||||
|
self.assertNoFormErrors(res)
|
25
openstack_dashboard/dashboards/identity/mappings/urls.py
Normal file
25
openstack_dashboard/dashboards/identity/mappings/urls.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Copyright (C) 2015 Yahoo! Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.conf.urls import patterns
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from openstack_dashboard.dashboards.identity.mappings import views
|
||||||
|
|
||||||
|
urlpatterns = patterns(
|
||||||
|
'openstack_dashboard.dashboards.identity.mappings.views',
|
||||||
|
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
url(r'^(?P<mapping_id>[^/]+)/update/$',
|
||||||
|
views.UpdateView.as_view(), name='update'),
|
||||||
|
url(r'^create/$', views.CreateView.as_view(), name='create'))
|
101
openstack_dashboard/dashboards/identity/mappings/views.py
Normal file
101
openstack_dashboard/dashboards/identity/mappings/views.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
# Copyright (C) 2015 Yahoo! Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 json
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.core.urlresolvers import reverse_lazy
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import messages
|
||||||
|
from horizon import tables
|
||||||
|
from horizon.utils import memoized
|
||||||
|
|
||||||
|
from openstack_dashboard import api
|
||||||
|
from openstack_dashboard import policy
|
||||||
|
|
||||||
|
from openstack_dashboard.dashboards.identity.mappings \
|
||||||
|
import forms as mapping_forms
|
||||||
|
from openstack_dashboard.dashboards.identity.mappings \
|
||||||
|
import tables as mapping_tables
|
||||||
|
|
||||||
|
|
||||||
|
class IndexView(tables.DataTableView):
|
||||||
|
table_class = mapping_tables.MappingsTable
|
||||||
|
template_name = 'identity/mappings/index.html'
|
||||||
|
page_title = _("Mappings")
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
mappings = []
|
||||||
|
if policy.check((("identity", "identity:list_mappings"),),
|
||||||
|
self.request):
|
||||||
|
try:
|
||||||
|
mappings = api.keystone.mapping_list(self.request)
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(
|
||||||
|
self.request,
|
||||||
|
_('Unable to retrieve mapping list.'))
|
||||||
|
else:
|
||||||
|
msg = _("Insufficient privilege level to view mapping "
|
||||||
|
"information.")
|
||||||
|
messages.info(self.request, msg)
|
||||||
|
return mappings
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateView(forms.ModalFormView):
|
||||||
|
template_name = 'identity/mappings/update.html'
|
||||||
|
modal_header = _("Update Mapping")
|
||||||
|
form_id = "update_mapping_form"
|
||||||
|
form_class = mapping_forms.UpdateMappingForm
|
||||||
|
submit_label = _("Update Mapping")
|
||||||
|
submit_url = "horizon:identity:mappings:update"
|
||||||
|
success_url = reverse_lazy('horizon:identity:mappings:index')
|
||||||
|
page_title = _("Update Mapping")
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_object(self):
|
||||||
|
try:
|
||||||
|
return api.keystone.mapping_get(
|
||||||
|
self.request,
|
||||||
|
self.kwargs['mapping_id'])
|
||||||
|
except Exception:
|
||||||
|
redirect = reverse("horizon:identity:mappings:index")
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_('Unable to update mapping.'),
|
||||||
|
redirect=redirect)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(UpdateView, self).get_context_data(**kwargs)
|
||||||
|
args = (self.get_object().id,)
|
||||||
|
context['submit_url'] = reverse(self.submit_url, args=args)
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
mapping = self.get_object()
|
||||||
|
rules = json.dumps(mapping.rules, indent=4)
|
||||||
|
return {'id': mapping.id,
|
||||||
|
'rules': rules}
|
||||||
|
|
||||||
|
|
||||||
|
class CreateView(forms.ModalFormView):
|
||||||
|
template_name = 'identity/mappings/create.html'
|
||||||
|
modal_header = _("Create Mapping")
|
||||||
|
form_id = "create_mapping_form"
|
||||||
|
form_class = mapping_forms.CreateMappingForm
|
||||||
|
submit_label = _("Create Mapping")
|
||||||
|
submit_url = reverse_lazy("horizon:identity:mappings:create")
|
||||||
|
success_url = reverse_lazy('horizon:identity:mappings:index')
|
||||||
|
page_title = _("Create Mapping")
|
10
openstack_dashboard/enabled/_3080_identity_mappings_panel.py
Normal file
10
openstack_dashboard/enabled/_3080_identity_mappings_panel.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# The slug of the panel to be added to HORIZON_CONFIG. Required.
|
||||||
|
PANEL = 'mappings'
|
||||||
|
# The slug of the dashboard the PANEL associated with. Required.
|
||||||
|
PANEL_DASHBOARD = 'identity'
|
||||||
|
# The slug of the panel group the PANEL is associated with.
|
||||||
|
PANEL_GROUP = 'federation'
|
||||||
|
|
||||||
|
# Python panel class of the PANEL to be added.
|
||||||
|
ADD_PANEL = ('openstack_dashboard.dashboards.identity.'
|
||||||
|
'mappings.panel.Mappings')
|
@ -24,6 +24,7 @@ from keystoneclient.v2_0 import roles
|
|||||||
from keystoneclient.v2_0 import tenants
|
from keystoneclient.v2_0 import tenants
|
||||||
from keystoneclient.v2_0 import users
|
from keystoneclient.v2_0 import users
|
||||||
from keystoneclient.v3.contrib.federation import identity_providers
|
from keystoneclient.v3.contrib.federation import identity_providers
|
||||||
|
from keystoneclient.v3.contrib.federation import mappings
|
||||||
from keystoneclient.v3 import domains
|
from keystoneclient.v3 import domains
|
||||||
from keystoneclient.v3 import groups
|
from keystoneclient.v3 import groups
|
||||||
from keystoneclient.v3 import role_assignments
|
from keystoneclient.v3 import role_assignments
|
||||||
@ -146,6 +147,7 @@ def data(TEST):
|
|||||||
TEST.ec2 = utils.TestDataContainer()
|
TEST.ec2 = utils.TestDataContainer()
|
||||||
|
|
||||||
TEST.identity_providers = utils.TestDataContainer()
|
TEST.identity_providers = utils.TestDataContainer()
|
||||||
|
TEST.idp_mappings = utils.TestDataContainer()
|
||||||
|
|
||||||
admin_role_dict = {'id': '1',
|
admin_role_dict = {'id': '1',
|
||||||
'name': 'admin'}
|
'name': 'admin'}
|
||||||
@ -387,3 +389,39 @@ def data(TEST):
|
|||||||
identity_providers.IdentityProviderManager,
|
identity_providers.IdentityProviderManager,
|
||||||
idp_dict_2)
|
idp_dict_2)
|
||||||
TEST.identity_providers.add(idp_1, idp_2)
|
TEST.identity_providers.add(idp_1, idp_2)
|
||||||
|
|
||||||
|
idp_mapping_dict = {
|
||||||
|
"id": "mapping_1",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"local": [
|
||||||
|
{
|
||||||
|
"user": {
|
||||||
|
"name": "{0}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group": {
|
||||||
|
"id": "0cd5e9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"remote": [
|
||||||
|
{
|
||||||
|
"type": "UserName"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "orgPersonType",
|
||||||
|
"not_any_of": [
|
||||||
|
"Contractor",
|
||||||
|
"Guest"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
idp_mapping = mappings.Mapping(
|
||||||
|
mappings.MappingManager,
|
||||||
|
idp_mapping_dict)
|
||||||
|
TEST.idp_mappings.add(idp_mapping)
|
||||||
|
@ -4,4 +4,6 @@ features:
|
|||||||
[`blueprint keystone-federation-idp <https://blueprints.launchpad.net/horizon/+spec/keystone-federation-idp>`_]
|
[`blueprint keystone-federation-idp <https://blueprints.launchpad.net/horizon/+spec/keystone-federation-idp>`_]
|
||||||
Add support for managing keystone identity provider. To enable the panel,
|
Add support for managing keystone identity provider. To enable the panel,
|
||||||
set ``OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT`` in the local_settting.py to True.
|
set ``OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT`` in the local_settting.py to True.
|
||||||
|
- >
|
||||||
|
[`blueprint keystone-federation-mapping <https://blueprints.launchpad.net/horizon/+spec/keystone-federation-mapping>`_]
|
||||||
|
Add basic support for managing keystone federation mapping.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user