From 9c8a4d2543e215f388e95e30f727a35eb9a7f778 Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" 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" 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 { + + @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" 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" 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 +# +# 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 (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 (default: pki-tomcat).') + print(' --file 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 + "" + + 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