summaryrefslogtreecommitdiffstats
path: root/install/ui/certificate.js
diff options
context:
space:
mode:
Diffstat (limited to 'install/ui/certificate.js')
-rwxr-xr-xinstall/ui/certificate.js785
1 files changed, 785 insertions, 0 deletions
diff --git a/install/ui/certificate.js b/install/ui/certificate.js
new file mode 100755
index 000000000..b7e5a51d3
--- /dev/null
+++ b/install/ui/certificate.js
@@ -0,0 +1,785 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Endi Sukma Dewata <edewata@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+var BEGIN_CERTIFICATE = '-----BEGIN CERTIFICATE-----';
+var END_CERTIFICATE = '-----END CERTIFICATE-----';
+
+var BEGIN_CERTIFICATE_REQUEST = '-----BEGIN CERTIFICATE REQUEST-----';
+var END_CERTIFICATE_REQUEST = '-----END CERTIFICATE REQUEST-----';
+
+var CRL_REASON = [
+ 'Unspecified',
+ 'Key Compromise',
+ 'CA Compromise',
+ 'Affiliation Changed',
+ 'Superseded',
+ 'Cessation of Operation',
+ 'Certificate Hold',
+ null,
+ 'Remove from CRL',
+ 'Privilege Withdrawn',
+ 'AA Compromise'
+];
+
+var CERTIFICATE_STATUS_MISSING = 0;
+var CERTIFICATE_STATUS_VALID = 1;
+var CERTIFICATE_STATUS_REVOKED = 2;
+
+function certificate_parse_dn(dn) {
+
+ var result = {};
+ if (!dn) return result;
+
+ // TODO: Use proper LDAP DN parser
+ var rdns = dn.split(',');
+ for (var i=0; i<rdns.length; i++) {
+ var rdn = rdns[i];
+ if (!rdn) continue;
+
+ var parts = rdn.split('=');
+ var name = $.trim(parts[0].toLowerCase());
+ var value = $.trim(parts[1]);
+
+ var old_value = result[name];
+ if (!old_value) {
+ result[name] = value;
+ } else if (typeof old_value == "string") {
+ result[name] = [old_value, value];
+ } else {
+ result[name].push(value);
+ }
+ }
+
+ return result;
+}
+
+function certificate_get_dialog(spec) {
+ var that = {};
+ spec = spec || {};
+
+ that.title = spec.title || '';
+ that.usercertificate = spec.usercertificate || '';
+
+ var dialog = $('<div/>', {
+ 'title': that.title
+ });
+
+ var textarea = $('<textarea/>', {
+ readonly: 'yes',
+ style: 'width: 100%; height: 275px;'
+ }).appendTo(dialog);
+
+ textarea.val(
+ BEGIN_CERTIFICATE+'\n'+
+ that.usercertificate+'\n'+
+ END_CERTIFICATE );
+
+ that.open = function() {
+ dialog.dialog({
+ modal: true,
+ width: 500,
+ height: 400,
+ buttons: {
+ 'Close': function() {
+ dialog.dialog('destroy');
+ }
+ }
+ });
+ };
+
+ return that;
+}
+
+function certificate_revoke_dialog(spec) {
+ var that = {};
+ spec = spec || {};
+
+ that.title = spec.title || '';
+ that.revoke = spec.revoke;
+
+ var dialog = $('<div/>', {
+ 'title': that.title
+ });
+
+ var table = $('<table/>').appendTo(dialog);
+
+ var tr = $('<tr/>').appendTo(table);
+
+ var td = $('<td/>').appendTo(tr);
+ td.append('Note:');
+
+ td = $('<td/>').appendTo(tr);
+ td.append(
+ 'To confirm your intention to revoke this certificate, '+
+ 'select a reason from the pull-down list, and click '+
+ 'the "Revoke" button.');
+
+ tr = $('<tr/>').appendTo(table);
+
+ td = $('<td/>').appendTo(tr);
+ td.append('Reason for Revocation:');
+
+ td = $('<td/>').appendTo(tr);
+
+ var select = $('<select/>').appendTo(td);
+ for (var i=0; i<CRL_REASON.length; i++) {
+ if (!CRL_REASON[i]) continue;
+ $('<option/>', {
+ 'value': i,
+ 'html': CRL_REASON[i]
+ }).appendTo(select);
+ }
+
+ that.open = function() {
+ dialog.dialog({
+ modal: true,
+ width: 500,
+ height: 300,
+ buttons: {
+ 'Revoke': function() {
+ var values = {};
+ values['reason'] = select.val();
+ if (that.revoke) {
+ that.revoke(values);
+ }
+ dialog.dialog('destroy');
+ },
+ 'Cancel': function() {
+ dialog.dialog('destroy');
+ }
+ }
+ });
+ };
+
+ return that;
+}
+
+function certificate_restore_dialog(spec) {
+ var that = {};
+ spec = spec || {};
+
+ that.title = spec.title || '';
+ that.restore = spec.restore;
+
+ var dialog = $('<div/>', {
+ 'title': that.title
+ });
+
+ dialog.append(
+ 'To confirm your intention to restore this certificate, '+
+ 'click the "Restore" button.');
+
+ that.open = function() {
+ dialog.dialog({
+ modal: true,
+ width: 400,
+ height: 200,
+ buttons: {
+ 'Restore': function() {
+ var values = {};
+ if (that.restore) {
+ that.restore(values);
+ }
+ dialog.dialog('destroy');
+ },
+ 'Cancel': function() {
+ dialog.dialog('destroy');
+ }
+ }
+ });
+ };
+
+ return that;
+}
+
+function certificate_view_dialog(spec) {
+ var that = {};
+ spec = spec || {};
+
+ that.title = spec.title || '';
+ that.subject = certificate_parse_dn(spec.subject);
+ that.serial_number = spec.serial_number || '';
+ that.issuer = certificate_parse_dn(spec.issuer);
+ that.issued_on = spec.issued_on || '';
+ that.expires_on = spec.expires_on || '';
+ that.md5_fingerprint = spec.md5_fingerprint || '';
+ that.sha1_fingerprint = spec.sha1_fingerprint || '';
+
+ var dialog = $('<div/>', {
+ 'title': that.title
+ });
+
+ var table = $('<table/>').appendTo(dialog);
+
+ var tr = $('<tr/>').appendTo(table);
+ $('<td/>', {
+ 'colspan': 2,
+ 'html': '<h3>Issued To</h3>'
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>Common Name:</td>').appendTo(tr);
+ $('<td/>', {
+ 'html': that.subject.cn
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>Organization:</td>').appendTo(tr);
+ $('<td/>', {
+ 'html': that.subject.o
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>Organizational Unit:</td>').appendTo(tr);
+ $('<td/>', {
+ 'html': that.subject.ou
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>Serial Number:</td>').appendTo(tr);
+ $('<td/>', {
+ 'html': that.serial_number
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td/>', {
+ 'colspan': 2,
+ 'html': '<h3>Issued By</h3>'
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>Common Name:</td>').appendTo(tr);
+ $('<td/>', {
+ 'html': that.issuer.cn
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>Organization:</td>').appendTo(tr);
+ $('<td/>', {
+ 'html': that.issuer.o
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>Organizational Unit:</td>').appendTo(tr);
+ $('<td/>', {
+ 'html': that.issuer.ou
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td/>', {
+ 'colspan': 2,
+ 'html': '<h3>Validity</h3>'
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>Issued On:</td>').appendTo(tr);
+ $('<td/>', {
+ 'html': that.issued_on
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>Expires On:</td>').appendTo(tr);
+ $('<td/>', {
+ 'html': that.expires_on
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td/>', {
+ 'colspan': 2,
+ 'html': '<h3>Fingerprints</h3>'
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>SHA1 Fingerprint:</td>').appendTo(tr);
+ $('<td/>', {
+ 'html': that.sha1_fingerprint
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>MD5 Fingerprint:</td>').appendTo(tr);
+ $('<td/>', {
+ 'html': that.md5_fingerprint
+ }).appendTo(tr);
+
+ that.open = function() {
+ dialog.dialog({
+ modal: true,
+ width: 600,
+ height: 500,
+ buttons: {
+ 'Close': function() {
+ dialog.dialog('destroy');
+ }
+ }
+ });
+ };
+
+ return that;
+}
+
+function certificate_request_dialog(spec) {
+ var that = {};
+ spec = spec || {};
+
+ that.title = spec.title || '';
+ that.request = spec.request;
+
+ var dialog = $('<div/>', {
+ 'title': that.title
+ });
+
+ dialog.append('Copy and paste the Base64-encoded CSR below:');
+ dialog.append('<br/>');
+ dialog.append('<br/>');
+
+ dialog.append(BEGIN_CERTIFICATE_REQUEST);
+ dialog.append('<br/>');
+
+ var textarea = $('<textarea/>', {
+ style: 'width: 100%; height: 225px;'
+ }).appendTo(dialog);
+
+ dialog.append('<br/>');
+ dialog.append(END_CERTIFICATE_REQUEST);
+
+ that.open = function() {
+ dialog.dialog({
+ modal: true,
+ width: 500,
+ height: 400,
+ buttons: {
+ 'Issue': function() {
+ var values = {};
+ var request = textarea.val();
+ request =
+ BEGIN_CERTIFICATE_REQUEST+'\n'+
+ $.trim(request)+'\n'+
+ END_CERTIFICATE_REQUEST+'\n';
+ values['request'] = request;
+ if (that.request) {
+ that.request(values);
+ }
+ dialog.dialog('destroy');
+ },
+ 'Cancel': function() {
+ dialog.dialog('destroy');
+ }
+ }
+ });
+ };
+
+ return that;
+}
+
+function certificate_status_widget(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.widget(spec);
+
+ that.entity_label = spec.entity_label || that.entity_name;
+
+ that.result = spec.result;
+
+ that.get_entity_pkey = spec.get_entity_pkey;
+ that.get_entity_name = spec.get_entity_name;
+ that.get_entity_principal = spec.get_entity_principal;
+ that.get_entity_certificate = spec.get_entity_certificate;
+
+ that.is_selfsign = function() {
+ return IPA.env.ra_plugin == 'selfsign';
+ };
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ var dd = $('<dd/>', {
+ 'class': 'first'
+ }).appendTo(container);
+
+ var div = $('<div/>', {
+ name: 'certificate-valid'
+ }).appendTo(dd);
+
+ $('<img/>', {
+ src: 'check.png',
+ style: 'float: left;',
+ 'class': 'status-icon'
+ }).appendTo(div);
+
+ var content_div = $('<div/>', {
+ style: 'float: left;'
+ }).appendTo(div);
+
+ content_div.append('<b>Valid Certificate Present:</b>');
+
+ content_div.append(' ');
+
+ $('<input/>', {
+ 'type': 'button',
+ 'name': 'get',
+ 'value': 'Get'
+ }).appendTo(content_div);
+
+ content_div.append(' ');
+
+ if (!that.is_selfsign()) {
+ $('<input/>', {
+ 'type': 'button',
+ 'name': 'revoke',
+ 'value': 'Revoke'
+ }).appendTo(content_div);
+
+ content_div.append(' ');
+ }
+
+ $('<input/>', {
+ 'type': 'button',
+ 'name': 'view',
+ 'value': 'View'
+ }).appendTo(content_div);
+
+ content_div.append(' ');
+
+ $('<input/>', {
+ 'type': 'button',
+ 'name': 'create',
+ 'value': 'New Certificate'
+ }).appendTo(content_div);
+
+ if (!that.is_selfsign()) {
+ div = $('<div/>', {
+ name: 'certificate-revoked'
+ }).appendTo(dd);
+
+ $('<img/>', {
+ src: 'caution.png',
+ style: 'float: left;',
+ 'class': 'status-icon'
+ }).appendTo(div);
+
+ content_div = $('<div/>', {
+ style: 'float: left;'
+ }).appendTo(div);
+
+ content_div.append('<b>Certificate Revoked:</b>');
+
+ content_div.append(' ');
+
+ content_div.append($('<span/>', {
+ 'name': 'revocation_reason'
+ }));
+
+ content_div.append(' ');
+
+ $('<input/>', {
+ 'type': 'button',
+ 'name': 'restore',
+ 'value': 'Restore'
+ }).appendTo(content_div);
+
+ content_div.append(' ');
+
+ $('<input/>', {
+ 'type': 'button',
+ 'name': 'create',
+ 'value': 'New Certificate'
+ }).appendTo(content_div);
+ }
+
+ div = $('<div/>', {
+ name: 'certificate-missing'
+ }).appendTo(dd);
+
+ $('<img/>', {
+ src: 'caution.png',
+ style: 'float: left;',
+ 'class': 'status-icon'
+ }).appendTo(div);
+
+ content_div = $('<div/>', {
+ style: 'float: left;'
+ }).appendTo(div);
+
+ content_div.append('<b>No Valid Certificate:</b>');
+
+ content_div.append(' ');
+
+ $('<input/>', {
+ 'type': 'button',
+ 'name': 'create',
+ 'value': 'New Certificate'
+ }).appendTo(content_div);
+ };
+
+ that.setup = function(container) {
+
+ that.widget_setup(container);
+
+ that.valid = $('div[name=certificate-valid]', that.container);
+ that.revoked = $('div[name=certificate-revoked]', that.container);
+ that.missing = $('div[name=certificate-missing]', that.container);
+
+ var button = $('input[name=get]', that.container);
+ that.get_button = IPA.button({
+ 'label': 'Get',
+ 'click': function() {
+ IPA.cmd(that.entity_name+'_show', [that.pkey], {},
+ function(data, text_status, xhr) {
+ get_certificate(data.result.result);
+ }
+ );
+ }
+ });
+ button.replaceWith(that.get_button);
+
+ button = $('input[name=revoke]', that.container);
+ that.revoke_button = IPA.button({
+ 'label': 'Revoke',
+ 'click': function() {
+ IPA.cmd(that.entity_name+'_show', [that.pkey], {},
+ function(data, text_status, xhr) {
+ revoke_certificate(data.result.result);
+ }
+ );
+ }
+ });
+ button.replaceWith(that.revoke_button);
+
+ button = $('input[name=view]', that.container);
+ that.view_button = IPA.button({
+ 'label': 'View',
+ 'click': function() {
+ IPA.cmd(that.entity_name+'_show', [that.pkey], {},
+ function(data, text_status, xhr) {
+ view_certificate(data.result.result);
+ }
+ );
+ }
+ });
+ button.replaceWith(that.view_button);
+
+ that.revocation_reason = $('span[name=revocation_reason]', that.container);
+
+ button = $('input[name=restore]', that.container);
+ that.restore_button = IPA.button({
+ 'label': 'Restore',
+ 'click': function() {
+ IPA.cmd(that.entity_name+'_show', [that.pkey], {},
+ function(data, text_status, xhr) {
+ restore_certificate(data.result.result);
+ }
+ );
+ }
+ });
+ button.replaceWith(that.restore_button);
+
+ $('input[name=create]', that.container).each(function(index) {
+ button = $(this);
+ that.create_button = IPA.button({
+ 'label': 'New Certificate',
+ 'click': function() {
+ request_certificate(that.result);
+ }
+ });
+ button.replaceWith(that.create_button);
+ });
+ };
+
+ that.load = function(result) {
+
+ that.result = result;
+ that.pkey = that.get_entity_pkey(that.result);
+
+ var entity_certificate = that.get_entity_certificate(that.result);
+ if (entity_certificate) {
+ check_status(that.result.serial_number);
+ } else {
+ set_status(CERTIFICATE_STATUS_MISSING);
+ }
+ };
+
+ function set_status(status, revocation_reason) {
+ that.valid.css('display', status == CERTIFICATE_STATUS_VALID ? 'inline' : 'none');
+ that.missing.css('display', status == CERTIFICATE_STATUS_MISSING ? 'inline' : 'none');
+
+ if (!that.is_selfsign()) {
+ that.revoked.css('display', status == CERTIFICATE_STATUS_REVOKED ? 'inline' : 'none');
+ that.revoke_button.css('visibility', status == CERTIFICATE_STATUS_VALID ? 'visible' : 'hidden');
+ that.revocation_reason.html(revocation_reason == undefined ? '' : CRL_REASON[revocation_reason]);
+ that.restore_button.css('visibility', revocation_reason == 6 ? 'visible' : 'hidden');
+ }
+ }
+
+ function check_status(serial_number) {
+
+ if (that.is_selfsign()) {
+ set_status(CERTIFICATE_STATUS_VALID);
+ return;
+ }
+
+ IPA.cmd(
+ 'cert_show',
+ [serial_number],
+ { },
+ function(data, text_status, xhr) {
+ var revocation_reason = data.result.result.revocation_reason;
+ if (revocation_reason == undefined) {
+ set_status(CERTIFICATE_STATUS_VALID);
+ } else {
+ set_status(CERTIFICATE_STATUS_REVOKED, revocation_reason);
+ }
+ }
+ );
+ }
+
+ function view_certificate(result) {
+
+ var entity_certificate = that.get_entity_certificate(result);
+ if (!entity_certificate) {
+ set_status(CERTIFICATE_STATUS_MISSING);
+ return;
+ }
+
+ var entity_name = that.get_entity_name(result);
+
+ var dialog = certificate_view_dialog({
+ 'title': 'Certificate for '+that.entity_label+' '+entity_name,
+ 'subject': result['subject'],
+ 'serial_number': result['serial_number'],
+ 'issuer': result['issuer'],
+ 'issued_on': result['valid_not_before'],
+ 'expires_on': result['valid_not_after'],
+ 'md5_fingerprint': result['md5_fingerprint'],
+ 'sha1_fingerprint': result['sha1_fingerprint']
+ });
+
+ dialog.open();
+ }
+
+ function get_certificate(result) {
+
+ var entity_certificate = that.get_entity_certificate(result);
+ if (!entity_certificate) {
+ set_status(CERTIFICATE_STATUS_MISSING);
+ return;
+ }
+
+ var entity_name = that.get_entity_name(result);
+
+ var dialog = certificate_get_dialog({
+ 'title': 'Certificate for '+that.entity_label+' '+entity_name,
+ 'usercertificate': entity_certificate
+ });
+
+ dialog.open();
+ }
+
+ function request_certificate(result) {
+
+ var entity_name = that.get_entity_name(result);
+ var entity_principal = that.get_entity_principal(result);
+
+ var dialog = certificate_request_dialog({
+ 'title': 'Issue New Certificate for '+that.entity_label+' '+entity_name,
+ 'request': function(values) {
+ var request = values['request'];
+
+ IPA.cmd(
+ 'cert_request',
+ [request],
+ {
+ 'principal': entity_principal
+ },
+ function(data, text_status, xhr) {
+ check_status(data.result.result.serial_number);
+ }
+ );
+ }
+ });
+
+ dialog.open();
+ }
+
+ function revoke_certificate(result) {
+
+ var entity_certificate = that.get_entity_certificate(result);
+ if (!entity_certificate) {
+ set_status(CERTIFICATE_STATUS_MISSING);
+ return;
+ }
+
+ var entity_name = that.get_entity_name(result);
+ var serial_number = result['serial_number'];
+
+ var dialog = certificate_revoke_dialog({
+ 'title': 'Revoke Certificate for '+that.entity_label+' '+entity_name,
+ 'revoke': function(values) {
+ var reason = values['reason'];
+
+ IPA.cmd(
+ 'cert_revoke',
+ [serial_number],
+ {
+ 'revocation_reason': reason
+ },
+ function(data, text_status, xhr) {
+ check_status(serial_number);
+ }
+ );
+ }
+ });
+
+ dialog.open();
+ }
+
+ function restore_certificate(result) {
+
+ var entity_certificate = that.get_entity_certificate(result);
+ if (!entity_certificate) {
+ set_status(CERTIFICATE_STATUS_MISSING);
+ return;
+ }
+
+ var entity_name = that.get_entity_name(result);
+ var serial_number = result['serial_number'];
+
+ var dialog = certificate_restore_dialog({
+ 'title': 'Restore Certificate for '+that.entity_label+' '+entity_name,
+ 'restore': function(values) {
+ IPA.cmd(
+ 'cert_remove_hold',
+ [serial_number],
+ { },
+ function(data, text_status, xhr) {
+ check_status(serial_number);
+ }
+ );
+ }
+ });
+
+ dialog.open();
+ }
+
+ return that;
+}