Skip to content

Commit

Permalink
initial certificate import dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
lslezak committed Apr 30, 2014
1 parent 015bdee commit d05544f
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 75 deletions.
9 changes: 7 additions & 2 deletions src/Makefile.am
Expand Up @@ -17,7 +17,10 @@ ylib_DATA = \
lib/registration/storage.rb \
lib/registration/registration.rb \
lib/registration/helpers.rb \
lib/registration/connect_helpers.rb \
lib/registration/connect_helpers.rb

ylibuidir = @ylibdir@/registration/ui
ylibui_DATA = \
lib/registration/ui/import_certificate_dialog.rb

ylibyastdir = @ylibdir@/yast
Expand All @@ -30,8 +33,10 @@ schemafiles_DATA = \

ydatadir = @ydatadir@/registration
ydata_DATA = \
data/registration/certificate_summary.erb \
data/registration/summary.erb

EXTRA_DIST = $(client_DATA) $(desktop_DATA) $(ylib_DATA) $(ylibyast_DATA) $(schemafiles_DATA) $(ydata_DATA)
EXTRA_DIST = $(client_DATA) $(desktop_DATA) $(ylib_DATA) $(ylibui_DATA) \
$(ylibyast_DATA) $(schemafiles_DATA) $(ydata_DATA)

include $(top_srcdir)/Makefile.am.common
72 changes: 72 additions & 0 deletions src/data/registration/certificate_summary.erb
@@ -0,0 +1,72 @@
<%
=begin the textdomain for y2makepot
textdomain "registration"
=end
%>
<% # dialog heading
%>
<h2><%= _("Secure Connection Error") %></h2>

<p>
<%= _("Error: %s") % h(Storage::SSLErrors.instance.ssl_error_msg) %>
</p>

<h3><%= _("Certificate Details") %></h3>

<h4><%= _("Issued To") %></h4>
<blockquote>
<p>
<% # %s is SSL certificate issuer identification
%>
<%= _("<b>Common Name (CN):</b> %s") % h(find_name_attribute(@subject, "CN")) %><br>
<% # %s is SSL certificate issuer identification
%>
<%= _("<b>Organization (O):</b> %s") % h(find_name_attribute(@subject, "O")) %><br>
<% # %s is SSL certificate issuer identification
%>
<%= _("<b>Organization Unit (OU):</b> %s") % h(find_name_attribute(@subject, "OU")) %>
</p>
</blockquote>

<h4><%= _("Issued By") %></h4>
<blockquote>
<p>
<% # %s is SSL certificate issuer identification
%>
<%= _("<b>Common Name (CN):</b> %s") % h(find_name_attribute(@issuer, "CN")) %><br>
<% # %s is SSL certificate issuer identification
%>
<%= _("<b>Organization (O):</b> %s") % h(find_name_attribute(@issuer, "O")) %><br>
<% # %s is SSL certificate issuer identification
%>
<%= _("<b>Organization Unit (OU):</b> %s") % h(find_name_attribute(@issuer, "OU")) %>
</p>
</blockquote>

<h4><%= _("Validity") %></h4>
<blockquote>
<p>
<% # %s is date
%>
<%= _("<b>Issued On:</b> %s") % h(@certificate.not_before.localtime.strftime("%F")) %><br>
<% # %s is date
%>
<%= _("<b>Expires On:</b> %s") % h(@certificate.not_after.localtime.strftime("%F")) %><br>
<% if true || Time.now > @certificate.not_after %>
<% # warning added after the certificate expiration date
# if the certificate has expired
%>
<b><font color="red"><%= _("WARNING: The certificate has expired!") %></font></b>
<% end %>
</p>
</p>
</blockquote>

<p>
<%= _("<b>Serial Number:</b> %s") % @certificate.serial.to_s(16).scan(/../).join(":") %><br>

<% # %s is SHA1 sum in HEX format, e.g. AB:CD:00:42:FF...
%>
<%= _("<b>SHA1 Fingerprint:</b> %s") % OpenSSL::Digest::SHA1.new(@certificate.to_der).to_s.upcase.scan(/../).join(':') %>
</p>
13 changes: 10 additions & 3 deletions src/lib/registration/connect_helpers.rb
Expand Up @@ -27,6 +27,7 @@
require "registration/helpers"
require "registration/exceptions"
require "registration/storage"
require "registration/ui/import_certificate_dialog"

module Registration

Expand Down Expand Up @@ -99,7 +100,14 @@ def self.catch_registration_errors(&block)
# in normal operation ask the user to import the certificate
# and retry after successful import
cert = Storage::SSLErrors.instance.ssl_failed_cert
retry if import_ssl_certificate(cert)

if cert
retry if import_ssl_certificate(cert)
else
Yast::Report.Error(
error_with_details(_("OpenSSL connection error."), ssl_error_details)
)
end
end

false
Expand Down Expand Up @@ -146,9 +154,8 @@ def self.ssl_error_details()
end

def self.import_ssl_certificate(cert)
# TODO use ui/import_certificate

if ret == :import
if UI::ImportCertificateDialog.run(cert) == :import
# TODO use Popup.Feedback
result = ::SUSE::Connect::SSLCertificate.import(cert)
log.info "Certificate import result: #{result}"
Expand Down
1 change: 1 addition & 0 deletions src/lib/registration/helpers.rb
Expand Up @@ -157,6 +157,7 @@ def self.reg_url_at_upgrade

# get registration URL in running system
def self.reg_url_at_runnig_system
return "https://projects.nue.suse.com/"
# TODO FIXME: read the URL from configuration file to use the same URL
# at re-registration as in installation

