From 6390db3502eaee385cb990eef723bc4f27a633c0 Mon Sep 17 00:00:00 2001
From: Rob Crittenden
Date: Wed, 12 Dec 2007 09:36:32 -0500
Subject: [PATCH] Add automatic browser configuration for kerberos SSO using
javascript. This uses the UniversalPreferencesWrite function to set the
browser preferences to allow negotiation and ticket forwarding in the IPA
domain. A self-signed certificate is generated to sign the javascript.
---
ipa-server/ipa-install/share/Makefile.am | 1 +
.../share/preferences.html.template | 33 +++++++++++
ipa-server/ipaserver/certs.py | 56 +++++++++++++++++--
ipa-server/ipaserver/httpinstance.py | 34 ++++++++++-
ipa-server/xmlrpc-server/ipa.conf | 5 +-
ipa-server/xmlrpc-server/unauthorized.html | 14 +++++
6 files changed, 134 insertions(+), 9 deletions(-)
create mode 100644 ipa-server/ipa-install/share/preferences.html.template
diff --git a/ipa-server/ipa-install/share/Makefile.am b/ipa-server/ipa-install/share/Makefile.am
index 36bb54e83..36837356d 100644
--- a/ipa-server/ipa-install/share/Makefile.am
+++ b/ipa-server/ipa-install/share/Makefile.am
@@ -19,6 +19,7 @@ app_DATA = \
krb.con.template \
krbrealm.con.template \
ntp.conf.server.template \
+ preferences.html.template \
radius.radiusd.conf.template \
referint-conf.ldif \
dna-posix.ldif \
diff --git a/ipa-server/ipa-install/share/preferences.html.template b/ipa-server/ipa-install/share/preferences.html.template
new file mode 100644
index 000000000..2d3684dcd
--- /dev/null
+++ b/ipa-server/ipa-install/share/preferences.html.template
@@ -0,0 +1,33 @@
+
+
+
+ Automatically set browser preferences
+
+
+
+
+
+
+
+
diff --git a/ipa-server/ipaserver/certs.py b/ipa-server/ipaserver/certs.py
index 77052c13e..eecfdf21c 100644
--- a/ipa-server/ipaserver/certs.py
+++ b/ipa-server/ipaserver/certs.py
@@ -77,6 +77,11 @@ class CertDB(object):
new_args = new_args + args
ipautil.run(new_args, stdin)
+ def run_signtool(self, args, stdin=None):
+ new_args = ["/usr/bin/signtool", "-d", self.secdir]
+ new_args = new_args + args
+ ipautil.run(new_args, stdin)
+
def create_noise_file(self):
ipautil.backup_file(self.noise_fname)
f = open(self.noise_fname, "w")
@@ -108,7 +113,7 @@ class CertDB(object):
self.run_certutil(["-S", "-n", self.cacert_name,
"-s", "cn=CAcert",
"-x",
- "-t", "CT,,",
+ "-t", "CT,,C",
"-m", self.next_serial(),
"-v", self.valid_months,
"-z", self.noise_fname,
@@ -130,7 +135,7 @@ class CertDB(object):
def load_cacert(self, cacert_fname):
self.run_certutil(["-A", "-n", self.cacert_name,
- "-t", "CT,CT,",
+ "-t", "CT,,C",
"-a",
"-i", cacert_fname])
@@ -139,7 +144,17 @@ class CertDB(object):
if not cdb:
cdb = self
self.request_cert(name)
- cdb.issue_cert(self.certreq_fname, self.certder_fname)
+ cdb.issue_server_cert(self.certreq_fname, self.certder_fname)
+ self.add_cert(self.certder_fname, nickname)
+ os.unlink(self.certreq_fname)
+ os.unlink(self.certder_fname)
+
+ def create_signing_cert(self, nickname, name, other_certdb=None):
+ cdb = other_certdb
+ if not cdb:
+ cdb = self
+ self.request_cert(name)
+ cdb.issue_signing_cert(self.certreq_fname, self.certder_fname)
self.add_cert(self.certder_fname, nickname)
os.unlink(self.certreq_fname)
os.unlink(self.certder_fname)
@@ -151,7 +166,7 @@ class CertDB(object):
"-z", self.noise_fname,
"-f", self.passwd_fname])
- def issue_cert(self, certreq_fname, cert_fname):
+ def issue_server_cert(self, certreq_fname, cert_fname):
p = subprocess.Popen(["/usr/bin/certutil",
"-d", self.secdir,
"-C", "-c", self.cacert_name,
@@ -179,8 +194,37 @@ class CertDB(object):
# n - not critical
p.stdin.write("2\n9\nn\n1\n9\nn\n")
p.wait()
-
-
+
+ def issue_signing_cert(self, certreq_fname, cert_fname):
+ p = subprocess.Popen(["/usr/bin/certutil",
+ "-d", self.secdir,
+ "-C", "-c", self.cacert_name,
+ "-i", certreq_fname,
+ "-o", cert_fname,
+ "-m", self.next_serial(),
+ "-v", self.valid_months,
+ "-f", self.passwd_fname,
+ "-1", "-5"],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+
+ # Bah - this sucks, but I guess it isn't possible to fully
+ # control this with command line arguments.
+ #
+ # What this is requesting is:
+ # -1 (Create key usage extension)
+ # 0 - Digital Signature
+ # 5 - Cert signing key
+ # 9 - done
+ # n - not critical
+ #
+ # -5 (Create netscape cert type extension)
+ # 3 - Object Signing
+ # 9 - done
+ # n - not critical
+ p.stdin.write("0\n5\n9\nn\n3\n9\nn\n")
+ p.wait()
+
def add_cert(self, cert_fname, nickname):
self.run_certutil(["-A", "-n", nickname,
"-t", "u,u,u",
diff --git a/ipa-server/ipaserver/httpinstance.py b/ipa-server/ipaserver/httpinstance.py
index de0b3af82..a131faedc 100644
--- a/ipa-server/ipaserver/httpinstance.py
+++ b/ipa-server/ipaserver/httpinstance.py
@@ -25,6 +25,7 @@ import pwd
import fileinput
import sys
import time
+import shutil
import service
import certs
@@ -49,9 +50,10 @@ class HTTPInstance(service.Service):
service.Service.__init__(self, "httpd")
def create_instance(self, realm, fqdn):
- self.sub_dict = { "REALM" : realm, "FQDN": fqdn }
self.fqdn = fqdn
self.realm = realm
+ self.domain = fqdn[fqdn.find(".")+1:]
+ self.sub_dict = { "REALM" : realm, "FQDN": fqdn, "DOMAIN" : self.domain }
self.start_creation(7, "Configuring the web interface")
@@ -60,6 +62,7 @@ class HTTPInstance(service.Service):
self.__configure_http()
self.__create_http_keytab()
self.__setup_ssl()
+ self.__setup_autoconfig()
self.step("restarting httpd")
self.restart()
@@ -141,4 +144,31 @@ class HTTPInstance(service.Service):
ds_ca.cur_serial = 2000
ca.create_from_cacert(ds_ca.cacert_fname)
ca.create_server_cert("Server-Cert", "cn=%s,ou=Apache Web Server" % self.fqdn, ds_ca)
-
+ ca.create_signing_cert("Signing-Cert", "cn=%s,ou=Signing Certificate,o=Identity Policy Audit" % self.fqdn, ds_ca)
+
+ def __setup_autoconfig(self):
+ prefs_txt = template_file(SHARE_DIR + "preferences.html.template", self.sub_dict)
+ prefs_fd = open("/usr/share/ipa/html/preferences.html", "w")
+ prefs_fd.write(prefs_txt)
+ prefs_fd.close()
+
+ # The signing cert is generated in __setup_ssl
+ ds_ca = certs.CertDB(dsinstance.config_dirname(self.realm))
+ ca = certs.CertDB(NSS_DIR)
+
+ # Publish the CA certificate
+ shutil.copy(ds_ca.cacert_fname, "/usr/share/ipa/html/ca.crt")
+ os.chmod("/usr/share/ipa/html/ca.crt", 0444)
+
+ try:
+ shutil.rmtree("/tmp/ipa")
+ except:
+ pass
+ os.mkdir("/tmp/ipa")
+ shutil.copy("/usr/share/ipa/html/preferences.html", "/tmp/ipa")
+
+ ca.run_signtool(["-k", "Signing-Cert",
+ "-Z", "/usr/share/ipa/html/configure.jar",
+ "-e", ".html",
+ "/tmp/ipa"])
+ shutil.rmtree("/tmp/ipa")
diff --git a/ipa-server/xmlrpc-server/ipa.conf b/ipa-server/xmlrpc-server/ipa.conf
index fbf26b67c..4e8bf528f 100644
--- a/ipa-server/xmlrpc-server/ipa.conf
+++ b/ipa-server/xmlrpc-server/ipa.conf
@@ -12,9 +12,12 @@ RewriteRule ^/(.*) http://$FQDN/$$1 [L,R=301]
# Redirect to the secure port if not displaying an error or retrieving
# configuration.
RewriteCond %{SERVER_PORT} !^443$$
-RewriteCond %{REQUEST_URI} !^/(errors|config)/
+RewriteCond %{REQUEST_URI} !^/(errors|config|favicon.ico)
RewriteRule ^/(.*) https://$FQDN/$$1 [L,R=301,NC]
+# This is required so the auto-configuration works with Firefox 2+
+AddType application/java-archive jar
+
AuthType Kerberos
AuthName "Kerberos Login"
diff --git a/ipa-server/xmlrpc-server/unauthorized.html b/ipa-server/xmlrpc-server/unauthorized.html
index 23a8d5c7d..e46ca538f 100644
--- a/ipa-server/xmlrpc-server/unauthorized.html
+++ b/ipa-server/xmlrpc-server/unauthorized.html
@@ -9,6 +9,20 @@ have configured your
browser correctly. If you are still unable to access
the IPA Web interface, please contact the helpdesk on for additional assistance.
+
+Import the IPA Certificate Authority.
+
+
+
+