Repository: cloudstack
Updated Branches:
  refs/heads/4.4 bbaefb8e5 -> d0ff6cd46


CLOUDSTACK-6695: Added support to the UI for uploading a chain of certificates

In the "SSL Certificate" dialog we added:
- new field for the root certificate;
- a button to add intermediate certificates if necessary; when this is pressed, 
a new field, called "Intermediate certificate 1" is added; pressed again, 
"Intermediate certificate 2" field is added, and so on.

We upload the certificates in order: first the root certificate (with id=1), 
then the intermediate certificates (with id=2,3,..) and finally the server 
certificate.
When uploading a certificate, we wait for the upload to be completed 
successfully and only then we proceed to uploading the next one. If one fails, 
we report failure and don't continue with the remaining.

Signed-off-by: Mihaela Stoica <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/d0ff6cd4
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/d0ff6cd4
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/d0ff6cd4

Branch: refs/heads/4.4
Commit: d0ff6cd461d9169133a7782850c93c9a3e994ba8
Parents: bbaefb8
Author: Jessica Wang <[email protected]>
Authored: Fri Aug 8 11:38:31 2014 -0700
Committer: Jessica Wang <[email protected]>
Committed: Fri Aug 8 11:39:38 2014 -0700

----------------------------------------------------------------------
 .../classes/resources/messages.properties       |   9 +-
 ui/css/cloudstack3.css                          |  20 +-
 ui/dictionary.jsp                               |   5 +-
 ui/scripts/ui-custom/physicalResources.js       | 187 ++++++++++++++-----
 4 files changed, 170 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d0ff6cd4/client/WEB-INF/classes/resources/messages.properties
----------------------------------------------------------------------
diff --git a/client/WEB-INF/classes/resources/messages.properties 
b/client/WEB-INF/classes/resources/messages.properties
index eff2c3e..fec0c6d 100644
--- a/client/WEB-INF/classes/resources/messages.properties
+++ b/client/WEB-INF/classes/resources/messages.properties
@@ -312,6 +312,7 @@ label.add.firewall=Add firewall rule
 label.add.guest.network=Add guest network
 label.add.host=Add Host
 label.add.ingress.rule=Add Ingress Rule
+label.add.intermediate.certificate=Add intermediate certificate
 label.add.ip.range=Add IP Range
 label.add.load.balancer=Add Load Balancer
 label.add.more=Add More
@@ -425,7 +426,9 @@ label.bytes.received=Bytes Received
 label.bytes.sent=Bytes Sent
 label.cancel=Cancel
 label.capacity=Capacity
-label.certificate=Certificate
+label.capacity.bytes=Capacity Bytes
+label.capacity.iops=Capacity IOPS
+label.certificate=Server certificate
 label.change.service.offering=Change service offering
 label.change.value=Change value
 label.character=Character
@@ -669,6 +672,7 @@ label.instance.limits=Instance Limits
 label.instance.name=Instance Name
 label.instance=Instance
 label.instances=Instances
+label.intermediate.certificate=Intermediate certificate {0}
 label.internal.dns.1=Internal DNS 1
 label.internal.dns.2=Internal DNS 2
 label.internal.name=Internal name
@@ -1008,6 +1012,7 @@ label.restore=Restore
 label.review=Review
 label.revoke.project.invite=Revoke invitation
 label.role=Role
+label.root.certificate=Root certificate
 label.root.disk.controller=Root disk controller
 label.root.disk.offering=Root Disk Offering
 label.round.robin=Round-robin
@@ -1804,7 +1809,7 @@ message.tooltip.reserved.system.netmask=The network 
prefix that defines the pod
 message.tooltip.zone.name=A name for the zone.
 message.update.os.preference=Please choose a OS preference for this host.  All 
virtual instances with similar preferences will be first allocated to this host 
before choosing another.
 message.update.resource.count=Please confirm that you want to update resource 
