From 7447fb22a75ba655c51eefdc509c89f7d7c6937f Mon Sep 17 00:00:00 2001
From: John Gasper <jtgasper3@gmail.com>
Date: Mon, 12 Mar 2018 17:01:15 -0700
Subject: [PATCH 1/4] initial start of moving logging to Docker logs

---
 Dockerfile                                    |  19 ++-
 container_files/api/log4j.properties          | 144 ++++++++++++++++++
 container_files/shibboleth/shibd.logger       |  61 ++++++++
 .../tier-support/supervisord-tomcat.conf      |   2 +-
 container_files/tomcat/conf/server.xml        |   2 +
 container_files/ui/classes/log4j.properties   | 144 ++++++++++++++++++
 container_files/ws/classes/log4j.properties   | 144 ++++++++++++++++++
 7 files changed, 505 insertions(+), 11 deletions(-)
 create mode 100644 container_files/api/log4j.properties
 create mode 100644 container_files/shibboleth/shibd.logger
 create mode 100644 container_files/ui/classes/log4j.properties
 create mode 100644 container_files/ws/classes/log4j.properties

diff --git a/Dockerfile b/Dockerfile
index c40748e..f0173d8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -58,20 +58,16 @@ RUN cd /opt/grouper/grouper.apiBinary/; \
     rm -fr ddlScripts/ grouper.lck grouper.log grouper.script grouper.tmp/ gshAddGrouperSystemWsGroup.gsh logs/
 
 RUN cd /opt/tomcat/; \
