diff options
-rw-r--r-- | install/static/Makefile.am | 1 | ||||
-rwxr-xr-x | install/static/certificate.js | 381 | ||||
-rw-r--r-- | install/static/index.xhtml | 1 | ||||
-rw-r--r-- | install/static/service.js | 250 | ||||
-rw-r--r-- | install/static/test/data/cert_remove_hold.json | 9 | ||||
-rw-r--r-- | install/static/test/data/cert_request.json | 17 | ||||
-rw-r--r-- | install/static/test/data/cert_revoke.json | 9 | ||||
-rw-r--r-- | install/static/test/data/json_metadata.json | 176 | ||||
-rw-r--r-- | install/static/test/data/service_show.json | 9 | ||||
-rw-r--r-- | ipalib/plugins/service.py | 41 |
10 files changed, 861 insertions, 33 deletions
diff --git a/install/static/Makefile.am b/install/static/Makefile.am index 8071d25f..ee8384c7 100644 --- a/install/static/Makefile.am +++ b/install/static/Makefile.am @@ -20,6 +20,7 @@ app_DATA = \ jquery-ui.js \ jquery.ba-bbq.js \ jquery-ui.css \ + certificate.js \ group.js \ host.js \ hostgroup.js \ diff --git a/install/static/certificate.js b/install/static/certificate.js new file mode 100755 index 00000000..4302e2f8 --- /dev/null +++ b/install/static/certificate.js @@ -0,0 +1,381 @@ +/* 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; version 2 only + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +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' +]; + +function certificate_parse_dn(dn) { + + var result = {}; + + // TODO: Use proper LDAP DN parser + var rdns = dn.split(','); + for (var i=0; i<rdns.length; i++) { + var rdn = rdns[i]; + var parts = rdn.split('='); + var name = parts[0].toLowerCase(); + var value = parts[1]; + + result[name] = value; + } + + return result; +} + +function certificate_confirmation_dialog(spec) { + var that = {}; + spec = spec || {}; + + var dialog = $('<div/>', { + 'title': spec.title + }); + + dialog.append(spec.message); + + that.open = function() { + dialog.dialog({ + modal: true, + width: 300, + height: 150, + buttons: { + 'Close': function() { + dialog.dialog('destroy'); + } + } + }); + }; + + return that; +} + +function certificate_get_dialog(spec) { + var that = {}; + spec = spec || {}; + + var dialog = $('<div/>', { + 'title': spec.title + }); + + var textarea = $('<textarea/>', { + readonly: 'yes', + style: 'width: 100%; height: 275px;' + }).appendTo(dialog); + + textarea.val( + BEGIN_CERTIFICATE_REQUEST+'\n'+ + spec.usercertificate+'\n'+ + END_CERTIFICATE_REQUEST + ); + + 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 || {}; + + var dialog = $('<div/>', { + 'title': spec.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 (spec.revoke) { + spec.revoke(values); + } + dialog.dialog('destroy'); + }, + 'Cancel': function() { + dialog.dialog('destroy'); + } + } + }); + }; + + return that; +} + +function certificate_restore_dialog(spec) { + var that = {}; + spec = spec || {}; + + var dialog = $('<div/>', { + 'title': spec.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 (spec.restore) { + spec.restore(values); + } + dialog.dialog('destroy'); + }, + 'Cancel': function() { + dialog.dialog('destroy'); + } + } + }); + }; + + return that; +} + +function certificate_view_dialog(spec) { + var that = {}; + spec = spec || {}; + + that.subject = certificate_parse_dn(spec.subject); + that.issuer = certificate_parse_dn(spec.issuer); + + var dialog = $('<div/>', { + 'title': spec.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': spec.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': spec.issued_on + }).appendTo(tr); + + tr = $('<tr/>').appendTo(table); + $('<td>Expires On:</td>').appendTo(tr); + $('<td/>', { + 'html': spec.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': spec.sha1_fingerprint + }).appendTo(tr); + + tr = $('<tr/>').appendTo(table); + $('<td>MD5 Fingerprint:</td>').appendTo(tr); + $('<td/>', { + 'html': spec.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 || {}; + + var dialog = $('<div/>', { + 'title': spec.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 (spec.request) { + spec.request(values); + } + dialog.dialog('destroy'); + }, + 'Cancel': function() { + dialog.dialog('destroy'); + } + } + }); + }; + + return that; +} diff --git a/install/static/index.xhtml b/install/static/index.xhtml index 338ddbb6..58c631e8 100644 --- a/install/static/index.xhtml +++ b/install/static/index.xhtml @@ -19,6 +19,7 @@ <script type="text/javascript" src="entity.js"></script> <script type="text/javascript" src="navigation.js"></script> + <script type="text/javascript" src="certificate.js"></script> <script type="text/javascript" src="user.js"></script> <script type="text/javascript" src="group.js"></script> <script type="text/javascript" src="host.js"></script> diff --git a/install/static/service.js b/install/static/service.js index 7b81c4d2..d688b9ad 100644 --- a/install/static/service.js +++ b/install/static/service.js @@ -34,16 +34,19 @@ ipa_entity_set_add_definition('service', [ ]); ipa_entity_set_details_definition('service', [ - ipa_stanza({name:'identity', label:'Service Details'}). + ipa_stanza({name:'details', label:'Service Details'}). input({name:'krbprincipalname', label:'Principal', setup:service_krbprincipalname_setup, load:service_krbprincipalname_load}). input({name:'service', label:'Service', load:service_service_load}). - input({name:'host', label:'Host Name', load:service_host_load}). - input({name:'usercertificate', label:'Certificate', - load:service_usercertificate_load, - save:service_usercertificate_save}) + input({name:'host', label:'Host Name', load:service_host_load}), + ipa_stanza({name:'provisioning', label:'Provisioning'}). + input({name:'provisioning_status', label:'Status', + load:service_provisioning_status_load}), + ipa_stanza({name:'certificate', label:'Service Certificate'}). + input({name:'certificate_status', label:'Status', + load:service_usercertificate_load}) ]); function service_add_krbprincipalname(add_dialog, mode) { @@ -76,45 +79,234 @@ function service_service_load(container, dt, result) { function service_host_load(container, dt, result) { var krbprincipalname = result['krbprincipalname'][0]; - var host = krbprincipalname.replace(/^.*\//, ''); + var host = krbprincipalname.replace(/^.*\//, '').replace(/@.*$/, ''); var dd = ipa_create_first_dd(this.name, host); dt.after(dd); } -function service_usercertificate_load(container, dt, result) { - var textarea = $("<textarea/>", { - title: 'usercertificate', - style: 'width: 300px; height: 200px;' +function service_provisioning_status_load(container, dt, result) { + // skip provisioning_status +} + +function service_usercertificate_get(result) { + + var usercertificate = result['usercertificate']; + if (!usercertificate) { + alert('Service has no usercertificate.'); + return; + } + + var krbprincipalname = result['krbprincipalname'][0]; + var service_name = krbprincipalname.replace(/@.*$/, ''); + + var dialog = certificate_get_dialog({ + 'title': 'Certificate for Service '+service_name, + 'usercertificate': usercertificate[0].__base64__ }); - var dd = ipa_create_first_dd(this.name, textarea); - dt.after(dd); + dialog.open(); +} + +function service_usercertificate_view(result) { var usercertificate = result['usercertificate']; - if (!usercertificate) return; + if (!usercertificate) { + alert('Service has no usercertificate.'); + return; + } + + var krbprincipalname = result['krbprincipalname'][0]; + var service_name = krbprincipalname.replace(/@.*$/, ''); + + var dialog = certificate_view_dialog({ + 'title': 'Certificate for Service '+service_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'] + }); - var value = usercertificate[0].__base64__; - textarea.val(value); + dialog.open(); } -function service_usercertificate_save(container) { - var field = this; - var values = []; +function service_usercertificate_revoke(result) { - var dd = $('dd[title='+field.name+']', container); - dd.each(function () { - var textarea = $('textarea', dd); - if (!textarea.length) return; + var usercertificate = result['usercertificate']; + if (!usercertificate) { + alert('Service has no usercertificate.'); + return; + } + + var krbprincipalname = result['krbprincipalname'][0]; + var service_name = krbprincipalname.replace(/@.*$/, ''); + + var serial_number = result['serial_number']; - var value = $.trim(textarea.val()); - if (value) { - value = {'__base64__': value}; - } else { - value = ''; + var dialog = certificate_revoke_dialog({ + 'title': 'Revoke Certificate for Service '+service_name, + 'revoke': function(values) { + var reason = values['reason']; + + ipa_cmd( + 'cert_revoke', + [serial_number], + { + 'revocation_reason': reason + }, + function(data, text_status, xhr) { + var dialog = certificate_confirmation_dialog({ + title: 'Success', + message: 'Certificate has been revoked successfully.' + }); + dialog.open(); + } + ); } + }); + + dialog.open(); +} - values.push(value); +function service_usercertificate_restore(result) { + + var usercertificate = result['usercertificate']; + if (!usercertificate) { + alert('Service has no usercertificate.'); + return; + } + + var krbprincipalname = result['krbprincipalname'][0]; + var service_name = krbprincipalname.replace(/@.*$/, ''); + + var serial_number = result['serial_number']; + + var dialog = certificate_restore_dialog({ + 'title': 'Restore Certificate for Service '+service_name, + 'restore': function(values) { + ipa_cmd( + 'cert_remove_hold', + [serial_number], + { }, + function(data, text_status, xhr) { + var dialog = certificate_confirmation_dialog({ + title: 'Success', + message: 'Certificate has been restored successfully.' + }); + dialog.open(); + } + ); + } }); - return values; + dialog.open(); +} + +function service_usercertificate_request(result) { + + var krbprincipalname = result['krbprincipalname'][0]; + var service_name = krbprincipalname.replace(/@.*$/, ''); + + var dialog = certificate_request_dialog({ + 'title': 'Issue New Certificate for Service '+service_name, + 'request': function(values) { + var request = values['request']; + + ipa_cmd( + 'cert_request', + [request], + { + 'principal': krbprincipalname + } + ); + } + }); + + dialog.open(); +} + +function service_usercertificate_load(container, dt, result) { + + var krbprincipalname = result['krbprincipalname'][0]; + + var table = $('<table/>'); + + var tr = $('<tr/>').appendTo(table); + + var td = $('<td/>').appendTo(tr); + td.append('Valid Certificate Present:'); + + td = $('<td/>').appendTo(tr); + $('<input/>', { + type: 'button', + value: 'Get', + click: function() { + ipa_cmd('service_show', [krbprincipalname], {}, + function(data, text_status, xhr) { + service_usercertificate_get(data.result.result); + } + ); + } + }).appendTo(td); + + $('<input/>', { + type: 'button', + value: 'Revoke', + click: function() { + ipa_cmd('service_show', [krbprincipalname], {}, + function(data, text_status, xhr) { + service_usercertificate_revoke(data.result.result); + } + ); + } + }).appendTo(td); + + $('<input/>', { + type: 'button', + value: 'View', + click: function() { + ipa_cmd('service_show', [krbprincipalname], {}, + function(data, text_status, xhr) { + service_usercertificate_view(data.result.result); + } + ); + } + }).appendTo(td); + + tr = $('<tr/>').appendTo(table); + + td = $('<td/>').appendTo(tr); + td.append('Certificate Revoked:'); + + td = $('<td/>').appendTo(tr); + $('<input/>', { + type: 'button', + value: 'Restore', + click: function() { + ipa_cmd('service_show', [krbprincipalname], {}, + function(data, text_status, xhr) { + service_usercertificate_restore(data.result.result); + } + ); + } + }).appendTo(td); + + tr = $('<tr/>').appendTo(table); + + td = $('<td/>').appendTo(tr); + td.append('No Valid Certificate:'); + + td = $('<td/>').appendTo(tr); + $('<input/>', { + type: 'button', + value: 'New Certificate', + click: function() { + service_usercertificate_request(result); + } + }).appendTo(td); + + var dd = ipa_create_first_dd(this.name, table); + dt.after(dd); } diff --git a/install/static/test/data/cert_remove_hold.json b/install/static/test/data/cert_remove_hold.json new file mode 100644 index 00000000..12548cb2 --- /dev/null +++ b/install/static/test/data/cert_remove_hold.json @@ -0,0 +1,9 @@ +{ + "error": null, + "id": 0, + "result": { + "result": { + "unrevoked": true + } + } +} diff --git a/install/static/test/data/cert_request.json b/install/static/test/data/cert_request.json new file mode 100644 index 00000000..190a4443 --- /dev/null +++ b/install/static/test/data/cert_request.json @@ -0,0 +1,17 @@ +{ + "error": null, + "id": 0, + "result": { + "result": { + "certificate": "MIIC2DCCAcCgAwIBAgIBFTANBgkqhkiG9w0BAQsFADAuMQwwCgYDVQQKEwNJUEExHjAcBgNVBAMTFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xMDEwMTUwNTE3MzZaFw0xMTA0MTMwNTE3MzZaMCgxDDAKBgNVBAoTA0lQQTEYMBYGA1UEAxMPZGV2LmV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDk18o/IK1Qe0Y/eURWsIHcJ/TmGdNy1h2fhzGIILtv8Qgq1K3U4T9eGAZVambpo1SUnJY+k+AAo43TyavSU05se4DIsw00XrrOyD5UunwsW+b+cIUCWbBJLFy9ODsVDJduXrj0RZGHEyta3VuO/gJBtdI9anjVvgegqXUBkenjPwIDAQABo4GKMIGHMB8GA1UdIwQYMBaAFCv9XyGV5ijtHriYMcECVmnNiMMAMD8GCCsGAQUFBwEBBDMwMTAvBggrBgEFBQcwAYYjaHR0cDovL2Rldi5leGFtcGxlLmNvbTo5MTgwL2NhL29jc3AwDgYDVR0PAQH/BAQDAgTwMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4IBAQB/OtoBZUYuGD0KZWpNdzIVdCxCTzZAetHA+o97cZCdufiBckZfZ9LEkQdL2MWvcnLlXOnRnQO/BnEAAtYVe4dpmizuzPn1+JTmK9+7q2HhQhXuU2NcsWutgYySNme7eNmfqi8uDoQ8FOPX4LvxLQDyKjkOogs6cEMZePMK8RE60ulHKdYfI23rRNtIExOl1zLJXkpExuXNq1flshyaLLu84B9zwE5FhSD/XAjPyAqYP97IPIkUfWpMyEs3N12JVCVNm0/753CDI946RPnyPpsULZufBV/8sdhDnULHfPIUMPgdOYemm9cYTP/V1uhwwCnFemhSAXSM/g6e9Xm4hH7s", + "issuer": "CN=Certificate Authority,O=IPA", + "md5_fingerprint": "87:ca:33:52:e3:07:4c:82:76:24:8d:53:ba:da:b3:fe", + "request_id": "50", + "serial_number": "1", + "sha1_fingerprint": "9f:fc:d3:e2:3b:f0:c1:1d:fc:5c:09:fa:f4:10:de:7b:b2:25:ae:7c", + "subject": "CN=dev.example.com,O=IPA", + "valid_not_after": "Wed Apr 13 05:17:36 2011 UTC", + "valid_not_before": "Fri Oct 15 05:17:36 2010 UTC" + } + } +} diff --git a/install/static/test/data/cert_revoke.json b/install/static/test/data/cert_revoke.json new file mode 100644 index 00000000..3fca1ee6 --- /dev/null +++ b/install/static/test/data/cert_revoke.json @@ -0,0 +1,9 @@ +{ + "error": null, + "id": 0, + "result": { + "result": { + "revoked": true + } + } +} diff --git a/install/static/test/data/json_metadata.json b/install/static/test/data/json_metadata.json index cd617b48..e1cbffb5 100644 --- a/install/static/test/data/json_metadata.json +++ b/install/static/test/data/json_metadata.json @@ -2976,6 +2976,180 @@ "query": false, "required": false, "type": "str" + }, + { + "attribute": false, + "autofill": false, + "class": "Str", + "cli_name": "issuer", + "cli_short_name": null, + "default": null, + "doc": "Issuer", + "exclude": null, + "flags": [ + "no_update", + "no_create", + "no_search" + ], + "hint": null, + "include": null, + "label": "Issuer", + "length": null, + "maxlength": null, + "minlength": null, + "multivalue": false, + "name": "issuer", + "pattern": null, + "pattern_errmsg": null, + "primary_key": false, + "query": false, + "required": false, + "type": "unicode" + }, + { + "attribute": false, + "autofill": false, + "class": "Str", + "cli_name": "valid_not_before", + "cli_short_name": null, + "default": null, + "doc": "Not Before", + "exclude": null, + "flags": [ + "no_update", + "no_create", + "no_search" + ], + "hint": null, + "include": null, + "label": "Not Before", + "length": null, + "maxlength": null, + "minlength": null, + "multivalue": false, + "name": "valid_not_before", + "pattern": null, + "pattern_errmsg": null, + "primary_key": false, + "query": false, + "required": false, + "type": "unicode" + }, + { + "attribute": false, + "autofill": false, + "class": "Str", + "cli_name": "valid_not_after", + "cli_short_name": null, + "default": null, + "doc": "Not After", + "exclude": null, + "flags": [ + "no_update", + "no_create", + "no_search" + ], + "hint": null, + "include": null, + "label": "Not After", + "length": null, + "maxlength": null, + "minlength": null, + "multivalue": false, + "name": "valid_not_after", + "pattern": null, + "pattern_errmsg": null, + "primary_key": false, + "query": false, + "required": false, + "type": "unicode" + }, + { + "attribute": false, + "autofill": false, + "class": "Str", + "cli_name": "md5_fingerprint", + "cli_short_name": null, + "default": null, + "doc": "Fingerprint (MD5)", + "exclude": null, + "flags": [ + "no_update", + "no_create", + "no_search" + ], + "hint": null, + "include": null, + "label": "Fingerprint (MD5)", + "length": null, + "maxlength": null, + "minlength": null, + "multivalue": false, + "name": "md5_fingerprint", + "pattern": null, + "pattern_errmsg": null, + "primary_key": false, + "query": false, + "required": false, + "type": "unicode" + }, + { + "attribute": false, + "autofill": false, + "class": "Str", + "cli_name": "sha1_fingerprint", + "cli_short_name": null, + "default": null, + "doc": "Fingerprint (SHA1)", + "exclude": null, + "flags": [ + "no_update", + "no_create", + "no_search" + ], + "hint": null, + "include": null, + "label": "Fingerprint (SHA1)", + "length": null, + "maxlength": null, + "minlength": null, + "multivalue": false, + "name": "sha1_fingerprint", + "pattern": null, + "pattern_errmsg": null, + "primary_key": false, + "query": false, + "required": false, + "type": "unicode" + }, + { + "attribute": false, + "autofill": false, + "class": "Str", + "cli_name": "serial_number", + "cli_short_name": null, + "default": null, + "doc": "Serial number", + "exclude": null, + "flags": [ + "no_update", + "no_create", + "no_search" + ], + "hint": null, + "include": null, + "label": "Serial number", + "length": null, + "maxlength": null, + "minlength": null, + "multivalue": false, + "name": "serial_number", + "pattern": null, + "pattern_errmsg": null, + "primary_key": false, + "query": false, + "required": false, + "type": "unicode" } ], "uuid_attribute": "ipauniqueid" @@ -4163,4 +4337,4 @@ } } } -}
\ No newline at end of file +} diff --git a/install/static/test/data/service_show.json b/install/static/test/data/service_show.json index 7ab778e1..d01f8585 100644 --- a/install/static/test/data/service_show.json +++ b/install/static/test/data/service_show.json @@ -5,17 +5,24 @@ "result": { "dn": "krbprincipalname=test/dev.example.com@dev.example.com,cn=services,cn=accounts,dc=dev,dc=example,dc=com", "has_keytab": false, + "issuer": "CN=IPA Test Certificate Authority", "krbprincipalname": [ "test/dev.example.com@DEV.EXAMPLE.COM" ], "managedby_host": [ "dev.example.com" ], + "md5_fingerprint": "08:86:a9:f9:87:af:0d:d7:42:01:e0:5f:12:9b:32:7f", + "serial_number": "1052", + "sha1_fingerprint": "b8:4c:4b:79:4f:13:03:79:47:08:fa:6b:52:63:3d:f9:15:8e:7e:dc", + "subject": "CN=dev.example.com,O=IPA", "usercertificate": [ { "__base64__": "MIICAjCCAWugAwIBAgICBAswDQYJKoZIhvcNAQEFBQAwKTEnMCUGA1UEAxMeSVBBIFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMTAwNzIzMzk0NFoXDTE1MTAwNzIzMzk0NFowKDEMMAoGA1UECgwDSVBBMRgwFgYDVQQDDA9kZXYuZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOTXyj8grVB7Rj95RFawgdwn9OYZ03LWHZ+HMYggu2/xCCrUrdThP14YBlVqZumjVJSclj6T4ACjjdPJq9JTTmx7gMizDTReus7IPlS6fCxb5v5whQJZsEksXL04OxUMl25euPRFkYcTK1rdW47+AkG10j1qeNW+B6CpdQGR6eM/AgMBAAGjOjA4MBEGCWCGSAGG+EIBAQQEAwIGQDATBgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8EBAMCBPAwDQYJKoZIhvcNAQEFBQADgYEASIhq723VL5xP0q51MYXFlGU1boD7pPD1pIQspD/MjCIEupcbH2kAo4wf+EiKsXR0rs+WZkaSgvFqaM4OQ2kWSFTiqmFXFDBEi6EFr68yLg7IpQpNTzVBXERd8B4GwNL9wrRw60jPXlUK29DPBsdGq8fDgX18l39wKkWXv7p1to4=" } - ] + ], + "valid_not_after": "Tue Oct 13 01:59:32 2015 UTC", + "valid_not_before": "Wed Oct 13 01:59:32 2010 UTC" }, "summary": null, "value": "test/dev.example.com@DEV.EXAMPLE.COM" diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py index 1e1dcd82..8ccdaeac 100644 --- a/ipalib/plugins/service.py +++ b/ipalib/plugins/service.py @@ -76,6 +76,7 @@ from ipalib.plugins.baseldap import * from ipalib import x509 from ipalib import _, ngettext from ipalib import util +import nss.nss as nss from nss.error import NSPRError @@ -203,7 +204,7 @@ class service(LDAPObject): cli_name='certificate', label=_('Certificate'), doc=_('Base-64 encoded server certificate'), - ), + ) ) api.register(service) @@ -357,7 +358,33 @@ class service_show(LDAPRetrieve): """ member_attributes = ['managedby'] takes_options = LDAPRetrieve.takes_options - has_output_params = LDAPRetrieve.has_output_params + output_params + + has_output_params = LDAPRetrieve.has_output_params + output_params + ( + Str('subject', + label=_('Subject'), + ), + Str('serial_number', + label=_('Serial Number'), + ), + Str('issuer', + label=_('Issuer'), + ), + Str('valid_not_before', + label=_('Not Before'), + ), + Str('valid_not_after', + label=_('Not After'), + ), + Str('md5_fingerprint', + label=_('Fingerprint (MD5)'), + ), + Str('sha1_fingerprint', + label=_('Fingerprint (SHA1)'), + ), + Str('revocation_reason?', + label=_('Revocation reason'), + ) + ) def post_callback(self, ldap, dn, entry_attrs, *keys, **options): if 'krblastpwdchange' in entry_attrs: @@ -367,6 +394,16 @@ class service_show(LDAPRetrieve): else: entry_attrs['has_keytab'] = False + if 'usercertificate' in entry_attrs: + cert = x509.load_certificate(entry_attrs['usercertificate'][0], datatype=x509.DER) + entry_attrs['subject'] = unicode(cert.subject) + entry_attrs['serial_number'] = unicode(cert.serial_number) + entry_attrs['issuer'] = unicode(cert.issuer) + entry_attrs['valid_not_before'] = unicode(cert.valid_not_before_str) + entry_attrs['valid_not_after'] = unicode(cert.valid_not_after_str) + entry_attrs['md5_fingerprint'] = unicode(nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0]) + entry_attrs['sha1_fingerprint'] = unicode(nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0]) + return dn api.register(service_show) |