Add modals for User Cert create and revoke.
This commit is contained in:
parent
73017e83ef
commit
c4d208e457
@ -87,6 +87,22 @@ def _get_service_url(request, service):
|
||||
return service_url
|
||||
|
||||
|
||||
@urls.register
|
||||
class UserCert(generic.View):
|
||||
"""Pass-through API for executing service requests.
|
||||
|
||||
Horizon only adds auth and CORS proxying.
|
||||
"""
|
||||
url_regex = r'ssh/usergen/(?P<path>.+)$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def post(self, request, path):
|
||||
data = dict(request.DATA) if request.DATA else {}
|
||||
data['user_id'] = request.user.id
|
||||
data['auth_id'] = request.user.project_id
|
||||
return passthrough_post(path, request, data).json()
|
||||
|
||||
|
||||
@urls.register
|
||||
class Passthrough(generic.View):
|
||||
"""Pass-through API for executing service requests.
|
||||
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @ngname designatedashboard.resources.os-tatu-user.actions
|
||||
*
|
||||
* @description
|
||||
* Provides all of the actions for Tatu User Certs.
|
||||
*/
|
||||
angular.module('tatudashboard.resources.os-tatu-user.actions', [
|
||||
'horizon.framework.conf',
|
||||
'horizon.app.core'
|
||||
])
|
||||
.run(run);
|
||||
|
||||
run.$inject = [
|
||||
'horizon.framework.conf.resource-type-registry.service',
|
||||
'tatudashboard.resources.os-tatu-user.resourceType',
|
||||
'tatudashboard.resources.os-tatu-user.actions.create',
|
||||
'tatudashboard.resources.os-tatu-user.actions.revoke'
|
||||
];
|
||||
|
||||
function run(registry,
|
||||
resourceTypeString,
|
||||
createAction,
|
||||
revokeAction) {
|
||||
var resourceType = registry.getResourceType(resourceTypeString);
|
||||
resourceType
|
||||
.globalActions
|
||||
.append({
|
||||
id: 'create',
|
||||
service: createAction,
|
||||
template: {
|
||||
text: gettext('Create User SSH Certificate')
|
||||
}
|
||||
});
|
||||
|
||||
resourceType
|
||||
.itemActions
|
||||
.append({
|
||||
id: 'revoke',
|
||||
service: revokeAction,
|
||||
template: {
|
||||
text: gettext('Revoke'),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
@ -36,6 +36,8 @@
|
||||
*/
|
||||
function apiService(apiPassthroughUrl, httpService, toastService) {
|
||||
var service = {
|
||||
create: create,
|
||||
revoke: revoke,
|
||||
get: get,
|
||||
list: list
|
||||
};
|
||||
@ -44,6 +46,41 @@
|
||||
|
||||
///////////////
|
||||
|
||||
/**
|
||||
* @name create
|
||||
* @description
|
||||
* Create a User Certificate
|
||||
*
|
||||
* @param {Object} data
|
||||
* Specifies the User Certificate information to create
|
||||
*
|
||||
* @returns {Object} The created user object
|
||||
*/
|
||||
function create(data) {
|
||||
return httpService.post(apiPassthroughUrl + 'usergen/noauth/usercerts/', data)
|
||||
.error(function() {
|
||||
toastService.add('error', gettext('Unable to create the certificate.'));
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @name revoke
|
||||
* @description
|
||||
* Revoke a single certificate
|
||||
*
|
||||
* @param {Object} user
|
||||
* Specifies the user certificate to revoke
|
||||
*
|
||||
* @returns {Object} The revoked user certificate
|
||||
*/
|
||||
function revoke(user) {
|
||||
var data = { 'serial': user.serial }
|
||||
var url = apiPassthroughUrl + 'noauth/revokeduserkeys/' + user.auth_id + '/'
|
||||
return httpService.post(url, data)
|
||||
.error(function() {
|
||||
toastService.add('error', gettext('Unable to revoke the certificate.'));
|
||||
})
|
||||
|
||||
/**
|
||||
* @name list
|
||||
* @description
|
||||
|
@ -0,0 +1,141 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright 2016 Hewlett Packard Enterprise Development Company LP
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use self 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.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('tatudashboard.resources.os-tatu-user.actions')
|
||||
.factory('tatudashboard.resources.os-tatu-user.actions.create', action);
|
||||
|
||||
action.$inject = [
|
||||
'$q',
|
||||
'tatudashboard.resources.os-tatu-user.actions.common-forms',
|
||||
'tatudashboard.resources.os-tatu-user.api',
|
||||
'tatudashboard.resources.os-tatu-user.resourceType',
|
||||
'horizon.app.core.openstack-service-api.policy',
|
||||
'horizon.app.core.openstack-service-api.serviceCatalog',
|
||||
'horizon.framework.widgets.form.ModalFormService',
|
||||
'horizon.framework.widgets.toast.service',
|
||||
'horizon.framework.widgets.modal-wait-spinner.service'
|
||||
];
|
||||
|
||||
/**
|
||||
* @ngDoc factory
|
||||
* @name tatudashboard.resources.os-tatu-user.actions.create
|
||||
*
|
||||
* @Description
|
||||
* Brings up the Create User modal.
|
||||
*/
|
||||
function action($q,
|
||||
forms,
|
||||
api,
|
||||
resourceTypeName,
|
||||
policy,
|
||||
serviceCatalog,
|
||||
schemaFormModalService,
|
||||
toast,
|
||||
waitSpinner) {
|
||||
var createUserPolicy, sshServiceEnabled;
|
||||
var title = gettext("Generate User Certificate");
|
||||
var message = {
|
||||
success: gettext('Certificate %s was successfully generated.')
|
||||
};
|
||||
|
||||
var service = {
|
||||
initScope: initScope,
|
||||
allowed: allowed,
|
||||
perform: perform
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
/////////////////
|
||||
|
||||
function initScope() {
|
||||
createUserPolicy = policy.ifAllowed({rules: [['ssh', 'create_user_cert']]});
|
||||
sshServiceEnabled = serviceCatalog.ifTypeEnabled('ssh');
|
||||
}
|
||||
|
||||
function allowed() {
|
||||
return $q.all([
|
||||
createUserPolicy,
|
||||
sshServiceEnabled
|
||||
]);
|
||||
}
|
||||
|
||||
function perform() {
|
||||
var formConfig = forms.getCreateFormConfig();
|
||||
formConfig.title = title;
|
||||
return schemaFormModalService.open(formConfig).then(onSubmit, onCancel);
|
||||
}
|
||||
|
||||
function onSubmit(context) {
|
||||
var userModel = angular.copy(context.model);
|
||||
waitSpinner.showModalSpinner(gettext('Creating User SSH Certificate'));
|
||||
return api.create(userModel).then(onSuccess, onFailure);
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
waitSpinner.hideModalSpinner();
|
||||
}
|
||||
|
||||
function onSuccess(response) {
|
||||
waitSpinner.hideModalSpinner();
|
||||
var user = response.data;
|
||||
toast.add('success', interpolate(message.success, [user.serial]));
|
||||
|
||||
// To make the result of this action generically useful, reformat the return
|
||||
// from the deleteModal into a standard form
|
||||
return {
|
||||
created: [{type: resourceTypeName, id: user.serial}],
|
||||
updated: [],
|
||||
deleted: [],
|
||||
failed: []
|
||||
};
|
||||
}
|
||||
|
||||
function onFailure() {
|
||||
waitSpinner.hideModalSpinner();
|
||||
}
|
||||
/**
|
||||
* Return the create User Cert form.
|
||||
* @returns {object} a schema form config, including default model
|
||||
*/
|
||||
function getCreateFormConfig() {
|
||||
return {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key.pub": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"form": [
|
||||
{
|
||||
"key": "key.pub",
|
||||
"type": "textarea",
|
||||
"title": gettext("SSH Public Key"),
|
||||
"description": gettext("The user's SSH public key."),
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
})();
|
@ -0,0 +1,203 @@
|
||||
/**
|
||||
* (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use self 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.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('tatudashboard.resources.os-tatu-user.actions')
|
||||
.factory('tatudashboard.resources.os-tatu-user.actions.revoke', action);
|
||||
|
||||
action.$inject = [
|
||||
'$q',
|
||||
'tatudashboard.resources.os-tatu-user.api',
|
||||
'tatudashboard.resources.util',
|
||||
'horizon.app.core.openstack-service-api.policy',
|
||||
'horizon.framework.util.actions.action-result.service',
|
||||
'horizon.framework.util.i18n.gettext',
|
||||
'horizon.framework.util.q.extensions',
|
||||
'horizon.framework.widgets.modal.simple-modal.service',
|
||||
'horizon.framework.widgets.toast.service',
|
||||
'tatudashboard.resources.os-tatu-user.resourceType'
|
||||
];
|
||||
|
||||
/*
|
||||
* @ngdoc factory
|
||||
* @name tatudashboard.resources.os-tatu-user.actions.revoke
|
||||
*
|
||||
* @Description
|
||||
* Brings up the revoke user confirmation modal dialog.
|
||||
|
||||
* On submit, revoke given user SSH certificate.
|
||||
* On cancel, do nothing.
|
||||
*/
|
||||
function action(
|
||||
$q,
|
||||
userApi,
|
||||
util,
|
||||
policy,
|
||||
actionResultService,
|
||||
gettext,
|
||||
$qExtensions,
|
||||
simpleModalService,
|
||||
toast,
|
||||
resourceType
|
||||
) {
|
||||
var scope, context, revokeUserPromise;
|
||||
var notAllowedMessage = gettext("You are not allowed to revoke user certificates: %s");
|
||||
|
||||
var service = {
|
||||
initScope: initScope,
|
||||
allowed: allowed,
|
||||
perform: perform
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
//////////////
|
||||
|
||||
function initScope(newScope) {
|
||||
scope = newScope;
|
||||
context = { };
|
||||
revokeUserPromise = policy.ifAllowed({rules: [['ssh', 'revoke_user_cert']]});
|
||||
}
|
||||
|
||||
function perform(items) {
|
||||
var certs = angular.isArray(items) ? items : [items];
|
||||
context.labels = labelize(certs.length);
|
||||
return $qExtensions.allSettled(users.map(checkPermission)).then(afterCheck);
|
||||
}
|
||||
|
||||
function allowed(user) {
|
||||
// only row actions pass in user
|
||||
// otherwise, assume it is a batch action
|
||||
if (user) {
|
||||
return $q.all([
|
||||
revokeUserPromise
|
||||
]);
|
||||
} else {
|
||||
return policy.ifAllowed({ rules: [['ssh', 'revoke_user_cert']] });
|
||||
}
|
||||
}
|
||||
|
||||
function checkPermission(user) {
|
||||
return {promise: allowed(user), context: user};
|
||||
}
|
||||
|
||||
function afterCheck(result) {
|
||||
var outcome = $q.reject(); // Reject the promise by default
|
||||
if (result.fail.length > 0) {
|
||||
toast.add('error', getMessage(notAllowedMessage, result.fail.map(getUser)));
|
||||
outcome = $q.reject(result.fail);
|
||||
}
|
||||
if (result.pass.length > 0) {
|
||||
outcome = open(result.pass.map(getUser)).then(createResult);
|
||||
}
|
||||
return outcome;
|
||||
}
|
||||
|
||||
function createResult(deleteModalResult) {
|
||||
// To make the result of this action generically useful, reformat the return
|
||||
// from the deleteModal into a standard form
|
||||
var actionResult = actionResultService.getActionResult();
|
||||
deleteModalResult.pass.forEach(function markDeleted(item) {
|
||||
actionResult.updated(resourceType, getUser(item).serial);
|
||||
});
|
||||
deleteModalResult.fail.forEach(function markFailed(item) {
|
||||
actionResult.failed(resourceType, getUser(item).serial);
|
||||
});
|
||||
return actionResult.result;
|
||||
}
|
||||
|
||||
function labelize(count) {
|
||||
return {
|
||||
|
||||
title: ngettext(
|
||||
'Confirm Revoke User Certificate',
|
||||
'Confirm Revoke Users Certificates', count),
|
||||
|
||||
message: ngettext(
|
||||
'You have selected "%s". Revoked user cert is not recoverable.',
|
||||
'You have selected "%s". Revoked users certs are not recoverable.', count),
|
||||
|
||||
submit: ngettext(
|
||||
'Revoke User Certificate',
|
||||
'Revoke Users Certificates', count),
|
||||
|
||||
success: ngettext(
|
||||
'Revoked User Cert: %s.',
|
||||
'Revoked Users Certs: %s.', count),
|
||||
|
||||
error: ngettext(
|
||||
'Unable to revoke User Certificate: %s.',
|
||||
'Unable to revoke Users Certificates: %s.', count)
|
||||
};
|
||||
}
|
||||
|
||||
function open(users) {
|
||||
var options = {
|
||||
title: context.labels.title,
|
||||
body: interpolate(context.labels.message, [users.map(getSerial).join("\", \"")]),
|
||||
submit: context.labels.submit
|
||||
};
|
||||
|
||||
return simpleModalService.modal(options).result.then(onModalSubmit);
|
||||
|
||||
function onModalSubmit() {
|
||||
return $qExtensions.allSettled(users.map(revokePromise)).then(notify);
|
||||
}
|
||||
|
||||
function revokePromise(user) {
|
||||
return {promise: userApi.revoke(user), context: user};
|
||||
}
|
||||
|
||||
function notify(result) {
|
||||
if (result.pass.length > 0) {
|
||||
var passEntities = result.pass.map(getUser);
|
||||
scope.$emit(context.successEvent, passEntities.map(getSerial));
|
||||
toast.add('success', getMessage(context.labels.success, passEntities));
|
||||
}
|
||||
|
||||
if (result.fail.length > 0) {
|
||||
var failEntities = result.fail.map(getUser);
|
||||
scope.$emit(context.failedEvent, failEntities.map(getSerial));
|
||||
toast.add('error', getMessage(context.labels.error, failEntities));
|
||||
}
|
||||
// Return the passed and failed entities as part of resolving the promise
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function getUser(result) {
|
||||
return result.context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the displayed message
|
||||
*/
|
||||
function getMessage(message, users) {
|
||||
return interpolate(message, [users.map(getSerial).join(", ")]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the serial number of the user
|
||||
*/
|
||||
function getSerial(user) {
|
||||
return user.serial;
|
||||
}
|
||||
|
||||
}
|
||||
})();
|
@ -1,4 +1,4 @@
|
||||
<hz-resource-panel resource-type-name="OS::Tatu::User">
|
||||
<hz-resource-table resource-type-name="OS::Tatu::User"
|
||||
track-by="fingerprint"></hz-resource-table>
|
||||
track-by="serial"></hz-resource-table>
|
||||
</hz-resource-panel>
|
||||
|
Loading…
Reference in New Issue
Block a user