Blob Blame History Raw
From 9c8a4d2543e215f388e95e30f727a35eb9a7f778 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Mon, 5 Jun 2017 21:50:00 +0200
Subject: [PATCH 1/4] Fixed access banner normalization.

The PKIService has been modified to trim whitespaces in access
banner before returning the value to the client. The clients
have been modified to no longer trim the banner.

https://pagure.io/dogtagpki/issue/2671

Change-Id: I51c5e78d11c89c711e369328def27bb352aa49e6
(cherry picked from commit 5e0dcb69a734c9f52cca673a7a5189d31fb15774)
---
 base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java        | 2 +-
 base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java | 2 +-
 base/server/share/webapps/pki/js/pki-banner.js                    | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java b/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
index 51861b5..8f91f32 100644
--- a/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
@@ -571,7 +571,7 @@ public class MainCLI extends CLI {
 
             if (banner != null) {
 
-                System.out.println(banner.trim());
+                System.out.println(banner);
                 System.out.println();
                 System.out.print("Do you want to proceed (y/N)? ");
                 System.out.flush();
diff --git a/base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java b/base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java
index e023aa6..3273477 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java
@@ -98,7 +98,7 @@ public class PKIService {
     }
 
     public static String getBanner() throws IOException {
-        return new String(Files.readAllBytes(bannerFile));
+        return new String(Files.readAllBytes(bannerFile)).trim();
     }
 
     public static MediaType resolveFormat(MediaType format) {
diff --git a/base/server/share/webapps/pki/js/pki-banner.js b/base/server/share/webapps/pki/js/pki-banner.js
index e88220e..ff64092 100644
--- a/base/server/share/webapps/pki/js/pki-banner.js
+++ b/base/server/share/webapps/pki/js/pki-banner.js
@@ -37,7 +37,7 @@ if (location.protocol == "https:" && !sessionStorage.bannerLock) {
             }
 
             // display the banner and ask for confirmation
-            var message = $.trim(data.Banner) + "\n\nDo you want to proceed?";
+            var message = banner + "\n\nDo you want to proceed?";
 
             // if banner accepted
             if (confirm(message)) {
-- 
1.8.3.1


From 00b439b9056baef2b40a16cba2b3e46d1365ce62 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Tue, 13 Jun 2017 21:09:52 +0200
Subject: [PATCH 2/4] Fixed access banner encoding.

The Info service and client have been modified to transmit access
banner in Base64-encoded form. The PKI UI has been modified to
decode the access banner properly.

https://pagure.io/dogtagpki/issue/2671

Change-Id: Ic8526bac4c4d6b99e627aced64ab24cf675f5d50
(cherry picked from commit e5f6ed7be301a3531b871ef3b0ce64bea0fe1973)
---
 .../src/org/dogtagpki/common/Base64Adapter.java    | 34 ++++++++++++++++++++++
 base/common/src/org/dogtagpki/common/Info.java     |  2 ++
 base/server/share/webapps/pki/js/pki-banner.js     |  3 ++
 3 files changed, 39 insertions(+)
 create mode 100644 base/common/src/org/dogtagpki/common/Base64Adapter.java

diff --git a/base/common/src/org/dogtagpki/common/Base64Adapter.java b/base/common/src/org/dogtagpki/common/Base64Adapter.java
new file mode 100644
index 0000000..f777745
--- /dev/null
+++ b/base/common/src/org/dogtagpki/common/Base64Adapter.java
@@ -0,0 +1,34 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// 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 of the License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2017 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.common;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+public class Base64Adapter extends XmlAdapter<byte[], String> {
+
+    @Override
+    public String unmarshal(byte[] bytes) throws Exception {
+        return new String(bytes);
+    }
+
+    @Override
+    public byte[] marshal(String string) throws Exception {
+        return string.getBytes();
+    }
+}
diff --git a/base/common/src/org/dogtagpki/common/Info.java b/base/common/src/org/dogtagpki/common/Info.java
index 0a216f4..7ea3fd7 100644
--- a/base/common/src/org/dogtagpki/common/Info.java
+++ b/base/common/src/org/dogtagpki/common/Info.java
@@ -26,6 +26,7 @@ import javax.xml.bind.Marshaller;
 import javax.xml.bind.Unmarshaller;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -66,6 +67,7 @@ public class Info extends ResourceMessage {
     }
 
     @XmlElement(name="Banner")
+    @XmlJavaTypeAdapter(Base64Adapter.class)
     public String getBanner() {
         return banner;
     }
diff --git a/base/server/share/webapps/pki/js/pki-banner.js b/base/server/share/webapps/pki/js/pki-banner.js
index ff64092..05b5f01 100644
--- a/base/server/share/webapps/pki/js/pki-banner.js
+++ b/base/server/share/webapps/pki/js/pki-banner.js
@@ -36,6 +36,9 @@ if (location.protocol == "https:" && !sessionStorage.bannerLock) {
                 return;
             }
 
+            // decode Base64-encoded UTF-8 banner
+            var banner = decodeURIComponent(escape(atob(data.Banner)));
+
             // display the banner and ask for confirmation
             var message = banner + "\n\nDo you want to proceed?";
 
-- 
1.8.3.1


From b5085492242307d669fb331dead66f331a07c09e Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Wed, 14 Jun 2017 03:40:43 +0200
Subject: [PATCH 3/4] Fixed access banner encoding (part 2).

The code that reads the access banner from file has been modified
to explicitly use UTF-8 encoding.

The Info class and the PKI UI have been modified not to encode the
access banner in Base64 since it is not necessary.

https://pagure.io/dogtagpki/issue/2671

Change-Id: I5f41a8ebac0bc91623b27f14608bca294bc9bc38
(cherry picked from commit 4a8e1703603ab348b24d4f010e3587c340e1a032)
---
 base/common/src/org/dogtagpki/common/Info.java                    | 2 --
 base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java | 2 +-
 base/server/share/webapps/pki/js/pki-banner.js                    | 5 +----
 3 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/base/common/src/org/dogtagpki/common/Info.java b/base/common/src/org/dogtagpki/common/Info.java
index 7ea3fd7..0a216f4 100644
--- a/base/common/src/org/dogtagpki/common/Info.java
+++ b/base/common/src/org/dogtagpki/common/Info.java
@@ -26,7 +26,6 @@ import javax.xml.bind.Marshaller;
 import javax.xml.bind.Unmarshaller;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -67,7 +66,6 @@ public class Info extends ResourceMessage {
     }
 
     @XmlElement(name="Banner")
-    @XmlJavaTypeAdapter(Base64Adapter.class)
     public String getBanner() {
         return banner;
     }
diff --git a/base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java b/base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java
index 3273477..7a4727b 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java
@@ -98,7 +98,7 @@ public class PKIService {
     }
 
     public static String getBanner() throws IOException {
-        return new String(Files.readAllBytes(bannerFile)).trim();
+        return new String(Files.readAllBytes(bannerFile), "UTF-8").trim();
     }
 
     public static MediaType resolveFormat(MediaType format) {
diff --git a/base/server/share/webapps/pki/js/pki-banner.js b/base/server/share/webapps/pki/js/pki-banner.js
index 05b5f01..2bb2792 100644
--- a/base/server/share/webapps/pki/js/pki-banner.js
+++ b/base/server/share/webapps/pki/js/pki-banner.js
@@ -36,11 +36,8 @@ if (location.protocol == "https:" && !sessionStorage.bannerLock) {
                 return;
             }
 
-            // decode Base64-encoded UTF-8 banner
-            var banner = decodeURIComponent(escape(atob(data.Banner)));
-
             // display the banner and ask for confirmation
-            var message = banner + "\n\nDo you want to proceed?";
+            var message = data.Banner + "\n\nDo you want to proceed?";
 
             // if banner accepted
             if (confirm(message)) {
-- 
1.8.3.1


From 6449371ab6cb95a10ce0ad37d4a303709e356973 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Wed, 14 Jun 2017 23:08:29 +0200
Subject: [PATCH 4/4] Added banner validation during server startup.

Some pki-server CLIs have been added to inspect and validate the
content of the banner file.

The PKI server startup script has been modified to validate the
content of the banner file using the new CLI.

https://pagure.io/dogtagpki/issue/2671

Change-Id: Ibc51afee184d0a720cc0d2961af08ef75d2b54c4
(cherry picked from commit d2e247798a36225880ef6050716cc7576fe2ad7f)
---
 base/server/python/pki/server/__init__.py   |   8 ++
 base/server/python/pki/server/cli/banner.py | 186 ++++++++++++++++++++++++++++
 base/server/sbin/pki-server                 |   2 +
 base/server/scripts/operations              |   6 +
 4 files changed, 202 insertions(+)
 create mode 100644 base/server/python/pki/server/cli/banner.py

diff --git a/base/server/python/pki/server/__init__.py b/base/server/python/pki/server/__init__.py
index 46c6711..0852b12 100644
--- a/base/server/python/pki/server/__init__.py
+++ b/base/server/python/pki/server/__init__.py
@@ -19,6 +19,7 @@
 #
 
 from __future__ import absolute_import
+import codecs
 from lxml import etree
 import functools
 import getpass
@@ -501,6 +502,7 @@ class PKIInstance(object):
         self.conf_dir = os.path.join(CONFIG_BASE_DIR, name)
         self.log_dir = os.path.join(LOG_BASE_DIR, name)
 
+        self.banner_file = os.path.join(self.conf_dir, 'banner.txt')
         self.password_conf = os.path.join(self.conf_dir, 'password.conf')
         self.external_certs_conf = os.path.join(
             self.conf_dir, 'external_certs.conf')
@@ -792,6 +794,12 @@ class PKIInstance(object):
             self.conf_dir, 'Catalina', 'localhost', webapp_name + '.xml')
         os.remove(context_xml)
 
+    def banner_installed(self):
+        return os.path.exists(self.banner_file)
+
+    def get_banner(self):
+        return codecs.open(self.banner_file, "UTF-8").read().strip()
+
     def __repr__(self):
         if self.type == 9:
             return "Dogtag 9 " + self.name
diff --git a/base/server/python/pki/server/cli/banner.py b/base/server/python/pki/server/cli/banner.py
new file mode 100644
index 0000000..98f8f16
--- /dev/null
+++ b/base/server/python/pki/server/cli/banner.py
@@ -0,0 +1,186 @@
+# Authors:
+#     Endi S. Dewata <edewata@redhat.com>
+#
+# 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 of the License.
+#
+# 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2017 Red Hat, Inc.
+# All rights reserved.
+#
+
+from __future__ import absolute_import
+from __future__ import print_function
+import codecs
+import getopt
+from lxml import etree
+import sys
+import traceback
+
+import pki.cli
+
+
+class BannerCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(BannerCLI, self).__init__('banner',
+                                        'Banner management commands')
+
+        self.add_module(BannerShowCLI())
+        self.add_module(BannerValidateCLI())
+
+
+class BannerShowCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(BannerShowCLI, self).__init__('show', 'Show banner')
+
+    def usage(self):
+        print('Usage: pki-server banner-show [OPTIONS]')
+        print()
+        print('  -i, --instance <instance ID>    Instance ID (default: pki-tomcat).')
+        print('  -v, --verbose                   Run in verbose mode.')
+        print('      --help                      Show help message.')
+        print()
+
+    def execute(self, argv):
+
+        try:
+            opts, _ = getopt.gnu_getopt(argv, 'i:v', [
+                'instance=',
+                'verbose', 'help'])
+
+        except getopt.GetoptError as e:
+            print('ERROR: ' + str(e))
+            self.usage()
+            sys.exit(1)
+
+        instance_name = 'pki-tomcat'
+
+        for o, a in opts:
+            if o in ('-i', '--instance'):
+                instance_name = a
+
+            elif o in ('-v', '--verbose'):
+                self.set_verbose(True)
+
+            elif o == '--help':
+                self.usage()
+                sys.exit()
+
+            else:
+                print('ERROR: unknown option ' + o)
+                self.usage()
+                sys.exit(1)
+
+        instance = pki.server.PKIInstance(instance_name)
+
+        if not instance.is_valid():
+            print('ERROR: Invalid instance %s.' % instance_name)
+            sys.exit(1)
+
+        instance.load()
+
+        if not instance.banner_installed():
+            print('ERROR: Banner is not installed')
+            sys.exit(1)
+
+        print(instance.get_banner())
+
+
+class BannerValidateCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(BannerValidateCLI, self).__init__('validate', 'Validate banner')
+
+    def usage(self):
+        print('Usage: pki-server banner-validate [OPTIONS]')
+        print()
+        print('  -i, --instance <instance ID>    Instance ID (default: pki-tomcat).')
+        print('      --file <path>               Validate specified banner file.')
+        print('  -v, --verbose                   Run in verbose mode.')
+        print('      --help                      Show help message.')
+        print()
+
+    def execute(self, argv):
+
+        try:
+            opts, _ = getopt.gnu_getopt(argv, 'i:v', [
+                'instance=', 'file=',
+                'verbose', 'help'])
+
+        except getopt.GetoptError as e:
+            print('ERROR: ' + str(e))
+            self.usage()
+            sys.exit(1)
+
+        instance_name = 'pki-tomcat'
+        banner_file = None
+
+        for o, a in opts:
+            if o in ('-i', '--instance'):
+                instance_name = a
+
+            elif o == '--file':
+                banner_file = a
+
+            elif o in ('-v', '--verbose'):
+                self.set_verbose(True)
+
+            elif o == '--help':
+                self.usage()
+                sys.exit()
+
+            else:
+                print('ERROR: unknown option ' + o)
+                self.usage()
+                sys.exit(1)
+
+        if banner_file:
+
+            # load banner from file
+            banner = codecs.open(banner_file, "UTF-8").read().strip()
+
+        else:
+
+            # load banner from instance
+            instance = pki.server.PKIInstance(instance_name)
+
+            if not instance.is_valid():
+                print('ERROR: Invalid instance %s.' % instance_name)
+                sys.exit(1)
+
+            instance.load()
+
+            if not instance.banner_installed():
+                self.print_message('Banner is not installed')
+                return
+
+            banner = instance.get_banner()
+
+        if not banner:
+            print('ERROR: Banner is empty')
+            sys.exit(1)
+
+        xml_banner = "<banner>" + banner + "</banner>"
+
+        try:
+            parser = etree.XMLParser()
+            etree.fromstring(xml_banner, parser)
+
+            self.print_message('Banner is valid')
+
+        except etree.XMLSyntaxError as e:
+            if self.verbose:
+                traceback.print_exc()
+            print('ERROR: Banner contains invalid character(s)')
+            sys.exit(1)
diff --git a/base/server/sbin/pki-server b/base/server/sbin/pki-server
index 6df70dc..ce06e28 100644
--- a/base/server/sbin/pki-server
+++ b/base/server/sbin/pki-server
@@ -32,6 +32,7 @@ import pki.server.cli.kra
 import pki.server.cli.ocsp
 import pki.server.cli.tks
 import pki.server.cli.tps
+import pki.server.cli.banner
 import pki.server.cli.db
 import pki.server.cli.instance
 import pki.server.cli.subsystem
@@ -52,6 +53,7 @@ class PKIServerCLI(pki.cli.CLI):
         self.add_module(pki.server.cli.tks.TKSCLI())
         self.add_module(pki.server.cli.tps.TPSCLI())
 
+        self.add_module(pki.server.cli.banner.BannerCLI())
         self.add_module(pki.server.cli.db.DBCLI())
         self.add_module(pki.server.cli.instance.InstanceCLI())
         self.add_module(pki.server.cli.subsystem.SubsystemCLI())
diff --git a/base/server/scripts/operations b/base/server/scripts/operations
index 907dd0e..908c952 100644
--- a/base/server/scripts/operations
+++ b/base/server/scripts/operations
@@ -1297,6 +1297,12 @@ EOF
         /var/lib/pki/$PKI_INSTANCE_NAME/conf/custom.policy > \
         /var/lib/pki/$PKI_INSTANCE_NAME/conf/catalina.policy
 
+    pki-server banner-validate -i "$PKI_INSTANCE_NAME"
+    rv=$?
+    if [ $rv -ne 0 ]; then
+        return $rv
+    fi
+
     if [ "${PKI_SERVER_AUTO_ENABLE_SUBSYSTEMS}" = "true" ] ; then
         # enable all subsystems
         pki-server subsystem-enable -i "$PKI_INSTANCE_NAME" --all
-- 
1.8.3.1