Expand Down
141 changes: 71 additions & 70 deletions src/lib/registration/ui/import_certificate_dialog.rb
@@ -1,123 +1,124 @@

require "erb"
require "yast"

module Registration
module UI

class ImportCertificateDialog
include Yast::Logger
include Yast::I18n
include Yast::UIShortcuts
include ERB::Util

attr_accessor :certificate

Yast.import "UI"
Yast.import "SignatureCheckDialogs"
Yast.import "Label"

def self.run(cert)
dialog = ImportCertificateDialog.new
dialog.run(cert)
dialog = ImportCertificateDialog.new(cert)
dialog.run
end

def initialize()
# @param cert []
def initialize(cert)
textdomain "registration"
@certificate = cert
end

def run(cert)

# popup message - label, part 1, %1 stands for repository name, %2 for its URL
dialog_text = Builtins.sformat(
_(
"The following GnuPG key has been found in repository\n" +
"%1\n" +
"(%2):"
),
Ops.get_locale(repo, "name", _("Unknown")),
Ops.get_locale(repo, "url", _("Unknown"))
)

# popup message - label, part 2
dialog_text2 = _(
"You can choose to import it into your keyring of trusted\n" +
"public keys, meaning that you trust the owner of the key.\n" +
"You should be sure that you can trust the owner and that\n" +
"the key really belongs to that owner before importing it."
)

if Time.now > cert.not_after
dialog_text2 << "\n\n" << _("WARNING: The key has expired!")
end


UI.OpenDialog(Opt(:decorated), import_dialog_content(cert))
def run
log.info "Dialog: #{import_dialog_content}"
Yast::UI.OpenDialog(Opt(:decorated), import_dialog_content)

begin
UI.SetFocus(:cancel)
return UI.UserInput == :import
Yast::UI.SetFocus(:cancel)
return Yast::UI.UserInput
ensure
UI.CloseDialog
Yast::UI.CloseDialog
end
end

private

def certificate_description(cert)

end

def import_dialog_content(cert)
displayinfo = UI.GetDisplayInfo
def import_dialog_content
displayinfo = Yast::UI.GetDisplayInfo
# hide additional help text in narrow terminals
hide_help = displayinfo["TextMode"] && displayinfo["Width"] < 105

window_height = displayinfo["Height"]
window_height = 25 if window_height > 25

HBox(
VSpacing(window_height),
# left-side help
hide_help ?
Empty() :
HWeight(3, VBox(RichText(warning_text))),
HSpacing(1.5),
# dialog
HWeight(2, VBox(RichText(Opt(:disabled), warning_text))),
HSpacing(1),
HWeight(
5,
VBox(
HBox(
VCenter(Yast::SignatureCheckDialogs.MessageIcon("question")),
# popup heading
VCenter(Heading(_("Import Untrusted SSL Certificate"))),
HStretch()
),
# dialog message
MarginBox(
0.4,
0.4,
VBox(
Left(Label(dialog_text)),
certificate_description(cert),
Left(Label(dialog_text2))
)
),
HSpacing(75),
MarginBox(0.4, 0.4, RichText(certificate_description)),
# dialog buttons
ButtonBox(
# push button
PushButton(Id(:import), Opt(:key_F10, :okButton), _("&Import")),
PushButton(Id(:import), Opt(:key_F10, :okButton), _("&Trust and Import")),
PushButton(
Id(:cancel),
Opt(:key_F9, :cancelButton),
Label.CancelButton
Yast::Label.CancelButton
)
)
)
)
)
end

def self.warning_text
# additional Richtext (HTML) warning text (kind of help), 1/2
_(
"<p>The owner of the key may distribute updates,\n" +
"packages, and package repositories that your system will trust and offer\n" +
"for installation and update without any further warning. In this way,\n" +
"importing the key into your keyring of trusted keys allows the key owner\n" +
"to have a certain amount of control over the software on your system.</p>"
)
def certificate_description
# use erb template for rendering the richtext summary
erb_file = File.expand_path("../../../../data/registration/certificate_summary.erb", __FILE__)

log.info "Loading ERB template #{erb_file}"
erb = ERB.new(File.read(erb_file))

@issuer = @certificate.issuer
@subject = @certificate.subject
# render the ERB template in the context of the current object
erb.result(binding)
end

def warning_text
# additional Richtext (HTML) warning text (kind of help) (1/2)
_("<p>Secure connection (HTTPS) uses SSL certificates to verify the authenticity " \
"of the server and for encrypting the transferred data.</p>") +

# additional Richtext (HTML) warning text (kind of help) (2/2)
_("<p>You can choose to import the certificate it into the list of known " \
"certificate autohorities (CA), meaning that you trust the subject " \
"and the issuer of the certificate.</p>") +

# additional Richtext (HTML) warning text (kind of help) (2/2)
_("<p>Importing the certificate into the list of trusted certificates " \
"allows the registration client to verify the authenticity of " \
"the server if the server certificate was not issued by a well " \
"known certification autority (known by the system).</p>") +

# additional Richtext (HTML) warning text (kind of help) (2/2)
_("<p><b>Important:</b> You should verify SHA1 fingerprint of the certificate " \
"to be sure you import the right certificate. Importing an unknown " \
"certificate without verification is a security risk.</p>")
end

# @param x509_name [OpenSSL::X509::Name] name object
# @param attribute [String] requested attribute name. e.g. "CN"
def find_name_attribute(x509_name, attribute)
# attribute list, example:
# [["CN", "linux", 19], ["emailAddress", "root@...", 22], ["O", "YaST", 19], ...]
attr_list = x509_name.to_a.find { |a| a.first == attribute}
attr_list ? attr_list[1] : nil
end

end
end
Expand Down

0 comments on commit d05544f

Please sign in to comment.