>From 69aaed340190d08cdba81037867a76d72f37c4aa Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Wed, 15 Feb 2017 17:51:28 +0100
Subject: [PATCH] Added InfoService.

A new InfoService class has been added to PKIApplication to
provide public information about the server including version
number and access banner.

https://fedorahosted.org/pki/ticket/2582
---
 base/common/src/CMakeLists.txt                     |   3 +-
 base/common/src/org/dogtagpki/rest/Info.java       | 138 +++++++++++++++++++++
 .../src/org/dogtagpki/rest/InfoResource.java}      |  40 ++----
 base/server/cms/src/CMakeLists.txt                 |   1 +
 .../com/netscape/cms/servlet/base/PKIService.java  |  22 +++-
 .../rest/{PKIApplication.java => InfoService.java} |  40 +++---
 .../org/dogtagpki/server/rest/PKIApplication.java  |   1 +
 7 files changed, 196 insertions(+), 49 deletions(-)
 create mode 100644 base/common/src/org/dogtagpki/rest/Info.java
 copy base/{server/cms/src/org/dogtagpki/server/rest/PKIApplication.java => common/src/org/dogtagpki/rest/InfoResource.java} (54%)
 copy base/server/cms/src/org/dogtagpki/server/rest/{PKIApplication.java => InfoService.java} (52%)