counts for this account.
-message.update.ssl=Please submit a new X.509 compliant SSL certificate to be 
updated to each console proxy and secondary storage virtual instance\:
+message.update.ssl=Please submit a new X.509 compliant SSL certificate chain 
to be updated to each console proxy and secondary storage virtual instance\:
 message.validate.instance.name=Instance name can not be longer than 63 
characters. Only ASCII letters a~z, A~Z, digits 0~9, hyphen are allowed. Must 
start with a letter and end with a letter or a digit.
 message.virtual.network.desc=A dedicated virtualized network for your account. 
 The broadcast domain is contained within a VLAN and all public network access 
is routed out by a virtual router.
 message.vm.create.template.confirm=Create Template will reboot the VM 
automatically.

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d0ff6cd4/ui/css/cloudstack3.css
----------------------------------------------------------------------
diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css
index 17441c4..ad3ab56 100644
--- a/ui/css/cloudstack3.css
+++ b/ui/css/cloudstack3.css
@@ -4052,7 +4052,7 @@ Dialogs*/
   display: inline-block;
 }
 
-.ui-dialog div.form-container div.value input {
+.ui-dialog div.form-container div.value input, textarea {
   width: 98%;
   font-size: 14px;
   padding: 4px;
@@ -12983,3 +12983,21 @@ div.gpugroups div.list-view {
   padding: 12px 12px 5px;
 }
 
+.ui-dialog .ui-button.add {
+    background: linear-gradient(to bottom, #f7f7f7 1%, #eaeaea 100%) repeat 
scroll 0px 0px transparent;
+    font-size: 12px;
+    height: 12px;
+    width: auto;
+    margin: 0px 0px 12px;
+    padding: 5px 7px 5px 6px;
+}
+
+.ui-dialog .ui-button.add:hover {
+    background: none repeat scroll 0px 0px #e5e5e5;
+    box-shadow: 0px 0px 5px #c3c3c3 inset;
+}
+
+.ui-dialog .ui-button.add span {
+    background: url("../images/icons.png") no-repeat scroll -626px -209px 
transparent;
+    padding: 0 0 3px 18px;
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d0ff6cd4/ui/dictionary.jsp
----------------------------------------------------------------------
diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp
index b668bb5..e2120ac 100644
--- a/ui/dictionary.jsp
+++ b/ui/dictionary.jsp
@@ -1882,7 +1882,10 @@ dictionary = {
 'message.confirm.enable.vpc.offering': '<fmt:message 
key="message.confirm.enable.vpc.offering" />',
 'message.enabling.vpc.offering': '<fmt:message 
key="message.enabling.vpc.offering" />',
 'message.confirm.remove.vpc.offering': '<fmt:message 
key="message.confirm.remove.vpc.offering" />',
-'message.confirm.disable.vpc.offering': '<fmt:message 
key="message.confirm.disable.vpc.offering" />'
+'message.confirm.disable.vpc.offering': '<fmt:message 
key="message.confirm.disable.vpc.offering" />',
+'label.root.certificate': '<fmt:message key="label.root.certificate" />',
+'label.intermediate.certificate': '<fmt:message 
key="label.intermediate.certificate" />',
+'label.add.intermediate.certificate': '<fmt:message 
key="label.add.intermediate.certificate" />'
 
 };
 </script>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d0ff6cd4/ui/scripts/ui-custom/physicalResources.js
----------------------------------------------------------------------
diff --git a/ui/scripts/ui-custom/physicalResources.js 
b/ui/scripts/ui-custom/physicalResources.js
index ac379b4..110945e 100644
--- a/ui/scripts/ui-custom/physicalResources.js
+++ b/ui/scripts/ui-custom/physicalResources.js
@@ -96,72 +96,165 @@
                     form: {
                         title: 'label.update.ssl',
                         desc: 'message.update.ssl',
+                        preFilter: function (args) {
+                            var $form = args.$form;
+
+                            // insert the "Add intermediate certificate" button
+                            var $addButton = $('<div>')
+                                .addClass('add ui-button')
+                                .append(
+                                    
$('<span>').html(_l('label.add.intermediate.certificate'))
+                                );
+                            var $servercertificate = 
$form.find('.form-item[rel=certificate]');
+                            $addButton.insertBefore($servercertificate);
+                            var count = 0;
+                            var $intermediatecertificate = 
$form.find('.form-item[rel=intermediatecertificate]');
+
+                            $addButton.click(function() {
+                                // clone the template intermediate certificate 
and make it visible
+                                var $newcertificate = 
$intermediatecertificate.clone().attr('id','intermediate'+count);
+                                $newcertificate.insertBefore($addButton);
+                                $newcertificate.css('display', 'inline-block');
+                                $newcertificate.addClass('sslcertificate');
+                                count++;
+                                // change label
+                                var $label = $newcertificate.find('label');
+                                $label.html($label.html().replace('{0}', 
count)); // 'Intermediate certificate ' + count + ':'
+                            });
+                        },
                         fields: {
+                            rootcertificate: {
+                                label: 'label.root.certificate',
+                                isTextarea: true,
+                                validation: { required: true }
+                            },
+                            intermediatecertificate: { // this is the template 
'intermediate certificate', always hidden
+                                label: 'label.intermediate.certificate',
+                                isTextarea: true,
+                                isHidden: true
+                            },
                             certificate: {
                                 label: 'label.certificate',
-                                isTextarea: true
+                                isTextarea: true,
+                                validation: { required: true }
                             },
                             privatekey: {
                                 label: 'label.privatekey',
-                                isTextarea: true
+                                isTextarea: true,
+                                validation: { required: true }
                             },
                             domainsuffix: {
-                                label: 'label.domain.suffix'
+                                label: 'label.domain.suffix',
+                                validation: { required: true }
                             }
                         }
                     },
                     after: function(args) {
                         var $loading = $('<div>').addClass('loading-overlay');
                         $('.system-dashboard-view:visible').prepend($loading);
-                        $.ajax({
-                            type: "POST",
-                            url: createURL('uploadCustomCertificate'),
-                            data: {
-                                certificate: args.data.certificate,
-                                privatekey: args.data.privatekey,
+
+                        // build a list with all certificates that need to be 
uploaded
+                        var certificates = [];
+                        certificates.push(args.data.rootcertificate);
+                        if ($.isArray(args.data.intermediatecertificate))
+                        {
+                            $.merge(certificates, 
args.data.intermediatecertificate);
+                        }
+                        else
+                        {
+                            
certificates.push(args.data.intermediatecertificate);
+                        }
+                        certificates.push(args.data.certificate);
+
+                        // Recursively uploads certificates.
+                        // When the upload succeeds, proceeds to uploading the 
next certificate.
+                        // When the upload fails, stops and reports failure.
+                        var uploadCertificate = function(index) {
+                            if (index >=  certificates.length)
+                            {
+                                return;
+                            }
+                            if ( !$.trim(certificates[index])) // skip empty 
certificate
+                            {
+                                uploadCertificate(index + 1);
+                                return;
+                            }
+
+                            // build certificate data
+                            var certificateData = {
+                                id: index + 1, // id start from 1
+                                certificate: certificates[index],
                                 domainsuffix: args.data.domainsuffix
-                            },
-                            dataType: 'json',
-                            success: function(json) {
-                                var jid = 
json.uploadcustomcertificateresponse.jobid;
-                                var uploadCustomCertificateIntervalID = 
setInterval(function() {
-                                    $.ajax({
-                                        url: 
createURL("queryAsyncJobResult&jobId=" + jid),
-                                        dataType: "json",
-                                        success: function(json) {
-                                            var result = 
json.queryasyncjobresultresponse;
-                                            if (result.jobstatus == 0) {
-                                                return; //Job has not completed
-                                            } else {
-                                                
clearInterval(uploadCustomCertificateIntervalID);
-                                                if (result.jobstatus == 1) {
-                                                    cloudStack.dialog.notice({
-                                                        message: 'Update SSL 
Certificate succeeded'
-                                                    });
-                                                } else if (result.jobstatus == 
2) {
-                                                    cloudStack.dialog.notice({
-                                                        message: 'Failed to 
update SSL Certificate. ' + _s(result.jobresult.errortext)
-                                                    });
+                            };
+                            switch (index) {
+                                case (0): //first certificate is the root 
certificate
+                                    certificateData['name'] = 'root';
+                                    break;
+                                case (certificates.length - 1): // last 
certificate is the server certificate
+                                    certificateData['privatekey'] = 
args.data.privatekey;
+                                    break;
+                                default: // intermediate certificates
+                                    certificateData['name'] = 'intermediate' + 
index;
+                            }
+
+                            $.ajax({
+                                type: "POST",
+                                url: createURL('uploadCustomCertificate'),
+                                data:  certificateData,
+                                dataType: 'json',
+                                success: function(json) {
+                                    var jid = 
json.uploadcustomcertificateresponse.jobid;
+                                    var uploadCustomCertificateIntervalID = 
setInterval(function() {
+                                        $.ajax({
+                                            url: 
createURL("queryAsyncJobResult&jobId=" + jid),
+                                            dataType: "json",
+                                            success: function(json) {
+                                                var result = 
json.queryasyncjobresultresponse;
+                                                if (result.jobstatus == 0) {
+                                                    return; //Job has not 
completed
+                                                } else {
+                                                    
clearInterval(uploadCustomCertificateIntervalID);
+                                                    if (result.jobstatus == 1) 
{
+                                                        if (index ==  
certificates.length - 1) // last one, report success
+                                                        {
+                                                            
cloudStack.dialog.notice({
+                                                                message: 
'Update SSL Certificates succeeded'
+                                                            });
+                                                            $loading.remove();
+                                                        }
+                                                        else // upload next 
certificate
+                                                        {
+                                                            
uploadCertificate(index + 1);
+                                                        }
+                                                    } else if 
(result.jobstatus == 2) {
+                                                        
cloudStack.dialog.notice({
+                                                            message: 'Failed 
to update SSL Certificate. ' + _s(result.jobresult.errortext)
+                                                        });
+                                                        $loading.remove();
+                                                    }
                                                 }
+                                            },
+                                            error: function(XMLHttpResponse) {
+                                                cloudStack.dialog.notice({
+                                                    message: 'Failed to update 
SSL Certificate. ' + parseXMLHttpResponse(XMLHttpResponse)
+                                                });
                                                 $loading.remove();
                                             }
-                                        },
-                                        error: function(XMLHttpResponse) {
-                                            cloudStack.dialog.notice({
-                                                message: 'Failed to update SSL 
Certificate. ' + parseXMLHttpResponse(XMLHttpResponse)
-                                            });
-                                            $loading.remove();
-                                        }
+                                        });
+                                    }, g_queryAsyncJobResultInterval);
+                                },
+                                error: function(XMLHttpResponse) {
+                                    cloudStack.dialog.notice({
+                                        message: 'Failed to update SSL 
Certificate. ' + parseXMLHttpResponse(XMLHttpResponse)
                                     });
-                                }, g_queryAsyncJobResultInterval);
-                            },
-                            error: function(XMLHttpResponse) {
-                                cloudStack.dialog.notice({
-                                    message: 'Failed to update SSL 
Certificate. ' + parseXMLHttpResponse(XMLHttpResponse)
-                                });
-                                $loading.remove();
-                            }
-                        });
+                                    $loading.remove();
+                                }
+                            });
+                            return;
+                        };
+
+                        // start uploading the certificates
+                        uploadCertificate(0);
                     },
                     context: {}
                 });

Reply via email to