-    rm -fr webapps/docs/ webapps/examples/ webapps/host-manager/ webapps/manager/ logs/* temp/* work/* \
-    && mkdir -p logs/grouperUi logs/grouperWs
+    rm -fr webapps/docs/ webapps/examples/ webapps/host-manager/ webapps/manager/ logs/* temp/* work/*
 
 RUN cd /opt/tomee/; \
     rm -fr webapps/docs/ webapps/host-manager/ webapps/manager/ logs/* temp/* work/*
 
-RUN sed -i "s/\/opt\/grouper\/$GROUPER_VERSION\/apache-tomcat-$TOMCAT_VERSION/\/opt\/tomcat/g" /opt/grouper/grouper.ui/WEB-INF/classes/log4j.properties \
-    && sed -i "s/\/opt\/grouper\/$GROUPER_VERSION\/apache-tomcat-$TOMCAT_VERSION/\/opt\/tomcat/g" /opt/grouper/grouper.ws/WEB-INF/classes/log4j.properties \
-    && sed -i 's/${grouper.home}/\/opt\/tomee\//g' /opt/grouper/grouper.scim/WEB-INF/classes/log4j.properties
-
+COPY container_files/api/* /opt/grouper/grouper.apiBinary/conf/
+COPY container_files/ui/ /opt/grouper/grouper.ui/WEB-INF/
+COPY container_files/ws/ /opt/grouper/grouper.ws/WEB-INF/
 COPY container_files/tomcat/ /opt/tomcat/
 COPY container_files/tomee/ /opt/tomee/
-COPY container_files/ui/* /opt/grouper/grouper.ui/WEB-INF/
-
 
 
 FROM tier/shibboleth_sp
@@ -106,12 +102,15 @@ RUN groupadd -r tomcat \
     && chown -R tomcat:tomcat /opt/tomee/logs/ /opt/tomee/temp/ /opt/tomee/work/
 
 COPY container_files/tier-support/ /opt/tier-support/
-COPY container_files/usr-local-bin /usr/local/bin/
+COPY container_files/usr-local-bin/ /usr/local/bin/
 COPY container_files/httpd/* /etc/httpd/conf.d/
 COPY container_files/shibboleth/* /etc/shibboleth/
 
 RUN cp /dev/null /etc/httpd/conf.d/ssl.conf \
-    && touch /etc/pki/tls/certs/cachain.pem
+    && sed -i 's/LogFormat "/LogFormat "httpd-access /g' /etc/httpd/conf/httpd.conf \
+    && echo -e "\nErrorLogFormat \"httpd-error [%{u}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i\"" >> /etc/httpd/conf/httpd.conf \
+    && sed -i 's/CustomLog "logs\/access_log"/CustomLog "\/proc\/self\/fd\/1"/g' /etc/httpd/conf/httpd.conf \
+    && sed -i 's/ErrorLog "logs\/error_log"/ErrorLog "\/proc\/self\/fd\/1"/g' /etc/httpd/conf/httpd.conf
 
 WORKDIR /opt/grouper/grouper.apiBinary/
 
diff --git a/container_files/api/log4j.properties b/container_files/api/log4j.properties
new file mode 100644
index 0000000..22ec105
--- /dev/null
+++ b/container_files/api/log4j.properties
@@ -0,0 +1,144 @@
+
+#
+# Copyright 2014 Internet2
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#${grouper.home} will be substituted with the System property "grouper.home", which must have a trailing \ or / 
+# depending on your OS. Of course you can use absolute paths if you prefer 
+
+
+#
+# log4j Configuration
+# $Id: log4j.example.properties,v 1.13 2009-12-18 13:56:51 tzeller Exp $
+#
+
+# Appenders
+
+## Grouper API event logging
+log4j.appender.grouper_event                            = org.apache.log4j.FileAppender
+log4j.appender.grouper_event.file                       = /dev/fd/1
+log4j.appender.grouper_event.append                     = true
+log4j.appender.grouper_event.layout                     = org.apache.log4j.PatternLayout
+log4j.appender.grouper_event.layout.ConversionPattern   = grouperd %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
+
+## Grouper API error logging
+log4j.appender.grouper_error                            = org.apache.log4j.FileAppender
+log4j.appender.grouper_error.file                       = /dev/fd/1
+log4j.appender.grouper_errot.append                     = true
+log4j.appender.grouper_error.layout                     = org.apache.log4j.PatternLayout
+log4j.appender.grouper_error.layout.ConversionPattern   = grouperd %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
+#log4j.appender.grouper_error.layout.ConversionPattern   = %d{ISO8601}: %m%n
+
+# Debug logging (Or: logging that I haven't cleaned up yet to send elsewhere)
+log4j.appender.grouper_debug                            = org.apache.log4j.FileAppender
+log4j.appender.grouper_debug.file                       = /dev/fd/1
+log4j.appender.grouper_debug.append                     = true
+log4j.appender.grouper_debug.layout                     = org.apache.log4j.PatternLayout
+#log4j.appender.grouper_debug.layout.ConversionPattern   = %d{ISO8601} %5p %c{2}: %m%n
+log4j.appender.grouper_debug.layout.ConversionPattern   = grouperd %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
+
+## Benchmark logging
+log4j.appender.grouper_gb                               = org.apache.log4j.FileAppender
+log4j.appender.grouper_gb.file                          = /dev/fd/1
+log4j.appender.grouper_gb.append                        = true
+log4j.appender.grouper_gb.layout                        = org.apache.log4j.PatternLayout
+#log4j.appender.grouper_gb.layout.ConversionPattern      = %d{ISO8601} %5p %c{2}: %m%n
+log4j.appender.grouper_gb.layout.ConversionPattern      = grouperd %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
+
+# Loggers
+
+## Default logger; will log *everything*
+log4j.rootLogger  = ERROR, grouper_error
+
+## All Internet2 (warn to grouper_error per default logger)
+log4j.logger.edu.internet2.middleware = WARN
+
+
+# Provisioning : PSP (version 2.1+)
+log4j.logger.edu.internet2.middleware.psp = INFO
+
+# Provisioning : vt-ldap
+# log4j.logger.edu.vt.middleware.ldap = INFO
+
+# Provisioning : Grouper plugin to Shibboleth attribute resolver
+# log4j.logger.edu.internet2.middleware.grouper.shibboleth = INFO
+
+
+# For more precise (or verbose) logging, enable one or more of the
+# following logging directives.  To remove duplicate entries, just change the 
+# level, and not where to send the logs
+# http://robertmarkbramprogrammer.blogspot.com/2007/06/log4j-duplicate-lines-in-output.html
+
+## Grouper Event Logging
+## * Logs at _info_ only
+log4j.logger.edu.internet2.middleware.grouper.log.EventLog        = INFO, grouper_event
+log4j.logger.edu.internet2.middleware.grouper.RegistryInstall = INFO, grouper_event
+
+## Grouper Error Logging
+## * Logs at _warn_, _fatal_ and _error_ only (by default this is WARN due to internet2 below)
+#log4j.logger.edu.internet2.middleware.grouper              = WARN, grouper_error
+
+## Grouper Debug Logging
+## * NOTE: There is currently VERY LITTLE (useful) information sent to this.
+## * Logs at _info_ only currently
+#log4j.logger.edu.internet2.middleware.grouper              = INFO, grouper_debug
+
+## Grouper XML Export + Import Logging
+## TODO Integrate with normal logging
+log4j.logger.edu.internet2.middleware.grouper.xml.XmlExporter           = INFO, grouper_event
+log4j.logger.edu.internet2.middleware.grouper.xml.XmlImporter           = INFO, grouper_event
+
+## Grouper Benchmark Logging
+log4j.logger.edu.internet2.middleware.grouper.bench                 = INFO, grouper_gb
+
+## Grouper script to add missing group sets
+log4j.logger.edu.internet2.middleware.grouper.misc.AddMissingGroupSets   = INFO, grouper_event
+
+## Grouper Sync Point in Time Tables
+log4j.logger.edu.internet2.middleware.grouper.misc.SyncPITTables   = INFO, grouper_event
+
+## Grouper Sync Stem Set Table
+log4j.logger.edu.internet2.middleware.grouper.misc.SyncStemSets      = INFO, grouper_event
+
+## Grouper Migrate Legacy Attributes
+log4j.logger.edu.internet2.middleware.grouper.misc.MigrateLegacyAttributes = INFO, grouper_event
+
+### Subject API
+#log4j.logger.edu.internet2.middleware.subject                       = ERROR, grouper_error
+#log4j.logger.edu.internet2.middleware.subject.provider              = ERROR, grouper_error
+### Hibernate 
+#log4j.logger.org.hibernate                                          = ERROR, grouper_error
+### ehcache
+#log4j.logger.net.sf.ehcache                                         = ERROR, grouper_error
+### Spring
+#log4j.logger.org.springframework                                    = ERROR, grouper_error
+
+## Grouper Stress Testing
+log4j.logger.edu.internet2.middleware.grouper.stress                = INFO, grouper_debug
+
+
+#######################################################
+##Optional settings for debug logs
+#######################################################
+
+## Hooks debug info
+#log4j.logger.edu.internet2.middleware.grouper.hooks.examples.GroupTypeTupleIncludeExcludeHook = DEBUG
+#log4j.logger.edu.internet2.middleware.grouper.Group = DEBUG
+
+#log4j.logger.edu.internet2.middleware.grouper.hooks.examples.GroupTypeSecurityHook = DEBUG
+
+
+# added by grouper-installer
+log4j.logger.org.apache.tools.ant = WARN
diff --git a/container_files/shibboleth/shibd.logger b/container_files/shibboleth/shibd.logger
new file mode 100644
index 0000000..345f327
--- /dev/null
+++ b/container_files/shibboleth/shibd.logger
@@ -0,0 +1,61 @@
+# set overall behavior
+log4j.rootCategory=INFO, shibd_log
+
+# fairly verbose for DEBUG, so generally leave at INFO
+log4j.category.XMLTooling.XMLObject=INFO
+log4j.category.XMLTooling.KeyInfoResolver=INFO
+log4j.category.Shibboleth.IPRange=INFO
+log4j.category.Shibboleth.PropertySet=INFO
+
+# raise for low-level tracing of SOAP client HTTP/SSL behavior
+log4j.category.XMLTooling.libcurl=INFO
+
+# useful categories to tune independently:
+#
+# tracing of SAML messages and security policies
+#log4j.category.OpenSAML.MessageDecoder=DEBUG
+#log4j.category.OpenSAML.MessageEncoder=DEBUG
+#log4j.category.OpenSAML.SecurityPolicyRule=DEBUG
+#log4j.category.XMLTooling.SOAPClient=DEBUG
+# interprocess message remoting
+#log4j.category.Shibboleth.Listener=DEBUG
+# mapping of requests to applicationId
+#log4j.category.Shibboleth.RequestMapper=DEBUG
+# high level session cache operations
+#log4j.category.Shibboleth.SessionCache=DEBUG
+# persistent storage and caching
+#log4j.category.XMLTooling.StorageService=DEBUG
+
+# logs XML being signed or verified if set to DEBUG
+log4j.category.XMLTooling.Signature.Debugger=INFO, sig_log
+log4j.additivity.XMLTooling.Signature.Debugger=false
+
+# the tran log blocks the "default" appender(s) at runtime
+# Level should be left at INFO for this category
+log4j.category.Shibboleth-TRANSACTION=INFO, tran_log
+log4j.additivity.Shibboleth-TRANSACTION=false
+# uncomment to suppress particular event types
+#log4j.category.Shibboleth-TRANSACTION.AuthnRequest=WARN
+#log4j.category.Shibboleth-TRANSACTION.Login=WARN
+#log4j.category.Shibboleth-TRANSACTION.Logout=WARN
+
+# define the appenders
+
+log4j.appender.shibd_log=org.apache.log4j.FileAppender
+log4j.appender.shibd_log.fileName=/dev/fd/1
+log4j.appender.shibd_log.maxFileSize=1000000
+log4j.appender.shibd_log.maxBackupIndex=10
+log4j.appender.shibd_log.layout=org.apache.log4j.PatternLayout
+log4j.appender.shibd_log.layout.ConversionPattern=shibd-log %d{%Y-%m-%d %H:%M:%S} %p %c %x: %m%n
+
+log4j.appender.tran_log=org.apache.log4j.FileAppender
+log4j.appender.tran_log.fileName=/dev/fd/1
+log4j.appender.tran_log.maxFileSize=1000000
+log4j.appender.tran_log.maxBackupIndex=20
+log4j.appender.tran_log.layout=org.apache.log4j.PatternLayout
+log4j.appender.tran_log.layout.ConversionPattern=shibd-tran %d{%Y-%m-%d %H:%M:%S} %p %c %x: %m%n
+
+log4j.appender.sig_log=org.apache.log4j.FileAppender
+log4j.appender.sig_log.fileName=/dev/fd/1
+log4j.appender.sig_log.layout=org.apache.log4j.PatternLayout
+log4j.appender.sig_log.layout.ConversionPattern=shibd-sig %m
diff --git a/container_files/tier-support/supervisord-tomcat.conf b/container_files/tier-support/supervisord-tomcat.conf
index 3bb7553..addcde9 100644
--- a/container_files/tier-support/supervisord-tomcat.conf
+++ b/container_files/tier-support/supervisord-tomcat.conf
@@ -22,7 +22,7 @@ stdout_logfile = /dev/fd/1
 stdout_logfile_maxbytes=0
 
 [program:shibbolethsp]
-user=shibd
+;user=shibd
 command=/usr/sbin/shibd -f -F
 stderr_logfile = /dev/fd/2
 stderr_logfile_maxbytes=0
diff --git a/container_files/tomcat/conf/server.xml b/container_files/tomcat/conf/server.xml
index d07f66f..9610fc7 100644
--- a/container_files/tomcat/conf/server.xml
+++ b/container_files/tomcat/conf/server.xml
@@ -161,9 +161,11 @@
         <!-- Access log processes all example.
              Documentation at: /docs/config/valve.html
              Note: The pattern used is equivalent to using pattern="common" -->
+        <!-- Managing through Apache HTTPD Server config     
         <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                prefix="localhost_access_log" suffix=".txt"
                pattern="%h %l %u %t &quot;%r&quot; %s %b" />
+        -->
 
       </Host>
     </Engine>
diff --git a/container_files/ui/classes/log4j.properties b/container_files/ui/classes/log4j.properties
new file mode 100644
index 0000000..5c981e5
--- /dev/null
+++ b/container_files/ui/classes/log4j.properties
@@ -0,0 +1,144 @@
+
+#
+# Copyright 2014 Internet2
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#/opt/grouper/2.3.0/grouper.apiBinary-2.3.0/ will be substituted with the System property "grouper.home", which must have a trailing \ or / 
+# depending on your OS. Of course you can use absolute paths if you prefer 
+
+
+#
+# log4j Configuration
+# $Id: log4j.example.properties,v 1.13 2009-12-18 13:56:51 tzeller Exp $
+#
+
+# Appenders
+
+## Grouper API event logging
+log4j.appender.grouper_event                            = org.apache.log4j.FileAppender
+log4j.appender.grouper_event.file                       = /dev/fd/1
+log4j.appender.grouper_event.append                     = true
+log4j.appender.grouper_event.layout                     = org.apache.log4j.PatternLayout
+log4j.appender.grouper_event.layout.ConversionPattern   = grouper-ui %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
+
+## Grouper API error logging
+log4j.appender.grouper_error                            = org.apache.log4j.FileAppender
+log4j.appender.grouper_error.file                       = /dev/fd/1
+log4j.appender.grouper_errot.append                     = true
+log4j.appender.grouper_error.layout                     = org.apache.log4j.PatternLayout
+log4j.appender.grouper_error.layout.ConversionPattern   = grouper-ui %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
+#log4j.appender.grouper_error.layout.ConversionPattern   = %d{ISO8601}: %m%n
+
+# Debug logging (Or: logging that I haven't cleaned up yet to send elsewhere)
+log4j.appender.grouper_debug                            = org.apache.log4j.FileAppender
+log4j.appender.grouper_debug.file                       = /dev/fd/1
+log4j.appender.grouper_debug.append                     = true
+log4j.appender.grouper_debug.layout                     = org.apache.log4j.PatternLayout
+#log4j.appender.grouper_debug.layout.ConversionPattern   = %d{ISO8601} %5p %c{2}: %m%n
+log4j.appender.grouper_debug.layout.ConversionPattern   = grouper-ui %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
+
+## Benchmark logging
+log4j.appender.grouper_gb                               = org.apache.log4j.FileAppender
+log4j.appender.grouper_gb.file                          = /dev/fd/1
+log4j.appender.grouper_gb.append                     = true
+log4j.appender.grouper_gb.layout                        = org.apache.log4j.PatternLayout
+#log4j.appender.grouper_gb.layout.ConversionPattern      = %d{ISO8601} %5p %c{2}: %m%n
+log4j.appender.grouper_gb.layout.ConversionPattern      = grouper-ui %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
+
+# Loggers
+
+## Default logger; will log *everything*
+log4j.rootLogger  = ERROR, grouper_error
+
+## All Internet2 (warn to grouper_error per default logger)
+log4j.logger.edu.internet2.middleware = WARN
+
+
+# Provisioning : PSP (version 2.1+)
+log4j.logger.edu.internet2.middleware.psp = INFO
+
+# Provisioning : vt-ldap
+# log4j.logger.edu.vt.middleware.ldap = INFO
+
+# Provisioning : Grouper plugin to Shibboleth attribute resolver
+# log4j.logger.edu.internet2.middleware.grouper.shibboleth = INFO
+
+
+# For more precise (or verbose) logging, enable one or more of the
+# following logging directives.  To remove duplicate entries, just change the 
+# level, and not where to send the logs
+# http://robertmarkbramprogrammer.blogspot.com/2007/06/log4j-duplicate-lines-in-output.html
+
+## Grouper Event Logging
+## * Logs at _info_ only
+log4j.logger.edu.internet2.middleware.grouper.log.EventLog        = INFO, grouper_event
+log4j.logger.edu.internet2.middleware.grouper.RegistryInstall = INFO, grouper_event
+
+## Grouper Error Logging
+## * Logs at _warn_, _fatal_ and _error_ only (by default this is WARN due to internet2 below)
+#log4j.logger.edu.internet2.middleware.grouper              = WARN, grouper_error
+
+## Grouper Debug Logging
+## * NOTE: There is currently VERY LITTLE (useful) information sent to this.
+## * Logs at _info_ only currently
+#log4j.logger.edu.internet2.middleware.grouper              = INFO, grouper_debug
+
+## Grouper XML Export + Import Logging
+## TODO Integrate with normal logging
+log4j.logger.edu.internet2.middleware.grouper.xml.XmlExporter           = INFO, grouper_event
+log4j.logger.edu.internet2.middleware.grouper.xml.XmlImporter           = INFO, grouper_event
+
+## Grouper Benchmark Logging
+log4j.logger.edu.internet2.middleware.grouper.bench                 = INFO, grouper_gb
+
+## Grouper script to add missing group sets
+log4j.logger.edu.internet2.middleware.grouper.misc.AddMissingGroupSets   = INFO, grouper_event
+
+## Grouper Sync Point in Time Tables
+log4j.logger.edu.internet2.middleware.grouper.misc.SyncPITTables   = INFO, grouper_event
+
+## Grouper Sync Stem Set Table
+log4j.logger.edu.internet2.middleware.grouper.misc.SyncStemSets      = INFO, grouper_event
+
+## Grouper Migrate Legacy Attributes
+log4j.logger.edu.internet2.middleware.grouper.misc.MigrateLegacyAttributes = INFO, grouper_event
+
+### Subject API
+#log4j.logger.edu.internet2.middleware.subject                       = ERROR, grouper_error
+#log4j.logger.edu.internet2.middleware.subject.provider              = ERROR, grouper_error
+### Hibernate 
+#log4j.logger.org.hibernate                                          = ERROR, grouper_error
+### ehcache
+#log4j.logger.net.sf.ehcache                                         = ERROR, grouper_error
+### Spring
+#log4j.logger.org.springframework                                    = ERROR, grouper_error
+
+## Grouper Stress Testing
+log4j.logger.edu.internet2.middleware.grouper.stress                = INFO, grouper_debug
+
+
+#######################################################
+##Optional settings for debug logs
+#######################################################
+
+## Hooks debug info
+#log4j.logger.edu.internet2.middleware.grouper.hooks.examples.GroupTypeTupleIncludeExcludeHook = DEBUG
+#log4j.logger.edu.internet2.middleware.grouper.Group = DEBUG
+
+#log4j.logger.edu.internet2.middleware.grouper.hooks.examples.GroupTypeSecurityHook = DEBUG
+
+
+# added by grouper-installer
+log4j.logger.org.apache.tools.ant = WARN
diff --git a/container_files/ws/classes/log4j.properties b/container_files/ws/classes/log4j.properties
new file mode 100644
index 0000000..88f684f
--- /dev/null
+++ b/container_files/ws/classes/log4j.properties
@@ -0,0 +1,144 @@
+
+#
+# Copyright 2014 Internet2
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#${grouper.home} will be substituted with the System property "grouper.home", which must have a trailing \ or / 
+# depending on your OS. Of course you can use absolute paths if you prefer 
+
+
+#
+# log4j Configuration
+# $Id: log4j.example.properties,v 1.13 2009-12-18 13:56:51 tzeller Exp $
+#
+
+# Appenders
+
+## Grouper API event logging
+log4j.appender.grouper_event                            = org.apache.log4j.FileAppender
+log4j.appender.grouper_event.file                       = /dev/fd/1
+log4j.appender.grouper_event.append                     = true
+log4j.appender.grouper_event.layout                     = org.apache.log4j.PatternLayout
+log4j.appender.grouper_event.layout.ConversionPattern   = grouper-ws %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
+
+## Grouper API error logging
+log4j.appender.grouper_error                            = org.apache.log4j.FileAppender
+log4j.appender.grouper_error.file                       = /dev/fd/1
+log4j.appender.grouper_errot.append                     = true
+log4j.appender.grouper_error.layout                     = org.apache.log4j.PatternLayout
+log4j.appender.grouper_error.layout.ConversionPattern   = grouper-ws %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
+#log4j.appender.grouper_error.layout.ConversionPattern   = %d{ISO8601}: %m%n
+
+# Debug logging (Or: logging that I haven't cleaned up yet to send elsewhere)
+log4j.appender.grouper_debug                            = org.apache.log4j.FileAppender
+log4j.appender.grouper_debug.file                       = /dev/fd/1
+log4j.appender.grouper_debug.append                     = true
+log4j.appender.grouper_debug.layout                     = org.apache.log4j.PatternLayout
+#log4j.appender.grouper_debug.layout.ConversionPattern   = %d{ISO8601} %5p %c{2}: %m%n
+log4j.appender.grouper_debug.layout.ConversionPattern   = grouper-ws %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
+
+## Benchmark logging
+log4j.appender.grouper_gb                               = org.apache.log4j.FileAppender
+log4j.appender.grouper_gb.file                          = /dev/fd/1
+log4j.appender.grouper_gb.append                     = true
+log4j.appender.grouper_gb.layout                        = org.apache.log4j.PatternLayout
+#log4j.appender.grouper_gb.layout.ConversionPattern      = %d{ISO8601} %5p %c{2}: %m%n
+log4j.appender.grouper_gb.layout.ConversionPattern      = grouper-ws %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
+
+# Loggers
+
+## Default logger; will log *everything*
+log4j.rootLogger  = ERROR, grouper_error
+
+## All Internet2 (warn to grouper_error per default logger)
+log4j.logger.edu.internet2.middleware = WARN
+
+
+# Provisioning : PSP (version 2.1+)
+log4j.logger.edu.internet2.middleware.psp = INFO
+
+# Provisioning : vt-ldap
+# log4j.logger.edu.vt.middleware.ldap = INFO
+
+# Provisioning : Grouper plugin to Shibboleth attribute resolver
+# log4j.logger.edu.internet2.middleware.grouper.shibboleth = INFO
+
+
+# For more precise (or verbose) logging, enable one or more of the
+# following logging directives.  To remove duplicate entries, just change the 
+# level, and not where to send the logs
+# http://robertmarkbramprogrammer.blogspot.com/2007/06/log4j-duplicate-lines-in-output.html
+
+## Grouper Event Logging
+## * Logs at _info_ only
+log4j.logger.edu.internet2.middleware.grouper.log.EventLog        = INFO, grouper_event
+log4j.logger.edu.internet2.middleware.grouper.RegistryInstall = INFO, grouper_event
+
+## Grouper Error Logging
+## * Logs at _warn_, _fatal_ and _error_ only (by default this is WARN due to internet2 below)
+#log4j.logger.edu.internet2.middleware.grouper              = WARN, grouper_error
+
+## Grouper Debug Logging
+## * NOTE: There is currently VERY LITTLE (useful) information sent to this.
+## * Logs at _info_ only currently
+#log4j.logger.edu.internet2.middleware.grouper              = INFO, grouper_debug
+
+## Grouper XML Export + Import Logging
+## TODO Integrate with normal logging
+log4j.logger.edu.internet2.middleware.grouper.xml.XmlExporter           = INFO, grouper_event
+log4j.logger.edu.internet2.middleware.grouper.xml.XmlImporter           = INFO, grouper_event
+
+## Grouper Benchmark Logging
+log4j.logger.edu.internet2.middleware.grouper.bench                 = INFO, grouper_gb
+
+## Grouper script to add missing group sets
+log4j.logger.edu.internet2.middleware.grouper.misc.AddMissingGroupSets   = INFO, grouper_event
+
+## Grouper Sync Point in Time Tables
+log4j.logger.edu.internet2.middleware.grouper.misc.SyncPITTables   = INFO, grouper_event
+
+## Grouper Sync Stem Set Table
+log4j.logger.edu.internet2.middleware.grouper.misc.SyncStemSets      = INFO, grouper_event
+
+## Grouper Migrate Legacy Attributes
+log4j.logger.edu.internet2.middleware.grouper.misc.MigrateLegacyAttributes = INFO, grouper_event
+
+### Subject API
+#log4j.logger.edu.internet2.middleware.subject                       = ERROR, grouper_error
+#log4j.logger.edu.internet2.middleware.subject.provider              = ERROR, grouper_error
+### Hibernate 
+#log4j.logger.org.hibernate                                          = ERROR, grouper_error
+### ehcache
+#log4j.logger.net.sf.ehcache                                         = ERROR, grouper_error
+### Spring
+#log4j.logger.org.springframework                                    = ERROR, grouper_error
+
+## Grouper Stress Testing
+log4j.logger.edu.internet2.middleware.grouper.stress                = INFO, grouper_debug
+
+
+#######################################################
+##Optional settings for debug logs
+#######################################################
+
+## Hooks debug info
+#log4j.logger.edu.internet2.middleware.grouper.hooks.examples.GroupTypeTupleIncludeExcludeHook = DEBUG
+#log4j.logger.edu.internet2.middleware.grouper.Group = DEBUG
+
+#log4j.logger.edu.internet2.middleware.grouper.hooks.examples.GroupTypeSecurityHook = DEBUG
+
+
+# added by grouper-installer
+log4j.logger.org.apache.tools.ant = WARN

From 96fafc69cf5e2e6981f6a5a0ea47cd0c2de36820 Mon Sep 17 00:00:00 2001
From: John Gasper <jtgasper3@gmail.com>
Date: Mon, 26 Mar 2018 11:50:14 -0700
Subject: [PATCH 2/4] Creating a user/process agnostic logging pipe and sending
 output there

---
 Dockerfile                                       |  4 ++--
 container_files/api/log4j.properties             |  8 ++++----
 container_files/shibboleth/shibd.logger          |  6 +++---
 .../tier-support/supervisord-tomcat.conf         | 16 ++++++++--------
 .../tier-support/supervisord-tomee.conf          | 10 +++++-----
 container_files/ui/classes/log4j.properties      | 10 +++++-----
 container_files/usr-local-bin/library.sh         |  4 ++++
 container_files/ws/classes/log4j.properties      | 10 +++++-----
 8 files changed, 36 insertions(+), 32 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index f0173d8..8f12322 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -109,8 +109,8 @@ COPY container_files/shibboleth/* /etc/shibboleth/
 RUN cp /dev/null /etc/httpd/conf.d/ssl.conf \
     && sed -i 's/LogFormat "/LogFormat "httpd-access /g' /etc/httpd/conf/httpd.conf \
     && echo -e "\nErrorLogFormat \"httpd-error [%{u}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i\"" >> /etc/httpd/conf/httpd.conf \
-    && sed -i 's/CustomLog "logs\/access_log"/CustomLog "\/proc\/self\/fd\/1"/g' /etc/httpd/conf/httpd.conf \
-    && sed -i 's/ErrorLog "logs\/error_log"/ErrorLog "\/proc\/self\/fd\/1"/g' /etc/httpd/conf/httpd.conf
+    && sed -i 's/CustomLog "logs\/access_log"/CustomLog "\/tmp\/logpipe"/g' /etc/httpd/conf/httpd.conf \
+    && sed -i 's/ErrorLog "logs\/error_log"/ErrorLog "\/tmp\/logpipe"/g' /etc/httpd/conf/httpd.conf
 
 WORKDIR /opt/grouper/grouper.apiBinary/
 
diff --git a/container_files/api/log4j.properties b/container_files/api/log4j.properties
index 22ec105..f9298f2 100644
--- a/container_files/api/log4j.properties
+++ b/container_files/api/log4j.properties
@@ -28,14 +28,14 @@
 
 ## Grouper API event logging
 log4j.appender.grouper_event                            = org.apache.log4j.FileAppender
-log4j.appender.grouper_event.file                       = /dev/fd/1
+log4j.appender.grouper_event.file                       = /tmp/logpipe
 log4j.appender.grouper_event.append                     = true
 log4j.appender.grouper_event.layout                     = org.apache.log4j.PatternLayout
 log4j.appender.grouper_event.layout.ConversionPattern   = grouperd %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
 
 ## Grouper API error logging
 log4j.appender.grouper_error                            = org.apache.log4j.FileAppender
-log4j.appender.grouper_error.file                       = /dev/fd/1
+log4j.appender.grouper_error.file                       = /tmp/logpipe
 log4j.appender.grouper_errot.append                     = true
 log4j.appender.grouper_error.layout                     = org.apache.log4j.PatternLayout
 log4j.appender.grouper_error.layout.ConversionPattern   = grouperd %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
@@ -43,7 +43,7 @@ log4j.appender.grouper_error.layout.ConversionPattern   = grouperd %d{ISO8601}:
 
 # Debug logging (Or: logging that I haven't cleaned up yet to send elsewhere)
 log4j.appender.grouper_debug                            = org.apache.log4j.FileAppender
-log4j.appender.grouper_debug.file                       = /dev/fd/1
+log4j.appender.grouper_debug.file                       = /tmp/logpipe
 log4j.appender.grouper_debug.append                     = true
 log4j.appender.grouper_debug.layout                     = org.apache.log4j.PatternLayout
 #log4j.appender.grouper_debug.layout.ConversionPattern   = %d{ISO8601} %5p %c{2}: %m%n
@@ -51,7 +51,7 @@ log4j.appender.grouper_debug.layout.ConversionPattern   = grouperd %d{ISO8601}:
 
 ## Benchmark logging
 log4j.appender.grouper_gb                               = org.apache.log4j.FileAppender
-log4j.appender.grouper_gb.file                          = /dev/fd/1
+log4j.appender.grouper_gb.file                          = /tmp/logpipe
 log4j.appender.grouper_gb.append                        = true
 log4j.appender.grouper_gb.layout                        = org.apache.log4j.PatternLayout
 #log4j.appender.grouper_gb.layout.ConversionPattern      = %d{ISO8601} %5p %c{2}: %m%n
diff --git a/container_files/shibboleth/shibd.logger b/container_files/shibboleth/shibd.logger
index 345f327..22208ca 100644
--- a/container_files/shibboleth/shibd.logger
+++ b/container_files/shibboleth/shibd.logger
@@ -42,20 +42,20 @@ log4j.additivity.Shibboleth-TRANSACTION=false
 # define the appenders
 
 log4j.appender.shibd_log=org.apache.log4j.FileAppender
-log4j.appender.shibd_log.fileName=/dev/fd/1
+log4j.appender.shibd_log.fileName=/tmp/logpipe
 log4j.appender.shibd_log.maxFileSize=1000000
 log4j.appender.shibd_log.maxBackupIndex=10
 log4j.appender.shibd_log.layout=org.apache.log4j.PatternLayout
 log4j.appender.shibd_log.layout.ConversionPattern=shibd-log %d{%Y-%m-%d %H:%M:%S} %p %c %x: %m%n
 
 log4j.appender.tran_log=org.apache.log4j.FileAppender
-log4j.appender.tran_log.fileName=/dev/fd/1
+log4j.appender.tran_log.fileName=/tmp/logpipe
 log4j.appender.tran_log.maxFileSize=1000000
 log4j.appender.tran_log.maxBackupIndex=20
 log4j.appender.tran_log.layout=org.apache.log4j.PatternLayout
 log4j.appender.tran_log.layout.ConversionPattern=shibd-tran %d{%Y-%m-%d %H:%M:%S} %p %c %x: %m%n
 
 log4j.appender.sig_log=org.apache.log4j.FileAppender
-log4j.appender.sig_log.fileName=/dev/fd/1
+log4j.appender.sig_log.fileName=/tmp/logpipe
 log4j.appender.sig_log.layout=org.apache.log4j.PatternLayout
 log4j.appender.sig_log.layout.ConversionPattern=shibd-sig %m
diff --git a/container_files/tier-support/supervisord-tomcat.conf b/container_files/tier-support/supervisord-tomcat.conf
index addcde9..78f0b2e 100644
--- a/container_files/tier-support/supervisord-tomcat.conf
+++ b/container_files/tier-support/supervisord-tomcat.conf
@@ -1,5 +1,5 @@
 [supervisord]
-logfile=/dev/fd/1                               ; supervisord log file
+logfile=/tmp/logpipe                               ; supervisord log file
 logfile_maxbytes=0                           ; maximum size of logfile before rotation
 loglevel=error                                  ; info, debug, warn, trace
 nodaemon=true                                  ; run supervisord as a daemon
@@ -16,24 +16,24 @@ serverurl=unix:///tmp/supervisor.sock         ; use a unix:// URL  for a unix so
 
 [program:httpd]
 command=httpd -DFOREGROUND
-stderr_logfile = /dev/fd/2
+stderr_logfile = /tmp/logpipe
 stderr_logfile_maxbytes=0
-stdout_logfile = /dev/fd/1
+stdout_logfile = /tmp/logpipe
 stdout_logfile_maxbytes=0
 
 [program:shibbolethsp]
-;user=shibd
+user=shibd
 command=/usr/sbin/shibd -f -F
-stderr_logfile = /dev/fd/2
+stderr_logfile = /tmp/logpipe
 stderr_logfile_maxbytes=0
-stdout_logfile = /dev/fd/1
+stdout_logfile = /tmp/logpipe
 stdout_logfile_maxbytes=0
 
 [program:tomcat]
 user=tomcat
 command=/opt/tomcat/bin/catalina.sh run 
-stderr_logfile = /dev/fd/2
+stderr_logfile = /tmp/logpipe
 stderr_logfile_maxbytes=0
-stdout_logfile = /dev/fd/1
+stdout_logfile = /tmp/logpipe
 stdout_logfile_maxbytes=0
 
diff --git a/container_files/tier-support/supervisord-tomee.conf b/container_files/tier-support/supervisord-tomee.conf
index 40d0c81..4d83843 100644
--- a/container_files/tier-support/supervisord-tomee.conf
+++ b/container_files/tier-support/supervisord-tomee.conf
@@ -1,5 +1,5 @@
 [supervisord]
-logfile=/dev/fd/1                               ; supervisord log file
+logfile=/tmp/logpipe                               ; supervisord log file
 logfile_maxbytes=0                           ; maximum size of logfile before rotation
 loglevel=error                                  ; info, debug, warn, trace
 nodaemon=true                                  ; run supervisord as a daemon
@@ -16,16 +16,16 @@ serverurl=unix:///tmp/supervisor.sock         ; use a unix:// URL  for a unix so
 
 [program:httpd]
 command=httpd -DFOREGROUND
-stderr_logfile = /dev/fd/2
+stderr_logfile = /tmp/logpipe
 stderr_logfile_maxbytes=0
-stdout_logfile = /dev/fd/1
+stdout_logfile = /tmp/logpipe
 stdout_logfile_maxbytes=0
 
 [program:tomee]
 user=tomcat
 command=/opt/tomee/bin/catalina.sh run 
-stderr_logfile = /dev/fd/2
+stderr_logfile = /tmp/logpipe
 stderr_logfile_maxbytes=0
-stdout_logfile = /dev/fd/1
+stdout_logfile = /tmp/logpipe
 stdout_logfile_maxbytes=0
 
diff --git a/container_files/ui/classes/log4j.properties b/container_files/ui/classes/log4j.properties
index 5c981e5..bbbfa94 100644
--- a/container_files/ui/classes/log4j.properties
+++ b/container_files/ui/classes/log4j.properties
@@ -28,14 +28,14 @@
 
 ## Grouper API event logging
 log4j.appender.grouper_event                            = org.apache.log4j.FileAppender
-log4j.appender.grouper_event.file                       = /dev/fd/1
+log4j.appender.grouper_event.file                       = /tmp/logpipe
 log4j.appender.grouper_event.append                     = true
 log4j.appender.grouper_event.layout                     = org.apache.log4j.PatternLayout
 log4j.appender.grouper_event.layout.ConversionPattern   = grouper-ui %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
 
 ## Grouper API error logging
 log4j.appender.grouper_error                            = org.apache.log4j.FileAppender
-log4j.appender.grouper_error.file                       = /dev/fd/1
+log4j.appender.grouper_error.file                       = /tmp/logpipe
 log4j.appender.grouper_errot.append                     = true
 log4j.appender.grouper_error.layout                     = org.apache.log4j.PatternLayout
 log4j.appender.grouper_error.layout.ConversionPattern   = grouper-ui %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
@@ -43,7 +43,7 @@ log4j.appender.grouper_error.layout.ConversionPattern   = grouper-ui %d{ISO8601}
 
 # Debug logging (Or: logging that I haven't cleaned up yet to send elsewhere)
 log4j.appender.grouper_debug                            = org.apache.log4j.FileAppender
-log4j.appender.grouper_debug.file                       = /dev/fd/1
+log4j.appender.grouper_debug.file                       = /tmp/logpipe
 log4j.appender.grouper_debug.append                     = true
 log4j.appender.grouper_debug.layout                     = org.apache.log4j.PatternLayout
 #log4j.appender.grouper_debug.layout.ConversionPattern   = %d{ISO8601} %5p %c{2}: %m%n
@@ -51,8 +51,8 @@ log4j.appender.grouper_debug.layout.ConversionPattern   = grouper-ui %d{ISO8601}
 
 ## Benchmark logging
 log4j.appender.grouper_gb                               = org.apache.log4j.FileAppender
-log4j.appender.grouper_gb.file                          = /dev/fd/1
-log4j.appender.grouper_gb.append                     = true
+log4j.appender.grouper_gb.file                          = /tmp/logpipe
+log4j.appender.grouper_gb.append                        = true
 log4j.appender.grouper_gb.layout                        = org.apache.log4j.PatternLayout
 #log4j.appender.grouper_gb.layout.ConversionPattern      = %d{ISO8601} %5p %c{2}: %m%n
 log4j.appender.grouper_gb.layout.ConversionPattern      = grouper-ui %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
diff --git a/container_files/usr-local-bin/library.sh b/container_files/usr-local-bin/library.sh
index d8b1dd9..c89ef4c 100644
--- a/container_files/usr-local-bin/library.sh
+++ b/container_files/usr-local-bin/library.sh
@@ -1,5 +1,9 @@
 #!/bin/sh
 
+# Make a "console" logging pipe that anyone can write too regardless of who owns the process.
+mkfifo -m 666 /tmp/logpipe
+cat <> /tmp/logpipe 1>&2 &
+
 linkGrouperSecrets() {
     for filepath in /run/secrets/*; do
         local label_file=`basename $filepath`
diff --git a/container_files/ws/classes/log4j.properties b/container_files/ws/classes/log4j.properties
index 88f684f..2ce32b6 100644
--- a/container_files/ws/classes/log4j.properties
+++ b/container_files/ws/classes/log4j.properties
@@ -28,14 +28,14 @@
 
 ## Grouper API event logging
 log4j.appender.grouper_event                            = org.apache.log4j.FileAppender
-log4j.appender.grouper_event.file                       = /dev/fd/1
+log4j.appender.grouper_event.file                       = /tmp/logpipe
 log4j.appender.grouper_event.append                     = true
 log4j.appender.grouper_event.layout                     = org.apache.log4j.PatternLayout
 log4j.appender.grouper_event.layout.ConversionPattern   = grouper-ws %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
 
 ## Grouper API error logging
 log4j.appender.grouper_error                            = org.apache.log4j.FileAppender
-log4j.appender.grouper_error.file                       = /dev/fd/1
+log4j.appender.grouper_error.file                       = /tmp/logpipe
 log4j.appender.grouper_errot.append                     = true
 log4j.appender.grouper_error.layout                     = org.apache.log4j.PatternLayout
 log4j.appender.grouper_error.layout.ConversionPattern   = grouper-ws %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n
@@ -43,7 +43,7 @@ log4j.appender.grouper_error.layout.ConversionPattern   = grouper-ws %d{ISO8601}
 
 # Debug logging (Or: logging that I haven't cleaned up yet to send elsewhere)
 log4j.appender.grouper_debug                            = org.apache.log4j.FileAppender
-log4j.appender.grouper_debug.file                       = /dev/fd/1
+log4j.appender.grouper_debug.file                       = /tmp/logpipe
 log4j.appender.grouper_debug.append                     = true
 log4j.appender.grouper_debug.layout                     = org.apache.log4j.PatternLayout
 #log4j.appender.grouper_debug.layout.ConversionPattern   = %d{ISO8601} %5p %c{2}: %m%n
@@ -51,8 +51,8 @@ log4j.appender.grouper_debug.layout.ConversionPattern   = grouper-ws %d{ISO8601}
 
 ## Benchmark logging
 log4j.appender.grouper_gb                               = org.apache.log4j.FileAppender
-log4j.appender.grouper_gb.file                          = /dev/fd/1
-log4j.appender.grouper_gb.append                     = true
+log4j.appender.grouper_gb.file                          = /tmp/logpipe
+log4j.appender.grouper_gb.append                        = true
 log4j.appender.grouper_gb.layout                        = org.apache.log4j.PatternLayout
 #log4j.appender.grouper_gb.layout.ConversionPattern      = %d{ISO8601} %5p %c{2}: %m%n
 log4j.appender.grouper_gb.layout.ConversionPattern      = grouper-ws %d{ISO8601}: [%t] %-5p %C{1}.%M(%L) - %x - %m%n

From 059b483ca4ade9123a4364c8e291c79684ab523b Mon Sep 17 00:00:00 2001
From: John Gasper <jtgasper3@gmail.com>
Date: Mon, 26 Mar 2018 11:52:30 -0700
Subject: [PATCH 3/4] POC for pulling in secrets into Grouper property files

---
 .../grouper/database_password.txt             |   0
 .../grouper/grouper.hibernate.properties      |   3 +-
 .../grouper/ldap.properties                   |   2 +-
 .../configs-and-secrets/grouper/sources.xml   | 295 ------------------
 .../grouper/subject.properties                |  75 +++++
 .../conf/grouper.hibernate.properties         |   3 +-
 .../data/container_files/conf/sources.xml     | 295 ------------------
 .../container_files/conf/subject.properties   |  75 +++++
 test-compose/docker-compose.yml               | 110 ++++---
 9 files changed, 220 insertions(+), 638 deletions(-)
 create mode 100644 test-compose/configs-and-secrets/grouper/database_password.txt
 delete mode 100644 test-compose/configs-and-secrets/grouper/sources.xml
 create mode 100644 test-compose/configs-and-secrets/grouper/subject.properties
 delete mode 100644 test-compose/data/container_files/conf/sources.xml
 create mode 100644 test-compose/data/container_files/conf/subject.properties

diff --git a/test-compose/configs-and-secrets/grouper/database_password.txt b/test-compose/configs-and-secrets/grouper/database_password.txt
new file mode 100644
index 0000000..e69de29
diff --git a/test-compose/configs-and-secrets/grouper/grouper.hibernate.properties b/test-compose/configs-and-secrets/grouper/grouper.hibernate.properties
index b9cc983..96abb4c 100644
--- a/test-compose/configs-and-secrets/grouper/grouper.hibernate.properties
+++ b/test-compose/configs-and-secrets/grouper/grouper.hibernate.properties
@@ -26,5 +26,4 @@ hibernate.connection.username         = root
 # If you are using an empty password, depending upon your version of
 # Java and Ant you may need to specify a password of "".
 # Note: you can keep passwords external and encrypted: https://bugs.internet2.edu/jira/browse/GRP-122
-hibernate.connection.password         = 
-
+hibernate.connection.password.elConfig = ${java.lang.System.getenv().get('GROUPER_DATABASE_PASSWORD_FILE') != null ? org.apache.commons.io.FileUtils.readFileToString(java.lang.System.getenv().get('GROUPER_DATABASE_PASSWORD_FILE'), "utf-8") : java.lang.System.getenv().get('GROUPER_DATABASE_PASSWORD') }
diff --git a/test-compose/configs-and-secrets/grouper/ldap.properties b/test-compose/configs-and-secrets/grouper/ldap.properties
index 5de794c..df38a6e 100644
--- a/test-compose/configs-and-secrets/grouper/ldap.properties
+++ b/test-compose/configs-and-secrets/grouper/ldap.properties
@@ -6,7 +6,7 @@ edu.vt.middleware.ldap.searchScope=SUBTREE
 
 # authn if simple
 edu.vt.middleware.ldap.bindDn=cn=admin,dc=internet2,dc=edu
-edu.vt.middleware.ldap.bindCredential=secret
+edu.vt.middleware.ldap.bindCredential.elConfig =
 # The bind credential may be external and encrypted: https://bugs.internet2.edu/jira/browse/GRP-122
 # edu.vt.middleware.ldap.bindCredential=/path/to/ldap.pwd
 edu.vt.middleware.ldap.authtype=simple
diff --git a/test-compose/configs-and-secrets/grouper/sources.xml b/test-compose/configs-and-secrets/grouper/sources.xml
deleted file mode 100644
index 9c884ae..0000000
--- a/test-compose/configs-and-secrets/grouper/sources.xml
+++ /dev/null
@@ -1,295 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
-Grouper's subject resolver configuration
-$Id: sources.example.xml,v 1.8 2009-08-11 20:18:09 mchyzer Exp $
--->
-
-<sources>
-
-  <!-- Group Subject Resolver -->
-  
-  <!-- 
-     You can flag a source as not throwing exception on a findAll (general search) i.e. if it is
-     ok if it is down.  Generally you probably won't want to do this.  It defaults to true if omitted.
-  
-     <init-param>
-       <param-name>throwErrorOnFindAllFailure</param-name>
-       <param-value>false</param-value>
-     </init-param>
-   -->
-  
-  <!-- 
-      You can make virtual attributes (attributes with formatting or based on other attributes) like this:
-      init-param name is subjectVirtualAttribute_<index>_<name> where index is the order to be processed
-      if some depend on others (0 to 99).  The value is the jexl expression language.  You can use subjectUtils
-      methods (aliased with "subjectUtils", or you can register your own class (must have default constructor).
-      Here are examples:
-  
-     <init-param>
-       <param-name>subjectVirtualAttribute_0_loginIdLfName</param-name>
-       <param-value>Hey ${subject.getAttributeValue('LOGINID')} and ${subject.getAttributeValue('LFNAME')}</param-value>
-     </init-param>
-     <init-param>
-       <param-name>subjectVirtualAttribute_1_loginIdLfNameLoginId</param-name>
-       <param-value>${subject.getAttributeValue('loginIdLfName')} Hey ${subject.getAttributeValue('LOGINID')} and ${subject.getAttributeValue('LFNAME')}</param-value>
-     </init-param>
-     <init-param>
-       <param-name>subjectVirtualAttributeVariable_JDBCSourceAdapterTest</param-name>
-       <param-value>edu.internet2.middleware.subject.provider.JDBCSourceAdapterTest</param-value>
-     </init-param>
-     <init-param>
-       <param-name>subjectVirtualAttribute_2_loginIdSquared</param-name>
-       <param-value>${JDBCSourceAdapterTest.appendToSelf(subject.getAttributeValue('LOGINID'))}</param-value>
-     </init-param>
-  
-    The first virtual attribute is accessible via: subject.getAttributeValue("loginIdLfNameLoginId");
-  
-    you can set these c3p0 settings: maxConnectionAge (seconds), testConnectionOnCheckout (true|false), 
-       preferredTestQuery (e.g. select 1 from dual), idleConnectionTestPeriod (seconds)
-  
-   -->
-  
-  <!-- 
-    NOTE: It is recommended that you **not** change the default
-          values for this source adapter.
-  -->
-  <source adapterClass="edu.internet2.middleware.grouper.GrouperSourceAdapter">
-    <id>g:gsa</id>
-    <name>Grouper: Group Source Adapter</name>
-    <type>group</type>
-
-    <init-param>
-      <param-name>subjectVirtualAttribute_0_searchAttribute0</param-name>
-      <param-value>${subject.getAttributeValue('name')},${subject.getAttributeValue('displayName')},${subject.getAttributeValue('alternateName')}</param-value>
-    </init-param>
-    <init-param>
-      <param-name>sortAttribute0</param-name>
-      <param-value>displayExtension</param-value>
-    </init-param>
-    <init-param>
-      <param-name>searchAttribute0</param-name>
-      <param-value>searchAttribute0</param-value>
-    </init-param>
-    <!-- on a findPage() this is the most results returned --> 
-    <init-param>
-      <param-name>maxPageSize</param-name>
-      <param-value>100</param-value>
-    </init-param>
-    <internal-attribute>searchAttribute0</internal-attribute>
-  </source>
-  <!-- Group Subject Resolver -->
-
-  <!-- 
-    NOTE: It is recommended that you **not** change the default
-          values for this source adapter.
-  -->
-  <source adapterClass="edu.internet2.middleware.grouper.entity.EntitySourceAdapter">
-    <id>grouperEntities</id>
-    <name>Grouper: Entity Source Adapter</name>
-    <type>application</type>
-
-    <init-param>
-      <param-name>subjectVirtualAttribute_0_searchAttribute0</param-name>
-      <!-- TODO add attribute for subject identifier -->
-      <param-value>${subject.getAttributeValue('name')},${subject.getAttributeValue('displayName')},${subject.getAttributeValue('alternateName')}</param-value>
-    </init-param>
-    <init-param>
-      <param-name>sortAttribute0</param-name>
-      <param-value>name</param-value>
-    </init-param>
-    <init-param>
-      <param-name>searchAttribute0</param-name>
-      <param-value>searchAttribute0</param-value>
-    </init-param>
-    <internal-attribute>searchAttribute0</internal-attribute>
-  </source>
-
-
-  <!-- Entity Subject Resolver -->
-  <source adapterClass="edu.internet2.middleware.grouper.subj.GrouperJndiSourceAdapter">
-    <id>ldap</id>
-    <name>EDU Ldap</name>
-    <type>person</type>
-    <init-param>
-      <param-name>INITIAL_CONTEXT_FACTORY</param-name>
-      <param-value>com.sun.jndi.ldap.LdapCtxFactory</param-value>
-    </init-param>
-    <init-param>
-      <param-name>PROVIDER_URL</param-name>
-      <param-value>ldap://data</param-value>
-    </init-param>
-    <init-param>
-      <param-name>SECURITY_AUTHENTICATION</param-name>
-      <param-value>simple</param-value>
-    </init-param>
-    <init-param>
-      <param-name>SECURITY_PRINCIPAL</param-name>
-      <param-value>cn=admin,dc=internet2,dc=edu</param-value>
-    </init-param>
-    <init-param>
-      <param-name>SECURITY_CREDENTIALS</param-name>
-      <param-value>password</param-value>
-    </init-param>
-     <init-param>
-      <param-name>SubjectID_AttributeType</param-name>
-      <param-value>uid</param-value>
-    </init-param>
-     <init-param>
-      <param-name>SubjectID_formatToLowerCase</param-name>
-      <param-value>false</param-value>
-    </init-param>
-    <init-param>
-      <param-name>Name_AttributeType</param-name>
-      <param-value>cn</param-value>
-    </init-param>
-    <init-param>
-      <param-name>Description_AttributeType</param-name>
-      <param-value>cn</param-value>
-    </init-param>
-    
-    /// Scope Values can be: OBJECT_SCOPE, ONELEVEL_SCOPE, SUBTREE_SCOPE 
-    /// For filter use 
-    
-    <search>
-        <searchType>searchSubject</searchType>
-        <param>
-            <param-name>filter</param-name>
-            <param-value>
-                (&amp;(uid=%TERM%)(objectclass=person))
-            </param-value>
-        </param>
-        <param>
-            <param-name>scope</param-name>
-            <param-value>
-                SUBTREE_SCOPE            
-            </param-value>
-        </param>
-        <param>
-            <param-name>base</param-name>
-            <param-value>
-                ou=people,dc=internet2,dc=edu
-            </param-value>
-        </param>
-    </search>
-
-    <search>
-        <searchType>searchSubjectByIdentifier</searchType>
-        <param>
-            <param-name>filter</param-name>
-            <param-value>
-                (&amp;(uid=%TERM%)(objectclass=person))
-            </param-value>
-        </param>
-        <param>
-            <param-name>scope</param-name>
-            <param-value>
-                SUBTREE_SCOPE            
-            </param-value>
-        </param>
-        <param>
-            <param-name>base</param-name>
-            <param-value>
-                ou=people,dc=internet2,dc=edu
-            </param-value>
-        </param>
-    </search>
-    
-    <search>
-       <searchType>search</searchType>
-         <param>
-            <param-name>filter</param-name>
-            <param-value>
-                (&amp;(|(|(uid=%TERM%)(cn=*%TERM%*))(uid=%TERM%*))(objectclass=person))
-            </param-value>
-        </param>
-        <param>
-            <param-name>scope</param-name>
-            <param-value>
-                SUBTREE_SCOPE            
-            </param-value>
-        </param>
-         <param>
-            <param-name>base</param-name>
-            <param-value>
-                ou=people,dc=internet2,dc=edu
-            </param-value>
-        </param>
-    </search>
-    <init-param>
-      <param-name>subjectVirtualAttribute_0_searchAttribute0</param-name>
-      <param-value>${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('uid'), "")},${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('cn'), "")},${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('exampleEduRegId'), "")}</param-value>
-    </init-param>
-    <init-param>
-      <param-name>sortAttribute0</param-name>
-      <param-value>cn</param-value>
-    </init-param>
-    <init-param>
-      <param-name>searchAttribute0</param-name>
-      <param-value>searchAttribute0</param-value>
-    </init-param>
-
-     <!-- ##########################  STATUS SECTION for searches to filter out inactives and allow
-                                                     the user to filter by status with e.g. status=all
-                                                     this is optional, and advanced - -> 
-     <!- - column or attribute which represents the status - - >
-     <!- -
-     <init-param>
-       <param-name>statusDatastoreFieldName</param-name>
-       <param-value>status</param-value>
-     </init-param> - - >
-     <!- - search string from user which represents the status.  e.g. status=active - - >
-     <!- -
-     <init-param>
-       <param-name>statusLabel</param-name>
-       <param-value>status</param-value>
-     </init-param> - - >
-     <!- - available statuses from screen (if not specified, any will be allowed). comma separated list.
-          Note, this is optional and you probably dont want to configure it, it is mostly necessary
-          when you have multiple sources with statuses...  if someone types an invalid status
-          and you have this configured, it will not filter by it - - >
-     <!- - 
-     <init-param>
-       <param-name>statusesFromUser<param-name>
-       <param-value>Active, Inactive, Pending, All</param-value>
-     </init-param> - - >
-     <!- - all label from the user - - >
-     <!- -
-     <init-param>
-       <param-name>statusAllFromUser</param-name>
-       <param-value>All</param-value>
-     </init-param> - - >
-     <!- - if no status is specified, this will be used (e.g. for active only).  Note, the value should be of the
-          form the user would type in - - >
-     <!- - 
-     <init-param>
-       <param-name>statusSearchDefault</param-name>
-       <param-value>status=active</param-value>
-     </init-param> - - >
-     <!- - translate between screen values of status, and the data store value.  Increment the 0 to 1, 2, etc for more translations.
-          so the user could enter: status=active, and that could translate to status_col=A.  The 'user' is what the user types in,
-          the 'datastore' is what is in the datastore.  The user part is not case-sensitive.  Note, this could be a many to one - - >
-     <!- -
-     <init-param>
-       <param-name>statusTranslateUser0</param-name>
-       <param-value>active</param-value>
-     </init-param>
-     <init-param>
-       <param-name>statusTranslateDatastore0</param-name>
-       <param-value>A</param-value>
-     </init-param> - - >
-     <!- - ########################## END STATUS SECTION --> 
-
-
-    <internal-attribute>searchAttribute0</internal-attribute>
-
-    ///Attributes you would like to display when doing a search 
-    <attribute>givenName</attribute>
-    <attribute>sn</attribute>
-    <attribute>uid</attribute>
-    
-  </source>
-
-
-</sources>
-
diff --git a/test-compose/configs-and-secrets/grouper/subject.properties b/test-compose/configs-and-secrets/grouper/subject.properties
new file mode 100644
index 0000000..fd5b25c
--- /dev/null
+++ b/test-compose/configs-and-secrets/grouper/subject.properties
@@ -0,0 +1,75 @@
+subject.sources.xml.location =
+
+subjectApi.source.ldap.id = ldap
+subjectApi.source.ldap.name = EDU Ldap 
+subjectApi.source.ldap.types = person
+subjectApi.source.ldap.adapterClass = edu.internet2.middleware.grouper.subj.GrouperJndiSourceAdapter
+subjectApi.source.ldap.param.INITIAL_CONTEXT_FACTORY.value = com.sun.jndi.ldap.LdapCtxFactory
+subjectApi.source.ldap.param.PROVIDER_URL.value = ldap://data:389
+subjectApi.source.ldap.param.SECURITY_AUTHENTICATION.value = simple
+subjectApi.source.ldap.param.SECURITY_PRINCIPAL.value = cn=admin,dc=internet2,dc=edu
+subjectApi.source.ldap.param.SECURITY_CREDENTIALS.value.elConfig = ${java.lang.System.getenv().get('SUBJECT_SOURCE_LDAP_PASSWORD_FILE') != null ? org.apache.commons.io.FileUtils.readFileToString(java.lang.System.getenv().get('SUBJECT_SOURCE_LDAP_PASSWORD_FILE'), "utf-8") : java.lang.System.getenv().get('SUBJECT_SOURCE_LDAP_PASSWORD')}
+subjectApi.source.ldap.param.SubjectID_AttributeType.value = uid
+subjectApi.source.ldap.param.SubjectID_formatToLowerCase.value = false
+subjectApi.source.ldap.param.Name_AttributeType.value = cn
+subjectApi.source.ldap.param.Description_AttributeType.value = cn
+subjectApi.source.ldap.param.VTLDAP_VALIDATOR.value = ConnectLdapValidator
+subjectApi.source.ldap.param.subjectVirtualAttribute_0_searchAttribute0.value = ${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('uid'), "")},${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('cn'), "")},${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('exampleEduRegId'), "")}
+subjectApi.source.ldap.param.sortAttribute0.value = cn
+subjectApi.source.ldap.param.searchAttribute0.value = searchAttribute0
+
+# STATUS SECTION for searches to filter out inactives and allow
+# the user to filter by status with e.g. status=all
+# this is optional, and advanced
+#
+# field in database or ldap or endpoint that is the status field
+#subjectApi.source.example.param.statusDatastoreFieldName.value = status
+
+# search string from user which represents the status.  e.g. status=active
+#subjectApi.source.example.param.statusLabel.value = status
+
+# available statuses from screen (if not specified, any will be allowed). comma separated list.
+# Note, this is optional and you probably dont want to configure it, it is mostly necessary
+# when you have multiple sources with statuses...  if someone types an invalid status
+# and you have this configured, it will not filter by it
+#subjectApi.source.example.param.statusesFromUser.value = Active, Inactive, Pending, All
+
+# all label from the user
+#subjectApi.source.example.param.statusAllFromUser.value = All
+
+# if no status is specified, this will be used (e.g. for active only).  Note, the value should be of the
+# form the user would type in
+#subjectApi.source.example.param.statusSearchDefault.value = status=active
+
+# translate between screen values of status, and the data store value.  Increment the 0 to 1, 2, etc for more translations.
+# so the user could enter: status=active, and that could translate to status_col=A.  The 'user' is what the user types in,
+# the 'datastore' is what is in the datastore.  The user part is not case-sensitive.  Note, this could be a many to one
+#subjectApi.source.example.param.statusTranslateUser0.value = active
+#subjectApi.source.example.param.statusTranslateDatastore0.value = A
+
+# subject identifier to store in grouper's member table.  this is used to increase speed of loader and perhaps for provisioning
+# you can have up to max 1 subject identifier
+#subjectApi.source.example.param.subjectIdentifierAttribute0.value = uid
+
+#searchSubject: find a subject by ID.  ID is generally an opaque and permanent identifier, e.g. 12345678.
+#  Each subject has one and only on ID.  Returns one result when searching for one ID.
+subjectApi.source.ldap.search.searchSubject.param.filter.value = (&(uid=%TERM%)(objectclass=person))
+subjectApi.source.ldap.search.searchSubject.param.scope.value = SUBTREE_SCOPE
+subjectApi.source.ldap.search.searchSubject.param.base.value = ou=people,dc=internet2,dc=edu
+
+#searchSubjectByIdentifier: find a subject by identifier.  Identifier is anything that uniquely
+#  identifies the user, e.g. jsmith or jsmith@institution.edu.
+#  Subjects can have multiple identifiers.  Note: it is nice to have if identifiers are unique
+#  even across sources.  Returns one result when searching for one identifier.
+subjectApi.source.ldap.search.searchSubjectByIdentifier.param.filter.value = (&(|(uid=%TERM%)(employeeNumber=%TERM%))(objectclass=person))
+subjectApi.source.ldap.search.searchSubjectByIdentifier.param.scope.value = SUBTREE_SCOPE
+subjectApi.source.ldap.search.searchSubjectByIdentifier.param.base.value = ou=people,dc=internet2,dc=edu
+
+#   search: find subjects by free form search.  Returns multiple results.
+
+subjectApi.source.ldap.search.search.param.filter.value = (&(|(|(uid=%TERM%)(cn=*%TERM%*))(uid=%TERM%*))(objectclass=person))
+subjectApi.source.ldap.search.search.param.scope.value = SUBTREE_SCOPE
+subjectApi.source.ldap.search.search.param.base.value = ou=people,dc=internet2,dc=edu
+
+subjectApi.source.ldap.attributes = givenName, sn, uid, mail, employeeNumber
+subjectApi.source.ldap.internalAttributes = searchAttribute0
diff --git a/test-compose/data/container_files/conf/grouper.hibernate.properties b/test-compose/data/container_files/conf/grouper.hibernate.properties
index 9a45eb9..89404b5 100644
--- a/test-compose/data/container_files/conf/grouper.hibernate.properties
+++ b/test-compose/data/container_files/conf/grouper.hibernate.properties
@@ -26,5 +26,4 @@ hibernate.connection.username         = root
 # If you are using an empty password, depending upon your version of
 # Java and Ant you may need to specify a password of "".
 # Note: you can keep passwords external and encrypted: https://bugs.internet2.edu/jira/browse/GRP-122
-hibernate.connection.password         = 
-
+hibernate.connection.password.elConfig = ${java.lang.System.getenv().get('GROUPER_DATABASE_PASSWORD_FILE') != null ? org.apache.commons.io.FileUtils.readFileToString(java.lang.System.getenv().get('GROUPER_DATABASE_PASSWORD_FILE'), "utf-8") : java.lang.System.getenv().get('GROUPER_DATABASE_PASSWORD') }
diff --git a/test-compose/data/container_files/conf/sources.xml b/test-compose/data/container_files/conf/sources.xml
deleted file mode 100644
index d92123e..0000000
--- a/test-compose/data/container_files/conf/sources.xml
+++ /dev/null
@@ -1,295 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
-Grouper's subject resolver configuration
-$Id: sources.example.xml,v 1.8 2009-08-11 20:18:09 mchyzer Exp $
--->
-
-<sources>
-
-  <!-- Group Subject Resolver -->
-  
-  <!-- 
-     You can flag a source as not throwing exception on a findAll (general search) i.e. if it is
-     ok if it is down.  Generally you probably won't want to do this.  It defaults to true if omitted.
-  
-     <init-param>
-       <param-name>throwErrorOnFindAllFailure</param-name>
-       <param-value>false</param-value>
-     </init-param>
-   -->
-  
-  <!-- 
-      You can make virtual attributes (attributes with formatting or based on other attributes) like this:
-      init-param name is subjectVirtualAttribute_<index>_<name> where index is the order to be processed
-      if some depend on others (0 to 99).  The value is the jexl expression language.  You can use subjectUtils
-      methods (aliased with "subjectUtils", or you can register your own class (must have default constructor).
-      Here are examples:
-  
-     <init-param>
-       <param-name>subjectVirtualAttribute_0_loginIdLfName</param-name>
-       <param-value>Hey ${subject.getAttributeValue('LOGINID')} and ${subject.getAttributeValue('LFNAME')}</param-value>
-     </init-param>
-     <init-param>
-       <param-name>subjectVirtualAttribute_1_loginIdLfNameLoginId</param-name>
-       <param-value>${subject.getAttributeValue('loginIdLfName')} Hey ${subject.getAttributeValue('LOGINID')} and ${subject.getAttributeValue('LFNAME')}</param-value>
-     </init-param>
-     <init-param>
-       <param-name>subjectVirtualAttributeVariable_JDBCSourceAdapterTest</param-name>
-       <param-value>edu.internet2.middleware.subject.provider.JDBCSourceAdapterTest</param-value>
-     </init-param>
-     <init-param>
-       <param-name>subjectVirtualAttribute_2_loginIdSquared</param-name>
-       <param-value>${JDBCSourceAdapterTest.appendToSelf(subject.getAttributeValue('LOGINID'))}</param-value>
-     </init-param>
-  
-    The first virtual attribute is accessible via: subject.getAttributeValue("loginIdLfNameLoginId");
-  
-    you can set these c3p0 settings: maxConnectionAge (seconds), testConnectionOnCheckout (true|false), 
-       preferredTestQuery (e.g. select 1 from dual), idleConnectionTestPeriod (seconds)
-  
-   -->
-  
-  <!-- 
-    NOTE: It is recommended that you **not** change the default
-          values for this source adapter.
-  -->
-  <source adapterClass="edu.internet2.middleware.grouper.GrouperSourceAdapter">
-    <id>g:gsa</id>
-    <name>Grouper: Group Source Adapter</name>
-    <type>group</type>
-
-    <init-param>
-      <param-name>subjectVirtualAttribute_0_searchAttribute0</param-name>
-      <param-value>${subject.getAttributeValue('name')},${subject.getAttributeValue('displayName')},${subject.getAttributeValue('alternateName')}</param-value>
-    </init-param>
-    <init-param>
-      <param-name>sortAttribute0</param-name>
-      <param-value>displayExtension</param-value>
-    </init-param>
-    <init-param>
-      <param-name>searchAttribute0</param-name>
-      <param-value>searchAttribute0</param-value>
-    </init-param>
-    <!-- on a findPage() this is the most results returned --> 
-    <init-param>
-      <param-name>maxPageSize</param-name>
-      <param-value>100</param-value>
-    </init-param>
-    <internal-attribute>searchAttribute0</internal-attribute>
-  </source>
-  <!-- Group Subject Resolver -->
-
-  <!-- 
-    NOTE: It is recommended that you **not** change the default
-          values for this source adapter.
-  -->
-  <source adapterClass="edu.internet2.middleware.grouper.entity.EntitySourceAdapter">
-    <id>grouperEntities</id>
-    <name>Grouper: Entity Source Adapter</name>
-    <type>application</type>
-
-    <init-param>
-      <param-name>subjectVirtualAttribute_0_searchAttribute0</param-name>
-      <!-- TODO add attribute for subject identifier -->
-      <param-value>${subject.getAttributeValue('name')},${subject.getAttributeValue('displayName')},${subject.getAttributeValue('alternateName')}</param-value>
-    </init-param>
-    <init-param>
-      <param-name>sortAttribute0</param-name>
-      <param-value>name</param-value>
-    </init-param>
-    <init-param>
-      <param-name>searchAttribute0</param-name>
-      <param-value>searchAttribute0</param-value>
-    </init-param>
-    <internal-attribute>searchAttribute0</internal-attribute>
-  </source>
-
-
-  <!-- Entity Subject Resolver -->
-  <source adapterClass="edu.internet2.middleware.grouper.subj.GrouperJndiSourceAdapter">
-    <id>ldap</id>
-    <name>EDU Ldap</name>
-    <type>person</type>
-    <init-param>
-      <param-name>INITIAL_CONTEXT_FACTORY</param-name>
-      <param-value>com.sun.jndi.ldap.LdapCtxFactory</param-value>
-    </init-param>
-    <init-param>
-      <param-name>PROVIDER_URL</param-name>
-      <param-value>ldap://localhost</param-value>
-    </init-param>
-    <init-param>
-      <param-name>SECURITY_AUTHENTICATION</param-name>
-      <param-value>simple</param-value>
-    </init-param>
-    <init-param>
-      <param-name>SECURITY_PRINCIPAL</param-name>
-      <param-value>cn=admin,dc=internet2,dc=edu</param-value>
-    </init-param>
-    <init-param>
-      <param-name>SECURITY_CREDENTIALS</param-name>
-      <param-value>password</param-value>
-    </init-param>
-     <init-param>
-      <param-name>SubjectID_AttributeType</param-name>
-      <param-value>uid</param-value>
-    </init-param>
-     <init-param>
-      <param-name>SubjectID_formatToLowerCase</param-name>
-      <param-value>false</param-value>
-    </init-param>
-    <init-param>
-      <param-name>Name_AttributeType</param-name>
-      <param-value>cn</param-value>
-    </init-param>
-    <init-param>
-      <param-name>Description_AttributeType</param-name>
-      <param-value>cn</param-value>
-    </init-param>
-    
-    /// Scope Values can be: OBJECT_SCOPE, ONELEVEL_SCOPE, SUBTREE_SCOPE 
-    /// For filter use 
-    
-    <search>
-        <searchType>searchSubject</searchType>
-        <param>
-            <param-name>filter</param-name>
-            <param-value>
-                (&amp;(uid=%TERM%)(objectclass=person))
-            </param-value>
-        </param>
-        <param>
-            <param-name>scope</param-name>
-            <param-value>
-                SUBTREE_SCOPE            
-            </param-value>
-        </param>
-        <param>
-            <param-name>base</param-name>
-            <param-value>
-                ou=people,dc=internet2,dc=edu
-            </param-value>
-        </param>
-    </search>
-
-    <search>
-        <searchType>searchSubjectByIdentifier</searchType>
-        <param>
-            <param-name>filter</param-name>
-            <param-value>
-                (&amp;(uid=%TERM%)(objectclass=person))
-            </param-value>
-        </param>
-        <param>
-            <param-name>scope</param-name>
-            <param-value>
-                SUBTREE_SCOPE            
-            </param-value>
-        </param>
-        <param>
-            <param-name>base</param-name>
-            <param-value>
-                ou=people,dc=internet2,dc=edu
-            </param-value>
-        </param>
-    </search>
-    
-    <search>
-       <searchType>search</searchType>
-         <param>
-            <param-name>filter</param-name>
-            <param-value>
-                (&amp;(|(|(uid=%TERM%)(cn=*%TERM%*))(uid=%TERM%*))(objectclass=person))
-            </param-value>
-        </param>
-        <param>
-            <param-name>scope</param-name>
-            <param-value>
-                SUBTREE_SCOPE            
-            </param-value>
-        </param>
-         <param>
-            <param-name>base</param-name>
-            <param-value>
-                ou=people,dc=internet2,dc=edu
-            </param-value>
-        </param>
-    </search>
-    <init-param>
-      <param-name>subjectVirtualAttribute_0_searchAttribute0</param-name>
-      <param-value>${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('uid'), "")},${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('cn'), "")},${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('exampleEduRegId'), "")}</param-value>
-    </init-param>
-    <init-param>
-      <param-name>sortAttribute0</param-name>
-      <param-value>cn</param-value>
-    </init-param>
-    <init-param>
-      <param-name>searchAttribute0</param-name>
-      <param-value>searchAttribute0</param-value>
-    </init-param>
-
-     <!-- ##########################  STATUS SECTION for searches to filter out inactives and allow
-                                                     the user to filter by status with e.g. status=all
-                                                     this is optional, and advanced - -> 
-     <!- - column or attribute which represents the status - - >
-     <!- -
-     <init-param>
-       <param-name>statusDatastoreFieldName</param-name>
-       <param-value>status</param-value>
-     </init-param> - - >
-     <!- - search string from user which represents the status.  e.g. status=active - - >
-     <!- -
-     <init-param>
-       <param-name>statusLabel</param-name>
-       <param-value>status</param-value>
-     </init-param> - - >
-     <!- - available statuses from screen (if not specified, any will be allowed). comma separated list.
-          Note, this is optional and you probably dont want to configure it, it is mostly necessary
-          when you have multiple sources with statuses...  if someone types an invalid status
-          and you have this configured, it will not filter by it - - >
-     <!- - 
-     <init-param>
-       <param-name>statusesFromUser<param-name>
-       <param-value>Active, Inactive, Pending, All</param-value>
-     </init-param> - - >
-     <!- - all label from the user - - >
-     <!- -
-     <init-param>
-       <param-name>statusAllFromUser</param-name>
-       <param-value>All</param-value>
-     </init-param> - - >
-     <!- - if no status is specified, this will be used (e.g. for active only).  Note, the value should be of the
-          form the user would type in - - >
-     <!- - 
-     <init-param>
-       <param-name>statusSearchDefault</param-name>
-       <param-value>status=active</param-value>
-     </init-param> - - >
-     <!- - translate between screen values of status, and the data store value.  Increment the 0 to 1, 2, etc for more translations.
-          so the user could enter: status=active, and that could translate to status_col=A.  The 'user' is what the user types in,
-          the 'datastore' is what is in the datastore.  The user part is not case-sensitive.  Note, this could be a many to one - - >
-     <!- -
-     <init-param>
-       <param-name>statusTranslateUser0</param-name>
-       <param-value>active</param-value>
-     </init-param>
-     <init-param>
-       <param-name>statusTranslateDatastore0</param-name>
-       <param-value>A</param-value>
-     </init-param> - - >
-     <!- - ########################## END STATUS SECTION --> 
-
-
-    <internal-attribute>searchAttribute0</internal-attribute>
-
-    ///Attributes you would like to display when doing a search 
-    <attribute>givenName</attribute>
-    <attribute>sn</attribute>
-    <attribute>uid</attribute>
-    
-  </source>
-
-
-</sources>
-
diff --git a/test-compose/data/container_files/conf/subject.properties b/test-compose/data/container_files/conf/subject.properties
new file mode 100644
index 0000000..a73bd20
--- /dev/null
+++ b/test-compose/data/container_files/conf/subject.properties
@@ -0,0 +1,75 @@
+subject.sources.xml.location =
+
+subjectApi.source.ldap.id = ldap
+subjectApi.source.ldap.name = EDU Ldap 
+subjectApi.source.ldap.types = person
+subjectApi.source.ldap.adapterClass = edu.internet2.middleware.grouper.subj.GrouperJndiSourceAdapter
+subjectApi.source.ldap.param.INITIAL_CONTEXT_FACTORY.value = com.sun.jndi.ldap.LdapCtxFactory
+subjectApi.source.ldap.param.PROVIDER_URL.value = ldap://localhost:389
+subjectApi.source.ldap.param.SECURITY_AUTHENTICATION.value = simple
+subjectApi.source.ldap.param.SECURITY_PRINCIPAL.value = cn=admin,dc=internet2,dc=edu
+subjectApi.source.ldap.param.SECURITY_CREDENTIALS.value.elConfig = password
+subjectApi.source.ldap.param.SubjectID_AttributeType.value = uid
+subjectApi.source.ldap.param.SubjectID_formatToLowerCase.value = false
+subjectApi.source.ldap.param.Name_AttributeType.value = cn
+subjectApi.source.ldap.param.Description_AttributeType.value = cn
+subjectApi.source.ldap.param.VTLDAP_VALIDATOR.value = ConnectLdapValidator
+subjectApi.source.ldap.param.subjectVirtualAttribute_0_searchAttribute0.value = ${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('uid'), "")},${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('cn'), "")},${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('exampleEduRegId'), "")}
+subjectApi.source.ldap.param.sortAttribute0.value = cn
+subjectApi.source.ldap.param.searchAttribute0.value = searchAttribute0
+
+# STATUS SECTION for searches to filter out inactives and allow
+# the user to filter by status with e.g. status=all
+# this is optional, and advanced
+#
+# field in database or ldap or endpoint that is the status field
+#subjectApi.source.example.param.statusDatastoreFieldName.value = status
+
+# search string from user which represents the status.  e.g. status=active
+#subjectApi.source.example.param.statusLabel.value = status
+
+# available statuses from screen (if not specified, any will be allowed). comma separated list.
+# Note, this is optional and you probably dont want to configure it, it is mostly necessary
+# when you have multiple sources with statuses...  if someone types an invalid status
+# and you have this configured, it will not filter by it
+#subjectApi.source.example.param.statusesFromUser.value = Active, Inactive, Pending, All
+
+# all label from the user
+#subjectApi.source.example.param.statusAllFromUser.value = All
+
+# if no status is specified, this will be used (e.g. for active only).  Note, the value should be of the
+# form the user would type in
+#subjectApi.source.example.param.statusSearchDefault.value = status=active
+
+# translate between screen values of status, and the data store value.  Increment the 0 to 1, 2, etc for more translations.
+# so the user could enter: status=active, and that could translate to status_col=A.  The 'user' is what the user types in,
+# the 'datastore' is what is in the datastore.  The user part is not case-sensitive.  Note, this could be a many to one
+#subjectApi.source.example.param.statusTranslateUser0.value = active
+#subjectApi.source.example.param.statusTranslateDatastore0.value = A
+
+# subject identifier to store in grouper's member table.  this is used to increase speed of loader and perhaps for provisioning
+# you can have up to max 1 subject identifier
+#subjectApi.source.example.param.subjectIdentifierAttribute0.value = uid
+
+#searchSubject: find a subject by ID.  ID is generally an opaque and permanent identifier, e.g. 12345678.
+#  Each subject has one and only on ID.  Returns one result when searching for one ID.
+subjectApi.source.ldap.search.searchSubject.param.filter.value = (&(uid=%TERM%)(objectclass=person))
+subjectApi.source.ldap.search.searchSubject.param.scope.value = SUBTREE_SCOPE
+subjectApi.source.ldap.search.searchSubject.param.base.value = ou=people,dc=internet2,dc=edu
+
+#searchSubjectByIdentifier: find a subject by identifier.  Identifier is anything that uniquely
+#  identifies the user, e.g. jsmith or jsmith@institution.edu.
+#  Subjects can have multiple identifiers.  Note: it is nice to have if identifiers are unique
+#  even across sources.  Returns one result when searching for one identifier.
+subjectApi.source.ldap.search.searchSubjectByIdentifier.param.filter.value = (&(|(uid=%TERM%)(employeeNumber=%TERM%))(objectclass=person))
+subjectApi.source.ldap.search.searchSubjectByIdentifier.param.scope.value = SUBTREE_SCOPE
+subjectApi.source.ldap.search.searchSubjectByIdentifier.param.base.value = ou=people,dc=internet2,dc=edu
+
+#   search: find subjects by free form search.  Returns multiple results.
+
+subjectApi.source.ldap.search.search.param.filter.value = (&(|(|(uid=%TERM%)(cn=*%TERM%*))(uid=%TERM%*))(objectclass=person))
+subjectApi.source.ldap.search.search.param.scope.value = SUBTREE_SCOPE
+subjectApi.source.ldap.search.search.param.base.value = ou=people,dc=internet2,dc=edu
+
+subjectApi.source.ldap.attributes = givenName, sn, uid, mail, employeeNumber
+subjectApi.source.ldap.internalAttributes = searchAttribute0
diff --git a/test-compose/docker-compose.yml b/test-compose/docker-compose.yml
index 6b2f765..e45844f 100644
--- a/test-compose/docker-compose.yml
+++ b/test-compose/docker-compose.yml
@@ -13,17 +13,21 @@ services:
        target: /opt/grouper/conf/grouper.client.properties
     depends_on: 
      - data
+    environment:
+     - GROUPER_DATABASE_PASSWORD_FILE=/run/secrets/database_password.txt
+     - SUBJECT_SOURCE_LDAP_PASSWORD=password
     networks:
      - back
     secrets:
+     - database_password.txt
      - source: grouper.hibernate.properties
        target: grouper_grouper.hibernate.properties
      - source: grouper-loader.properties
        target: grouper_grouper-loader.properties
      - source: ldap.properties
        target: grouper_ldap.properties
-     - source: sources.xml
-       target: grouper_sources.xml
+     - source: subject.properties
+       target: grouper_subject.properties
  
   ui:
     build: ./ui/
@@ -52,6 +56,9 @@ services:
        target: /etc/pki/tls/certs/cachain.pem
     depends_on: 
      - data
+    environment:
+     - GROUPER_DATABASE_PASSWORD_FILE=/run/secrets/database_password.txt
+     - SUBJECT_SOURCE_LDAP_PASSWORD=password
     networks:
      - front
      - back
@@ -59,14 +66,15 @@ services:
      - "80:80"
      - "443:443"
     secrets:
+     - database_password.txt
      - source: grouper.hibernate.properties
        target: grouper_grouper.hibernate.properties
      - source: grouper-loader.properties
        target: grouper_grouper-loader.properties
      - source: ldap.properties
        target: grouper_ldap.properties
-     - source: sources.xml
-       target: grouper_sources.xml
+     - source: subject.properties
+       target: grouper_subject.properties
      - source: sp-key.pem
        target: shib_sp-key.pem
      - source: host-key.pem
@@ -90,55 +98,59 @@ services:
        target: /etc/pki/tls/certs/cachain.pem
     depends_on: 
      - data
+    environment:
+     - GROUPER_DATABASE_PASSWORD_FILE=/run/secrets/database_password.txt
+     - SUBJECT_SOURCE_LDAP_PASSWORD=password
     networks:
      - front
      - back
     ports:
      - "8443:443"
     secrets:
+     - database_password.txt
      - source: grouper.hibernate.properties
        target: grouper_grouper.hibernate.properties
      - source: grouper-loader.properties
        target: grouper_grouper-loader.properties
      - source: ldap.properties
        target: grouper_ldap.properties
-     - source: sources.xml
-       target: grouper_sources.xml
+     - source: subject.properties
+       target: grouper_subject.properties
      - source: host-key.pem
 
-  scim:
-    build: ./scim/
-    command: bash -c "while ! curl -s data:3306 > /dev/null; do echo waiting for mysql to start; sleep 3; done; while ! curl -s ldap://data:389 > /dev/null; do echo waiting for ldap to start; sleep 3; done; exec scim"
-    volumes:
-     - type: bind
-       source: ./configs-and-secrets/grouper/grouper.properties
-       target: /opt/grouper/conf/grouper.properties
-     - type: bind
-       source: ./configs-and-secrets/grouper/grouper.client.properties
-       target: /opt/grouper/conf/grouper.client.properties
-     - type: bind
-       source: ./configs-and-secrets/httpd/host-cert.pem
-       target: /etc/pki/tls/certs/host-cert.pem
-     - type: bind
-       source: ./configs-and-secrets/httpd/host-cert.pem
-       target: /etc/pki/tls/certs/cachain.pem
-    depends_on: 
-     - data
-    networks:
-     - front
-     - back
-    ports:
-     - "9443:443"
-    secrets:
-     - source: grouper.hibernate.properties
-       target: grouper_grouper.hibernate.properties
-     - source: grouper-loader.properties
-       target: grouper_grouper-loader.properties
-     - source: ldap.properties
-       target: grouper_ldap.properties
-     - source: sources.xml
-       target: grouper_sources.xml
-     - source: host-key.pem
+#  scim:
+#    build: ./scim/
+#    command: bash -c "while ! curl -s data:3306 > /dev/null; do echo waiting for mysql to start; sleep 3; done; while ! curl -s ldap://data:389 > /dev/null; do echo waiting for ldap to start; sleep 3; done; exec scim"
+#    volumes:
+#     - type: bind
+#       source: ./configs-and-secrets/grouper/grouper.properties
+#       target: /opt/grouper/conf/grouper.properties
+#     - type: bind
+#       source: ./configs-and-secrets/grouper/grouper.client.properties
+#       target: /opt/grouper/conf/grouper.client.properties
+#     - type: bind
+#       source: ./configs-and-secrets/httpd/host-cert.pem
+#       target: /etc/pki/tls/certs/host-cert.pem
+#     - type: bind
+#       source: ./configs-and-secrets/httpd/host-cert.pem
+#       target: /etc/pki/tls/certs/cachain.pem
+#    depends_on: 
+#     - data
+#    networks:
+#     - front
+#     - back
+#    ports:
+#     - "9443:443"
+#    secrets:
+#     - source: grouper.hibernate.properties
+#       target: grouper_grouper.hibernate.properties
+#     - source: grouper-loader.properties
+#       target: grouper_grouper-loader.properties
+#     - source: ldap.properties
+#       target: grouper_ldap.properties
+#     - source: sources.xml
+#       target: grouper_sources.xml
+#     - source: host-key.pem
 
   gsh:
     build: ./gsh/
@@ -151,21 +163,28 @@ services:
        target: /opt/grouper/conf/grouper.client.properties
     depends_on: 
      - data
+    environment:
+     - GROUPER_DATABASE_PASSWORD_FILE=/run/secrets/database_password.txt
+     - SUBJECT_SOURCE_LDAP_PASSWORD=password
     networks:
      - back
     secrets:
+     - database_password.txt
      - source: grouper.hibernate.properties
        target: grouper_grouper.hibernate.properties
      - source: grouper-loader.properties
        target: grouper_grouper-loader.properties
      - source: ldap.properties
        target: grouper_ldap.properties
-     - source: sources.xml
-       target: grouper_sources.xml
+     - source: subject.properties
+       target: grouper_subject.properties
 
 
   data:
     build: ./data/
+    environment:
+     - GROUPER_DATABASE_PASSWORD_FILE=/run/secrets/database_password.txt
+     - SUBJECT_SOURCE_LDAP_PASSWORD=password
     expose:
      - "389"
      - "3306"
@@ -174,6 +193,9 @@ services:
     ports:
      - "389:389"
      - "3306:3306"
+    secrets:
+     - database_password.txt
+
 
   idp:
     build: ./idp/
@@ -211,12 +233,14 @@ secrets:
     file: ./configs-and-secrets/grouper/grouper.hibernate.properties
   grouper-loader.properties:
     file: ./configs-and-secrets/grouper/grouper-loader.properties
-  sources.xml:
-    file: ./configs-and-secrets/grouper/sources.xml
+  subject.properties:
+    file: ./configs-and-secrets/grouper/subject.properties
   ldap.properties:
     file: ./configs-and-secrets/grouper/ldap.properties
   sp-key.pem:
     file: ./configs-and-secrets/shibboleth/sp-key.pem
   host-key.pem:
     file: ./configs-and-secrets/httpd/host-key.pem
+  database_password.txt:
+    file: ./configs-and-secrets/grouper/database_password.txt
   
\ No newline at end of file

From 2ef4ce9b9e610cde31dd4317c860f324dea2b780 Mon Sep 17 00:00:00 2001
From: John Gasper <jtgasper3@gmail.com>
Date: Mon, 26 Mar 2018 12:58:09 -0700
Subject: [PATCH 4/4] Adding more secrets to the POC.

---
 .../grouper/grouper-loader.properties         |  6 +-
 .../grouper/grouper.client.properties         |  6 +-
 .../grouper/ldap.properties                   | 73 -------------------
 .../grouper/rabbitmq_password.txt             |  1 +
 test-compose/docker-compose.yml               | 16 ++--
 5 files changed, 13 insertions(+), 89 deletions(-)
 delete mode 100644 test-compose/configs-and-secrets/grouper/ldap.properties
 create mode 100644 test-compose/configs-and-secrets/grouper/rabbitmq_password.txt

diff --git a/test-compose/configs-and-secrets/grouper/grouper-loader.properties b/test-compose/configs-and-secrets/grouper/grouper-loader.properties
index 77cf522..07c4f56 100644
--- a/test-compose/configs-and-secrets/grouper/grouper-loader.properties
+++ b/test-compose/configs-and-secrets/grouper/grouper-loader.properties
@@ -11,13 +11,13 @@
 ldap.demo.url = ldap://data:389/dc=example,dc=edu
  
 #optional, if authenticated
-#ldap.personLdap.user = uid=someapp,ou=people,dc=myschool,dc=edu
+ldap.demo.user = cn=admin,dc=internet2,dc=edu
  
 #optional, if authenticated note the password can be stored encrypted in an external file
-#ldap.personLdap.pass = secret
+ldap.demo.pass = ${java.lang.System.getenv().get('SUBJECT_SOURCE_LDAP_PASSWORD_FILE') != null ? org.apache.commons.io.FileUtils.readFileToString(java.lang.System.getenv().get('SUBJECT_SOURCE_LDAP_PASSWORD_FILE'), "utf-8") : java.lang.System.getenv().get('SUBJECT_SOURCE_LDAP_PASSWORD')}
  
 #optional, if you are using tls, set this to true.  Generally you will not be using an SSL URL to use TLS...
-#ldap.personLdap.tls = false
+ldap.demo.tls = false
  
 #optional, if using sasl
 #ldap.personLdap.saslAuthorizationId =
diff --git a/test-compose/configs-and-secrets/grouper/grouper.client.properties b/test-compose/configs-and-secrets/grouper/grouper.client.properties
index 07d7cd1..5169c71 100644
--- a/test-compose/configs-and-secrets/grouper/grouper.client.properties
+++ b/test-compose/configs-and-secrets/grouper/grouper.client.properties
@@ -55,7 +55,7 @@ grouperClient.webService.login = banderson
 
 # password for shared secret authentication to web service
 # or you can put a filename with an encrypted password
-grouperClient.webService.password = password
+grouperClient.webService.password = ${java.lang.System.getenv().get('GROUPER_CLIENT_WEBSERVICE_PASSWORD_FILE') != null ? org.apache.commons.io.FileUtils.readFileToString(java.lang.System.getenv().get('GROUPER_CLIENT_WEBSERVICE_PASSWORD_FILE'), "utf-8") : java.lang.System.getenv().get('GROUPER_CLIENT_WEBSERVICE_PASSWORD') }
 
 
 ################################
@@ -98,9 +98,9 @@ grouper.messaging.system.rabbitmq.name = rabbitmq
 grouper.messaging.system.rabbitmq.defaultSystemName = rabbitmqSystem
 
 grouper.messaging.system.rabbitmq.user = guest
- 
+
 #pass
-grouper.messaging.system.rabbitmq.password = guest
+grouper.messaging.system.rabbitmq.password = ${java.lang.System.getenv().get('RABBITMQ_PASSWORD_FILE') != null ? org.apache.commons.io.FileUtils.readFileToString(java.lang.System.getenv().get('RABBITMQ_PASSWORD_FILE'), "utf-8") : java.lang.System.getenv().get('RABBITMQ_PASSWORD') }
 # set the following three properties if you want to use TLS connection to rabbitmq. All three need to be populated.
 # TLS Version
 #grouper.messaging.system.rabbitmqSystem.tlsVersion = TLSv1.1
diff --git a/test-compose/configs-and-secrets/grouper/ldap.properties b/test-compose/configs-and-secrets/grouper/ldap.properties
deleted file mode 100644
index df38a6e..0000000
--- a/test-compose/configs-and-secrets/grouper/ldap.properties
+++ /dev/null
@@ -1,73 +0,0 @@
-# This is the configuration file for vt-ldap.
-# See http://code.google.com/p/vt-middleware/wiki/vtldapProperties
-
-edu.vt.middleware.ldap.ldapUrl=ldap://data:389
-edu.vt.middleware.ldap.searchScope=SUBTREE
-
-# authn if simple
-edu.vt.middleware.ldap.bindDn=cn=admin,dc=internet2,dc=edu
-edu.vt.middleware.ldap.bindCredential.elConfig =
-# The bind credential may be external and encrypted: https://bugs.internet2.edu/jira/browse/GRP-122
-# edu.vt.middleware.ldap.bindCredential=/path/to/ldap.pwd
-edu.vt.middleware.ldap.authtype=simple
-
-# encryption
-edu.vt.middleware.ldap.ssl=false
-edu.vt.middleware.ldap.tls=false
-
-# pooling options
-edu.vt.middleware.ldap.pool.minPoolSize = 2
-edu.vt.middleware.ldap.pool.maxPoolSize = 5
-
-# paged results
-edu.vt.middleware.ldap.pagedResultsSize=0
-
-# authn for sasl external (certificates)
-# edu.vt.middleware.ldap.authtype=EXTERNAL
-# edu.vt.middleware.ldap.tls=true
-# edu.vt.middleware.ldap.serviceUser=cn=admin.example.edu
-# these to use PEM format cert and key
-# pemCaFile=/path/to/ca.pem
-# pemCertFile=/path/to/cert.pem
-# pemKeyFile=/path/to/key.pem
-
-
-# The default base DN for searches.
-# All subordinate objects will be deleted during tests !
-edu.vt.middleware.ldap.baseDn=dc=internet2,dc=edu
-
-# The base DN for groups.
-edu.internet2.middleware.psp.groupsBaseDn=ou=groups,dc=internet2,dc=edu
-
-# The base DN for people.
-edu.internet2.middleware.psp.peopleBaseDn=ou=people,dc=internet2,dc=edu
-
-# The group object class.
-# OpenLDAP, RedHat, 389, ApacheDS, etc.
-edu.internet2.middleware.psp.groupObjectClass=groupOfNames
-# Active Directory
-# edu.internet2.middleware.psp.groupObjectClass=group
-
-# The base Grouper stem to be provisioned.
-edu.internet2.middleware.psp.baseStem=psp
-
-# The ldap DN structure may be either flat or bushy.
-# In a flat structure all groups are provisioned under a single base DN (container ID).
-# A flat group's ldap RDN is its Grouper name or displayName.
-# edu.internet2.middleware.psp.structure=flat
-# edu.internet2.middleware.psp.cnSourceAttributeID=name
-
-# In a bushy structure groups are provisioned hierarchically, with stems as branches in the tree.
-# A bushy group's RDN is its Grouper extension or displayExtension.
-edu.internet2.middleware.psp.structure=flat
-edu.internet2.middleware.psp.cnSourceAttributeID=name
-
-# The QuotedDnResultHandler removes quotes from DNs of the form "CN=quoted/name",DC=edu.
-# The FqdnSearchResultHandler makes sure that all ldap dns are fully qualified.
-# You may wish to comment out the following property for the Grouper UI or WS.
-edu.vt.middleware.ldap.searchResultHandlers=edu.internet2.middleware.psp.ldap.QuotedDnResultHandler,edu.vt.middleware.ldap.handler.FqdnSearchResultHandler
-
-# handle Active Directory groups with a large (>1500) number of members
-# see https://bugs.internet2.edu/jira/browse/GRP-335
-# see http://code.google.com/p/vt-middleware/wiki/vtldapAD#Range_Attributes
-# edu.vt.middleware.ldap.searchResultHandlers=edu.internet2.middleware.ldappc.util.QuotedDnResultHandler,edu.vt.middleware.ldap.handler.FqdnSearchResultHandler,edu.internet2.middleware.ldappc.util.RangeSearchResultHandler
diff --git a/test-compose/configs-and-secrets/grouper/rabbitmq_password.txt b/test-compose/configs-and-secrets/grouper/rabbitmq_password.txt
new file mode 100644
index 0000000..158f675
--- /dev/null
+++ b/test-compose/configs-and-secrets/grouper/rabbitmq_password.txt
@@ -0,0 +1 @@
+guest
\ No newline at end of file
diff --git a/test-compose/docker-compose.yml b/test-compose/docker-compose.yml
index e45844f..cebb97b 100644
--- a/test-compose/docker-compose.yml
+++ b/test-compose/docker-compose.yml
@@ -14,18 +14,19 @@ services:
     depends_on: 
      - data
     environment:
+     - GROUPER_CLIENT_WEBSERVICE_PASSWORD_FILE=password
      - GROUPER_DATABASE_PASSWORD_FILE=/run/secrets/database_password.txt
+     - RABBITMQ_PASSWORD_FILE=/run/secrets/rabbitmq_password.txt
      - SUBJECT_SOURCE_LDAP_PASSWORD=password
     networks:
      - back
     secrets:
      - database_password.txt
+     - rabbitmq_password.txt
      - source: grouper.hibernate.properties
        target: grouper_grouper.hibernate.properties
      - source: grouper-loader.properties
        target: grouper_grouper-loader.properties
-     - source: ldap.properties
-       target: grouper_ldap.properties
      - source: subject.properties
        target: grouper_subject.properties
  
@@ -71,8 +72,6 @@ services:
        target: grouper_grouper.hibernate.properties
      - source: grouper-loader.properties
        target: grouper_grouper-loader.properties
-     - source: ldap.properties
-       target: grouper_ldap.properties
      - source: subject.properties
        target: grouper_subject.properties
      - source: sp-key.pem
@@ -112,8 +111,6 @@ services:
        target: grouper_grouper.hibernate.properties
      - source: grouper-loader.properties
        target: grouper_grouper-loader.properties
-     - source: ldap.properties
-       target: grouper_ldap.properties
      - source: subject.properties
        target: grouper_subject.properties
      - source: host-key.pem
@@ -174,8 +171,6 @@ services:
        target: grouper_grouper.hibernate.properties
      - source: grouper-loader.properties
        target: grouper_grouper-loader.properties
-     - source: ldap.properties
-       target: grouper_ldap.properties
      - source: subject.properties
        target: grouper_subject.properties
 
@@ -235,12 +230,13 @@ secrets:
     file: ./configs-and-secrets/grouper/grouper-loader.properties
   subject.properties:
     file: ./configs-and-secrets/grouper/subject.properties
-  ldap.properties:
-    file: ./configs-and-secrets/grouper/ldap.properties
   sp-key.pem:
     file: ./configs-and-secrets/shibboleth/sp-key.pem
   host-key.pem:
     file: ./configs-and-secrets/httpd/host-key.pem
   database_password.txt:
     file: ./configs-and-secrets/grouper/database_password.txt
+  rabbitmq_password.txt:
+    file: ./configs-and-secrets/grouper/rabbitmq_password.txt
+
   
\ No newline at end of file