diff --git a/base/common/src/CMakeLists.txt b/base/common/src/CMakeLists.txt
index 2c0672c3cda79d8d1275aa6e533799e15275fee2..c08d1b75d50a1debd395b0428890e3de4edc83ad 100644
--- a/base/common/src/CMakeLists.txt
+++ b/base/common/src/CMakeLists.txt
@@ -101,13 +101,14 @@ javac(pki-certsrv-classes
     SOURCES
         *.java
     CLASSPATH
-        ${PKI_NSUTIL_JAR} ${PKI_CMSUTIL_JAR}
+        ${SLF4J_API_JAR}
         ${LDAPJDK_JAR} ${SERVLET_JAR} ${VELOCITY_JAR} ${XALAN_JAR} ${XERCES_JAR}
         ${JSS_JAR} ${COMMONS_CODEC_JAR} ${COMMONS_HTTPCLIENT_JAR}
         ${APACHE_COMMONS_LANG_JAR}
         ${TOMCAT_CATALINA_JAR} ${TOMCAT_UTIL_JAR} ${SYMKEY_JAR}
         ${JAXRS_API_JAR} ${RESTEASY_JAXRS_JAR} ${RESTEASY_ATOM_PROVIDER_JAR} ${RESTEASY_CLIENT_JAR}
         ${HTTPCLIENT_JAR} ${HTTPCORE_JAR}
+        ${PKI_NSUTIL_JAR} ${PKI_CMSUTIL_JAR}
     OUTPUT_DIR
         ${CMAKE_CURRENT_BINARY_DIR}/classes
     DEPENDS
diff --git a/base/common/src/org/dogtagpki/rest/Info.java b/base/common/src/org/dogtagpki/rest/Info.java
new file mode 100644
index 0000000000000000000000000000000000000000..fe8dd55a92b7d8b7f7f12c5d2fcb50e4a0b5eb9a
--- /dev/null
+++ b/base/common/src/org/dogtagpki/rest/Info.java
@@ -0,0 +1,138 @@
+// --- 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.rest;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.netscape.certsrv.base.ResourceMessage;
+
+/**
+ * @author Endi S. Dewata
+ */
+@XmlRootElement(name="Info")
+public class Info extends ResourceMessage {
+
+    private static Logger logger = LoggerFactory.getLogger(Info.class);
+
+    public static Marshaller marshaller;
+    public static Unmarshaller unmarshaller;
+
+    static {
+        try {
+            marshaller = JAXBContext.newInstance(Info.class).createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            unmarshaller = JAXBContext.newInstance(Info.class).createUnmarshaller();
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+        }
+    }
+
+    String version;
+    String banner;
+
+    @XmlElement(name="Version")
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    @XmlElement(name="Banner")
+    public String getBanner() {
+        return banner;
+    }
+
+    public void setBanner(String banner) {
+        this.banner = banner;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((banner == null) ? 0 : banner.hashCode());
+        result = prime * result + ((version == null) ? 0 : version.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Info other = (Info) obj;
+        if (banner == null) {
+            if (other.banner != null)
+                return false;
+        } else if (!banner.equals(other.banner))
+            return false;
+        if (version == null) {
+            if (other.version != null)
+                return false;
+        } else if (!version.equals(other.version))
+            return false;
+        return true;
+    }
+
+    public String toString() {
+        try {
+            StringWriter sw = new StringWriter();
+            marshaller.marshal(this, sw);
+            return sw.toString();
+
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static Info valueOf(String string) throws Exception {
+        return (Info)unmarshaller.unmarshal(new StringReader(string));
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        Info before = new Info();
+        before.setVersion("10.4.0");
+        before.setBanner(
+                "WARNING!\n" +
+                "Access to this service is restricted to those individuals with " +
+                "specific permissions.");
+
+        String string = before.toString();
+        System.out.println(string);
+
+        Info after = Info.valueOf(string);
+        System.out.println(before.equals(after));
+    }
+}
diff --git a/base/server/cms/src/org/dogtagpki/server/rest/PKIApplication.java b/base/common/src/org/dogtagpki/rest/InfoResource.java
similarity index 54%
copy from base/server/cms/src/org/dogtagpki/server/rest/PKIApplication.java
copy to base/common/src/org/dogtagpki/rest/InfoResource.java
index d6ac7939c979d6d491f35094b689746558af1363..d4a1cae3836a9a5596a758c2a44bf8615a23cbfc 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/PKIApplication.java
+++ b/base/common/src/org/dogtagpki/rest/InfoResource.java
@@ -16,35 +16,21 @@
 // All rights reserved.
 // --- END COPYRIGHT BLOCK ---
 
-package org.dogtagpki.server.rest;
+package org.dogtagpki.rest;
 
-import java.util.LinkedHashSet;
-import java.util.Set;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
 
-import javax.ws.rs.core.Application;
+import org.jboss.resteasy.annotations.ClientResponseType;
 
-public class PKIApplication extends Application {
-
-    private Set<Object> singletons = new LinkedHashSet<Object>();
-    private Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
-
-    public PKIApplication() {
-
-        // services
-
-        // exception mappers
-        classes.add(PKIExceptionMapper.class);
-
-        // interceptors
-        singletons.add(new MessageFormatInterceptor());
-    }
-
-    public Set<Class<?>> getClasses() {
-        return classes;
-    }
-
-    public Set<Object> getSingletons() {
-        return singletons;
-    }
+/**
+ * @author Endi S. Dewata
+ */
+@Path("info")
+public interface InfoResource {
 
+    @GET
+    @ClientResponseType(entityType=Info.class)
+    public Response getInfo() throws Exception;
 }
diff --git a/base/server/cms/src/CMakeLists.txt b/base/server/cms/src/CMakeLists.txt
index 7c56595539849946d46897479c2c02be3183a089..2ca0285a4335cd3bb3f5b7e625cd0d708bc41e88 100644
--- a/base/server/cms/src/CMakeLists.txt
+++ b/base/server/cms/src/CMakeLists.txt
@@ -101,6 +101,7 @@ javac(pki-cms-classes
     SOURCES
         *.java
     CLASSPATH
+        ${SLF4J_API_JAR}
         ${COMMONS_CODEC_JAR} ${COMMONS_IO_JAR} ${COMMONS_LANG_JAR} ${COMMONS_HTTPCLIENT_JAR}
         ${HTTPCLIENT_JAR} ${HTTPCORE_JAR}
         ${XALAN_JAR} ${XERCES_JAR}
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 3ed4b91b7b42e077e2581e2bb362422c6107ff4a..8dfbef1e511edd508880021e1245c2bff256e20c 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
@@ -17,8 +17,12 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.cms.servlet.base;
 
+import java.io.IOException;
 import java.lang.reflect.Method;
 import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -78,8 +82,22 @@ public class PKIService {
     @Context
     protected ServletContext servletContext;
 
-    public String getInstanceDir() {
-        return System.getProperty("catalina.base");
+    public static Path bannerFile = Paths.get(getInstanceDir(), "conf", "banner.txt");
+
+    public static String getInstanceDir() {
+        return System.getProperty("catalina.base");  // provided by Tomcat
+    }
+
+    public static String getVersion() {
+        return System.getenv("PKI_VERSION");  // defined in tomcat.conf
+    }
+
+    public static boolean isBannerEnabled() {
+        return Files.exists(bannerFile);
+    }
+
+    public static String getBanner() throws IOException {
+        return new String(Files.readAllBytes(bannerFile));
     }
 
     public static MediaType resolveFormat(MediaType format) {
diff --git a/base/server/cms/src/org/dogtagpki/server/rest/PKIApplication.java b/base/server/cms/src/org/dogtagpki/server/rest/InfoService.java
similarity index 52%
copy from base/server/cms/src/org/dogtagpki/server/rest/PKIApplication.java
copy to base/server/cms/src/org/dogtagpki/server/rest/InfoService.java
index d6ac7939c979d6d491f35094b689746558af1363..7038cecbaaee529dc8bed3c5023c235c0b2d97d9 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/PKIApplication.java
+++ b/base/server/cms/src/org/dogtagpki/server/rest/InfoService.java
@@ -18,33 +18,35 @@
 
 package org.dogtagpki.server.rest;
 
-import java.util.LinkedHashSet;
-import java.util.Set;
+import javax.ws.rs.core.Response;
 
-import javax.ws.rs.core.Application;
+import org.dogtagpki.rest.Info;
+import org.dogtagpki.rest.InfoResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-public class PKIApplication extends Application {
+import com.netscape.cms.servlet.base.PKIService;
 
-    private Set<Object> singletons = new LinkedHashSet<Object>();
-    private Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
+/**
+ * @author Endi S. Dewata
+ */
+public class InfoService extends PKIService implements InfoResource {
 
-    public PKIApplication() {
+    private static Logger logger = LoggerFactory.getLogger(InfoService.class);
 
-        // services
+    @Override
+    public Response getInfo() throws Exception {
 
-        // exception mappers
-        classes.add(PKIExceptionMapper.class);
+        Info info = new Info();
+        info.setVersion(getVersion());
 
-        // interceptors
-        singletons.add(new MessageFormatInterceptor());
-    }
+        boolean bannerEnabled = isBannerEnabled();
 
-    public Set<Class<?>> getClasses() {
-        return classes;
-    }
+        if (bannerEnabled) {
+            String banner = getBanner();
+            info.setBanner(banner);
+        }
 
-    public Set<Object> getSingletons() {
-        return singletons;
+        return createOKResponse(info);
     }
-
 }
diff --git a/base/server/cms/src/org/dogtagpki/server/rest/PKIApplication.java b/base/server/cms/src/org/dogtagpki/server/rest/PKIApplication.java
index d6ac7939c979d6d491f35094b689746558af1363..9e2a3c4205fe932dd3857c7d71e0161331946c99 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/PKIApplication.java
+++ b/base/server/cms/src/org/dogtagpki/server/rest/PKIApplication.java
@@ -31,6 +31,7 @@ public class PKIApplication extends Application {
     public PKIApplication() {
 
         // services
+        classes.add(InfoService.class);
 
         // exception mappers
         classes.add(PKIExceptionMapper.class);
-- 
2.9.3

